Merge "defconfig: msm: Disable KPROBES for Bengal perf"
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 94b67a2..bef7d96 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -113,7 +113,7 @@
the GPE dispatcher.
This facility can be used to prevent such uncontrolled
GPE floodings.
- Format: <int>
+ Format: <byte>
acpi_no_auto_serialize [HW,ACPI]
Disable auto-serialization of AML methods
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index eeb3fc9..16be5e2 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -59,6 +59,7 @@
| ARM | Cortex-A73 | #858921 | ARM64_ERRATUM_858921 |
| ARM | Cortex-A55 | #1024718 | ARM64_ERRATUM_1024718 |
| ARM | Cortex-A76 | #1463225 | ARM64_ERRATUM_1463225 |
+| ARM | Cortex-A77 | #1542418 | ARM64_ERRATUM_1542418 |
| ARM | MMU-500 | #841119,#826419 | N/A |
| | | | |
| Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 |
diff --git a/Makefile b/Makefile
index d57f0ff..3bb6239 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
VERSION = 4
PATCHLEVEL = 19
-SUBLEVEL = 91
+SUBLEVEL = 95
EXTRAVERSION =
NAME = "People's Front"
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1b88246..0b5e8ac 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -541,6 +541,31 @@
help
Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
+config ARCH_QCOM
+ bool "Qualcomm MSM (non-multiplatform)"
+ select ARCH_REQUIRE_GPIOLIB
+ select CPU_V7
+ select AUTO_ZRELADDR
+ select HAVE_SMP
+ select CLKDEV_LOOKUP
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_ALLOCATOR
+ select ARM_PATCH_PHYS_VIRT
+ select ARM_HAS_SG_CHAIN
+ select ARCH_HAS_OPP
+ select SOC_BUS
+ select MULTI_IRQ_HANDLER
+ select PM_OPP
+ select SPARSE_IRQ
+ select USE_OF
+ select PINCTRL
+ help
+ Support for Qualcomm MSM/QSD based systems. This runs on the
+ apps processor of the MSM/QSD and depends on a shared memory
+ interface to the modem processor which runs the baseband
+ stack and controls some vital subsystems
+ (clock and power control, etc).
+
config ARCH_RPC
bool "RiscPC"
depends on MMU
@@ -1470,7 +1495,7 @@
int
default 2048 if ARCH_SOCFPGA
default 1024 if ARCH_BRCMSTB || ARCH_RENESAS || ARCH_TEGRA || \
- ARCH_ZYNQ
+ ARCH_ZYNQ || ARCH_QCOM
default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || \
SOC_DRA7XX || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210
default 416 if ARCH_SUNXI
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 86d6b04..c341f10 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -1867,7 +1867,7 @@
config UNCOMPRESS_INCLUDE
string
default "debug/uncompress.h" if ARCH_MULTIPLATFORM || ARCH_MSM || \
- PLAT_SAMSUNG || ARM_SINGLE_ARMV7M
+ ARCH_QCOM || PLAT_SAMSUNG || ARM_SINGLE_ARMV7M
default "mach/uncompress.h"
config EARLY_PRINTK
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ded1724..6d02008 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -30,6 +30,10 @@
# Never generate .eh_frame
KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm)
+ifeq ($(cc-name),clang)
+KBUILD_CFLAGS += -Wno-vectorizer-no-neon
+endif
+
# This should work on most of the modern platforms
KBUILD_DEFCONFIG := multi_v7_defconfig
diff --git a/arch/arm/boot/compressed/libfdt_env.h b/arch/arm/boot/compressed/libfdt_env.h
index b36c028..6a0f1f5 100644
--- a/arch/arm/boot/compressed/libfdt_env.h
+++ b/arch/arm/boot/compressed/libfdt_env.h
@@ -2,11 +2,13 @@
#ifndef _ARM_LIBFDT_ENV_H
#define _ARM_LIBFDT_ENV_H
+#include <linux/limits.h>
#include <linux/types.h>
#include <linux/string.h>
#include <asm/byteorder.h>
-#define INT_MAX ((int)(~0U>>1))
+#define INT32_MAX S32_MAX
+#define UINT32_MAX U32_MAX
typedef __be16 fdt16_t;
typedef __be32 fdt32_t;
diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
index 5b97c20..8a17eca 100644
--- a/arch/arm/boot/dts/am437x-gp-evm.dts
+++ b/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -83,7 +83,7 @@
};
lcd0: display {
- compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
+ compatible = "osddisplays,osd070t1718-19ts", "panel-dpi";
label = "lcd";
backlight = <&lcd_bl>;
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 6502d33..12735cf 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -45,7 +45,7 @@
};
lcd0: display {
- compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
+ compatible = "osddisplays,osd070t1718-19ts", "panel-dpi";
label = "lcd";
backlight = <&lcd_bl>;
diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi
index 253df71..887a60c 100644
--- a/arch/arm/boot/dts/bcm-cygnus.dtsi
+++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -169,8 +169,8 @@
mdio: mdio@18002000 {
compatible = "brcm,iproc-mdio";
reg = <0x18002000 0x8>;
- #size-cells = <1>;
- #address-cells = <0>;
+ #size-cells = <0>;
+ #address-cells = <1>;
status = "disabled";
gphy0: ethernet-phy@0 {
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
index 31b2964..c9322a5 100644
--- a/arch/arm/boot/dts/bcm283x.dtsi
+++ b/arch/arm/boot/dts/bcm283x.dtsi
@@ -39,7 +39,7 @@
trips {
cpu-crit {
- temperature = <80000>;
+ temperature = <90000>;
hysteresis = <0>;
type = "critical";
};
diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi
index bc607d1..a678fb7 100644
--- a/arch/arm/boot/dts/bcm5301x.dtsi
+++ b/arch/arm/boot/dts/bcm5301x.dtsi
@@ -350,8 +350,8 @@
mdio: mdio@18003000 {
compatible = "brcm,iproc-mdio";
reg = <0x18003000 0x8>;
- #size-cells = <1>;
- #address-cells = <0>;
+ #size-cells = <0>;
+ #address-cells = <1>;
};
mdio-bus-mux {
diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi b/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
index 8180211..6953034 100644
--- a/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
+++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
@@ -175,7 +175,7 @@
flash0: n25q256a@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "micron,n25q256a";
+ compatible = "micron,n25q256a", "jedec,spi-nor";
spi-max-frequency = <29000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi
index 50834a43..adecd6e 100644
--- a/arch/arm/boot/dts/imx6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul.dtsi
@@ -87,6 +87,8 @@
"pll1_sys";
arm-supply = <®_arm>;
soc-supply = <®_soc>;
+ nvmem-cells = <&cpu_speed_grade>;
+ nvmem-cell-names = "speed_grade";
};
};
@@ -930,6 +932,10 @@
tempmon_temp_grade: temp-grade@20 {
reg = <0x20 4>;
};
+
+ cpu_speed_grade: speed-grade@10 {
+ reg = <0x10 4>;
+ };
};
lcdif: lcdif@21c8000 {
diff --git a/arch/arm/configs/vendor/bengal-perf_defconfig b/arch/arm/configs/vendor/bengal-perf_defconfig
index 36fc3dd..6cc29ab 100644
--- a/arch/arm/configs/vendor/bengal-perf_defconfig
+++ b/arch/arm/configs/vendor/bengal-perf_defconfig
@@ -1,6 +1,5 @@
CONFIG_LOCALVERSION="-perf"
# CONFIG_LOCALVERSION_AUTO is not set
-CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y
# CONFIG_AUDITSYSCALL is not set
CONFIG_NO_HZ=y
@@ -9,7 +8,6 @@
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_SCHED_WALT=y
CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_PSI=y
@@ -31,12 +29,10 @@
# CONFIG_PID_NS is not set
CONFIG_SCHED_AUTOGROUP=y
CONFIG_SCHED_TUNE=y
-CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
# CONFIG_RD_LZ4 is not set
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
# CONFIG_FHANDLE is not set
CONFIG_KALLSYMS_ALL=y
CONFIG_BPF_SYSCALL=y
@@ -48,8 +44,8 @@
CONFIG_PROFILING=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_BENGAL=y
+CONFIG_ARCH_SCUBA=y
# CONFIG_VDSO is not set
-CONFIG_PCI=y
CONFIG_SMP=y
CONFIG_SCHED_MC=y
CONFIG_NR_CPUS=8
@@ -57,7 +53,6 @@
CONFIG_HIGHMEM=y
CONFIG_SECCOMP=y
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
-CONFIG_EFI=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
@@ -212,11 +207,6 @@
CONFIG_IP6_NF_RAW=y
CONFIG_BRIDGE_NF_EBTABLES=y
CONFIG_BRIDGE_EBT_BROUTE=y
-CONFIG_BRIDGE_EBT_T_FILTER=y
-CONFIG_BRIDGE_EBT_T_NAT=y
-CONFIG_BRIDGE_EBT_ARPREPLY=y
-CONFIG_BRIDGE_EBT_DNAT=y
-CONFIG_BRIDGE_EBT_SNAT=y
CONFIG_IP_SCTP=y
CONFIG_L2TP=y
CONFIG_L2TP_V3=y
@@ -252,11 +242,9 @@
CONFIG_MSM_BT_POWER=y
CONFIG_BTFM_SLIM_WCN3990=y
CONFIG_CFG80211=y
-CONFIG_CFG80211_INTERNAL_REGDB=y
CONFIG_RFKILL=y
CONFIG_NFC_NQ=y
CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
CONFIG_FW_LOADER_USER_HELPER=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
CONFIG_REGMAP_WCD_IRQ=y
@@ -293,7 +281,6 @@
CONFIG_TUN=y
CONFIG_RMNET=y
CONFIG_PHYLIB=y
-CONFIG_AT803X_PHY=y
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
@@ -310,43 +297,33 @@
CONFIG_CLD_LL_CORE=y
CONFIG_CNSS_GENL=y
CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_KEYRESET=y
CONFIG_KEYBOARD_GPIO=y
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_JOYSTICK_XPAD=y
-CONFIG_INPUT_TABLET=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_QPNP_POWER_ON=y
CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=y
# CONFIG_SERIO_SERPORT is not set
# CONFIG_VT is not set
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVMEM is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SERIAL_MSM_GENI=y
CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y
-CONFIG_HVC_DCC=y
-CONFIG_HVC_DCC_SERIALIZE_SMP=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
+# CONFIG_DEVPORT is not set
CONFIG_DIAG_CHAR=y
CONFIG_MSM_ADSPRPC=y
CONFIG_MSM_RDBG=m
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QCOM_GENI=y
CONFIG_SPI=y
-CONFIG_SPI_DEBUG=y
-CONFIG_SPI_QUP=y
CONFIG_SPI_QCOM_GENI=y
CONFIG_SPI_SPIDEV=y
CONFIG_SPMI=y
-CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
-CONFIG_PTP_1588_CLOCK=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_PINCTRL_BENGAL=y
CONFIG_GPIOLIB=y
@@ -354,7 +331,6 @@
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_QCOM=y
CONFIG_POWER_RESET_SYSCON=y
-CONFIG_POWER_SUPPLY=y
CONFIG_QPNP_SMB5=y
CONFIG_SMB1355_SLAVE_CHARGER=y
CONFIG_QPNP_QG=y
@@ -380,7 +356,7 @@
CONFIG_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR=y
-CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
CONFIG_REGULATOR_FAN53555=y
CONFIG_REGULATOR_QCOM_SMD_RPM=y
CONFIG_REGULATOR_QPNP_LCDB=y
@@ -389,21 +365,18 @@
CONFIG_REGULATOR_PM8008=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
-CONFIG_MEDIA_RADIO_SUPPORT=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_VIDEO_ADV_DEBUG=y
CONFIG_VIDEO_FIXED_MINOR_RANGES=y
CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_SOC_CAMERA=y
-CONFIG_SOC_CAMERA_PLATFORM=y
CONFIG_V4L_TEST_DRIVERS=y
CONFIG_VIDEO_VIM2M=y
CONFIG_VIDEO_VICODEC=y
CONFIG_DRM=y
# CONFIG_DRM_MSM is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
-# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
@@ -415,7 +388,6 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_USB_AUDIO_QMI=y
CONFIG_SND_SOC=y
-CONFIG_HIDRAW=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_ELECOM=y
@@ -423,6 +395,7 @@
CONFIG_HID_MICROSOFT=y
CONFIG_HID_MULTITOUCH=y
CONFIG_HID_PLANTRONICS=y
+CONFIG_HID_SONY=y
CONFIG_USB_HIDDEV=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_MON=y
@@ -431,7 +404,6 @@
CONFIG_USB_DWC3=y
# CONFIG_USB_DWC3_OF_SIMPLE is not set
CONFIG_USB_DWC3_MSM=y
-CONFIG_USB_SERIAL=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_LINK_LAYER_TEST=y
CONFIG_NOP_USB_XCEIV=y
@@ -509,7 +481,6 @@
CONFIG_RPMSG_QCOM_GLINK_SMEM=y
CONFIG_MSM_RPM_SMD=y
CONFIG_QCOM_COMMAND_DB=y
-CONFIG_QCOM_CPUSS_DUMP=y
CONFIG_QCOM_MDT_LOADER=y
CONFIG_QPNP_PBS=y
CONFIG_QCOM_QMI_HELPERS=y
@@ -561,7 +532,6 @@
CONFIG_ARM_QCOM_DEVFREQ_FW=y
CONFIG_DEVFREQ_SIMPLE_DEV=y
CONFIG_QCOM_DEVFREQ_DEVBW=y
-CONFIG_EXTCON_USB_GPIO=y
CONFIG_IIO=y
CONFIG_QCOM_SPMI_ADC5=y
CONFIG_PWM=y
@@ -571,6 +541,7 @@
CONFIG_RAS=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
+# CONFIG_NVMEM_SYSFS is not set
CONFIG_QCOM_QFPROM=y
CONFIG_NVMEM_SPMI_SDAM=y
CONFIG_SLIMBUS_MSM_NGD=y
@@ -589,11 +560,9 @@
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_EFIVAR_FS=y
CONFIG_SDCARD_FS=y
# CONFIG_NETWORK_FILESYSTEMS is not set
CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
@@ -614,17 +583,14 @@
CONFIG_CRYPTO_DEV_QCRYPTO=y
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_CRYPTO_DEV_QCOM_ICE=y
-CONFIG_XZ_DEC=y
-CONFIG_STACK_HASH_ORDER_SHIFT=12
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_INFO=y
CONFIG_FRAME_WARN=2048
-CONFIG_PAGE_OWNER=y
# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
-CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_TIMEOUT=-1
CONFIG_SCHEDSTATS=y
+# CONFIG_DEBUG_PREEMPT is not set
CONFIG_IPC_LOGGING=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
diff --git a/arch/arm/configs/vendor/bengal_defconfig b/arch/arm/configs/vendor/bengal_defconfig
index 4f3bbeb..92a76a8 100644
--- a/arch/arm/configs/vendor/bengal_defconfig
+++ b/arch/arm/configs/vendor/bengal_defconfig
@@ -47,8 +47,8 @@
CONFIG_PROFILING=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_BENGAL=y
+CONFIG_ARCH_SCUBA=y
# CONFIG_VDSO is not set
-CONFIG_PCI=y
CONFIG_SMP=y
CONFIG_SCHED_MC=y
CONFIG_NR_CPUS=8
@@ -319,6 +319,7 @@
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_JOYSTICK_XPAD=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
CONFIG_INPUT_TABLET=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
@@ -338,6 +339,7 @@
CONFIG_TTY_PRINTK=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
+# CONFIG_DEVPORT is not set
CONFIG_DIAG_CHAR=y
CONFIG_MSM_ADSPRPC=y
CONFIG_MSM_RDBG=m
@@ -358,7 +360,6 @@
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_QCOM=y
CONFIG_POWER_RESET_SYSCON=y
-CONFIG_POWER_SUPPLY=y
CONFIG_QPNP_SMB5=y
CONFIG_SMB1355_SLAVE_CHARGER=y
CONFIG_QPNP_QG=y
@@ -427,6 +428,7 @@
CONFIG_HID_MICROSOFT=y
CONFIG_HID_MULTITOUCH=y
CONFIG_HID_PLANTRONICS=y
+CONFIG_HID_SONY=y
CONFIG_USB_HIDDEV=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_MON=y
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 523c499..02e0425 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -366,6 +366,11 @@ static inline int hyp_map_aux_data(void)
#define kvm_phys_to_vttbr(addr) (addr)
+static inline void kvm_workaround_1542418_vmid_rollover(void)
+{
+ /* not affected */
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
index a00288d7..3c534a5 100644
--- a/arch/arm/include/asm/traps.h
+++ b/arch/arm/include/asm/traps.h
@@ -28,6 +28,8 @@ static inline int __in_irqentry_text(unsigned long ptr)
ptr < (unsigned long)&__irqentry_text_end;
}
+extern void get_timer_freq_hook_init(void);
+extern void get_timer_count_hook_init(void);
extern void __init early_trap_init(void *);
extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index badf02c..027bbd5 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -31,6 +31,7 @@
#include <linux/irq.h>
#include <linux/atomic.h>
+#include <asm/arch_timer.h>
#include <asm/cacheflush.h>
#include <asm/exception.h>
#include <asm/unistd.h>
@@ -736,6 +737,77 @@ late_initcall(arm_mrc_hook_init);
#endif
+static int get_timer_count_trap(struct pt_regs *regs, unsigned int instr)
+{
+ u64 cval;
+ unsigned int res;
+ int rd = (instr >> 12) & 0xF;
+ int rn = (instr >> 16) & 0xF;
+
+ res = arm_check_condition(instr, regs->ARM_cpsr);
+ if (res == ARM_OPCODE_CONDTEST_FAIL) {
+ regs->ARM_pc += 4;
+ return 0;
+ }
+
+ if (rd == 15 || rn == 15)
+ return 1;
+ cval = arch_counter_get_cntvct();
+ regs->uregs[rd] = cval;
+ regs->uregs[rn] = cval >> 32;
+ regs->ARM_pc += 4;
+ return 0;
+}
+
+static struct undef_hook get_timer_count_hook = {
+ .instr_mask = 0x0ff00fff,
+ .instr_val = 0x0c500f1e,
+ .cpsr_mask = MODE_MASK,
+ .cpsr_val = USR_MODE,
+ .fn = get_timer_count_trap,
+};
+
+void get_timer_count_hook_init(void)
+{
+ register_undef_hook(&get_timer_count_hook);
+}
+EXPORT_SYMBOL(get_timer_count_hook_init);
+
+static int get_freq_trap(struct pt_regs *regs, unsigned int instr)
+{
+ u32 fval;
+ unsigned int res;
+ int rd = (instr >> 12) & 0xF;
+
+ res = arm_check_condition(instr, regs->ARM_cpsr);
+ if (res == ARM_OPCODE_CONDTEST_FAIL) {
+ regs->ARM_pc += 4;
+ return 0;
+ }
+
+ if (rd == 15)
+ return 1;
+
+ fval = arch_timer_get_cntfrq();
+ regs->uregs[rd] = fval;
+ regs->ARM_pc += 4;
+ return 0;
+}
+
+static struct undef_hook get_freq_hook = {
+ .instr_mask = 0x0fff0fff,
+ .instr_val = 0x0e1e0f10,
+ .cpsr_mask = MODE_MASK,
+ .cpsr_val = USR_MODE,
+ .fn = get_freq_trap,
+};
+
+void get_timer_freq_hook_init(void)
+{
+ register_undef_hook(&get_freq_hook);
+}
+EXPORT_SYMBOL(get_timer_freq_hook_init);
+
/*
* A data abort trap was taken, but we did not handle the instruction.
* Try to abort the user program, or panic if it was the kernel.
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 7bb6192..c108485 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -1,56 +1,92 @@
-menuconfig ARCH_QCOM
- bool "Qualcomm Support"
- depends on ARCH_MULTI_V7
- select ARCH_SUPPORTS_BIG_ENDIAN
- select ARM_GIC
- select ARM_AMBA
- select PINCTRL
- select MFD_CORE
- select SND_SOC_COMPRESS
- select SND_HWDEP
- select QCOM_SCM if SMP
- help
- Support for Qualcomm's devicetree based systems.
-
if ARCH_QCOM
+menu "QCOM SoC Type"
config ARCH_MSM8X60
bool "Enable support for MSM8X60"
+ select ARCH_SUPPORTS_BIG_ENDIAN
+ select ARM_GIC
+ select ARM_AMBA
+ select QCOM_SCM if SMP
select CLKSRC_QCOM
+ select CLKSRC_OF
+ select COMMON_CLK
config ARCH_MSM8960
bool "Enable support for MSM8960"
select CLKSRC_QCOM
+ select ARCH_SUPPORTS_BIG_ENDIAN
+ select ARM_GIC
+ select ARM_AMBA
+ select QCOM_SCM if SMP
+ select CLKSRC_OF
+ select COMMON_CLK
+
config ARCH_MSM8974
bool "Enable support for MSM8974"
select HAVE_ARM_ARCH_TIMER
+ select ARCH_SUPPORTS_BIG_ENDIAN
+ select ARM_GIC
+ select ARM_AMBA
+ select QCOM_SCM if SMP
+ select CLKSRC_OF
+ select COMMON_CLK
config ARCH_MDM9615
bool "Enable support for MDM9615"
select CLKSRC_QCOM
+ select ARCH_SUPPORTS_BIG_ENDIAN
+ select ARM_GIC
+ select ARM_AMBA
+ select QCOM_SCM if SMP
+ select CLKSRC_OF
+ select COMMON_CLK
config ARCH_BENGAL
bool "Enable Support for Qualcomm Technologies, Inc. BENGAL"
select COMMON_CLK_QCOM
- select CPU_V7
+ select ARCH_SUPPORT_BIG_ENDIAN
+ select ARM_GIC
+ select ARM_AMBA
+ select QCOM_SCM if SMP
+ select CLKSRC_OF
+ select COMMON_CLK
select HAVE_CLK
select HAVE_CLK_PREPARE
- select PM_OPP
- select SOC_BUS
select THERMAL_WRITABLE_TRIPS
select ARM_GIC_V3
- select ARM_AMBA
- select SPARSE_IRQ
- select MULTI_IRQ_HANDLER
select HAVE_ARM_ARCH_TIMER
- select COMMON_CLK
select PINCTRL_MSM
select MSM_PM if PM
select CPU_FREQ
select PM_DEVFREQ
+ select PCI
help
This enables support for the BENGAL chipset. If you do not
wish to build a kernel that runs on this chipset, say 'N' here.
+config ARCH_SCUBA
+ bool "Enable Support for Qualcomm Technologies, Inc. SCUBA"
+ select COMMON_CLK_QCOM
+ select ARCH_SUPPORT_BIG_ENDIAN
+ select ARM_GIC
+ select ARM_AMBA
+ select QCOM_SCM if SMP
+ select CLKSRC_OF
+ select COMMON_CLK
+ select HAVE_CLK
+ select HAVE_CLK_PREPARE
+ select THERMAL_WRITABLE_TRIPS
+ select ARM_GIC_V3
+ select HAVE_ARM_ARCH_TIMER
+ select PINCTRL_MSM
+ select MSM_PM if PM
+ select CPU_FREQ
+ select PM_DEVFREQ
+ select PCI
+ help
+ This enables support for the SCUBA chipset. If you do not
+ wish to build a kernel that runs on this chipset, say 'N' here.
+
+endmenu
endif
diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile
index 685e7b8..f6658a2 100644
--- a/arch/arm/mach-qcom/Makefile
+++ b/arch/arm/mach-qcom/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_USE_OF) += board-dt.o
obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_ARCH_BENGAL) += board-bengal.o
+obj-$(CONFIG_ARCH_SCUBA) += board-scuba.o
diff --git a/arch/arm/mach-qcom/board-scuba.c b/arch/arm/mach-qcom/board-scuba.c
new file mode 100644
index 0000000..137765a
--- /dev/null
+++ b/arch/arm/mach-qcom/board-scuba.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include "board-dt.h"
+
+static const char *scuba_dt_match[] __initconst = {
+ "qcom,scuba",
+ NULL
+};
+
+static void __init scuba_init(void)
+{
+ board_dt_populate(NULL);
+}
+
+DT_MACHINE_START(BENGAL,
+ "Qualcomm Technologies, Inc. SCUBA (Flattened Device Tree)")
+ .init_machine = scuba_init,
+ .dt_compat = scuba_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-vexpress/spc.c b/arch/arm/mach-vexpress/spc.c
index 0f5381d..55bbbc3 100644
--- a/arch/arm/mach-vexpress/spc.c
+++ b/arch/arm/mach-vexpress/spc.c
@@ -551,8 +551,9 @@ static struct clk *ve_spc_clk_register(struct device *cpu_dev)
static int __init ve_spc_clk_init(void)
{
- int cpu;
+ int cpu, cluster;
struct clk *clk;
+ bool init_opp_table[MAX_CLUSTERS] = { false };
if (!info)
return 0; /* Continue only if SPC is initialised */
@@ -578,8 +579,17 @@ static int __init ve_spc_clk_init(void)
continue;
}
+ cluster = topology_physical_package_id(cpu_dev->id);
+ if (init_opp_table[cluster])
+ continue;
+
if (ve_init_opp_table(cpu_dev))
pr_warn("failed to initialise cpu%d opp table\n", cpu);
+ else if (dev_pm_opp_set_sharing_cpus(cpu_dev,
+ topology_core_cpumask(cpu_dev->id)))
+ pr_warn("failed to mark OPPs shared for cpu%d\n", cpu);
+ else
+ init_opp_table[cluster] = true;
}
platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0);
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 7c41669..92c3199 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1811,7 +1811,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
int ret = 0;
unsigned int count;
struct scatterlist *s;
- int prot;
+ int prot = 0;
size = PAGE_ALIGN(size);
*handle = ARM_MAPPING_ERROR;
@@ -1820,6 +1820,11 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
if (iova == ARM_MAPPING_ERROR)
return -ENOMEM;
+ /*
+ * Check for coherency.
+ */
+ prot |= is_coherent ? IOMMU_CACHE : 0;
+
for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s)) {
phys_addr_t phys = page_to_phys(sg_page(s));
unsigned int len = PAGE_ALIGN(s->offset + s->length);
@@ -1827,7 +1832,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
if (!is_coherent && (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
- prot = __dma_info_to_prot(dir, attrs);
+ prot |= __dma_info_to_prot(dir, attrs);
ret = iommu_map(mapping->domain, iova, phys, len, prot);
if (ret < 0)
@@ -1931,9 +1936,23 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg,
dma_addr_t iova;
int prot = __dma_info_to_prot(dir, attrs);
bool coherent;
+ /*
+ * This is used to check if there are any unaligned offset/size
+ * given in the scatter list.
+ */
+ bool unaligned_offset_size = false;
- for_each_sg(sg, s, nents, i)
+ for_each_sg(sg, s, nents, i) {
total_length += s->length;
+ if ((s->offset & ~PAGE_MASK) || (s->length & ~PAGE_MASK)) {
+ unaligned_offset_size = true;
+ break;
+ }
+ }
+
+ if (unaligned_offset_size)
+ return __iommu_map_sg(dev, sg, nents, dir, attrs,
+ is_dma_coherent(dev, attrs, false));
iova = __alloc_iova(mapping, total_length);
if (iova == ARM_MAPPING_ERROR)
diff --git a/arch/arm/mm/proc-v7-bugs.c b/arch/arm/mm/proc-v7-bugs.c
index 9a07916..a6554fd 100644
--- a/arch/arm/mm/proc-v7-bugs.c
+++ b/arch/arm/mm/proc-v7-bugs.c
@@ -65,6 +65,9 @@ static void cpu_v7_spectre_init(void)
break;
#ifdef CONFIG_ARM_PSCI
+ case ARM_CPU_PART_BRAHMA_B53:
+ /* Requires no workaround */
+ break;
default:
/* Other ARM CPUs require no workaround */
if (read_cpuid_implementor() == ARM_CPU_IMP_ARM)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index a465396..e8c8e63 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -524,6 +524,22 @@
If unsure, say Y.
+config ARM64_ERRATUM_1542418
+ bool "Cortex-A77: The core might fetch a stale instuction, violating the ordering of instruction fetches"
+ default y
+ help
+ This option adds a workaround for Arm Cortex-A77 erratum 1542418.
+
+ On the affected Cortex-A77 cores (r0p0 and r1p0), software relying
+ on the prefetch-speculation-protection instead of explicit
+ synchronisation may fetch a stale instruction from a CPU-specific
+ cache. This violates the ordering rules for instruction fetches.
+
+ Work around the erratum by ensuring that 60 ASIDs are selected
+ before any ASID is reused.
+
+ If unsure, say Y.
+
config CAVIUM_ERRATUM_22375
bool "Cavium erratum 22375, 24313"
default y
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
index 00f7be6..09a27e0 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
@@ -293,7 +293,7 @@
};
&usb0_phy {
- status = "okay";
+ status = "disabled";
phy-supply = <&usb_otg_pwr>;
};
@@ -303,7 +303,7 @@
};
&usb0 {
- status = "okay";
+ status = "disabled";
};
&usb1 {
diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig
index 713be11..22789da 100644
--- a/arch/arm64/configs/cuttlefish_defconfig
+++ b/arch/arm64/configs/cuttlefish_defconfig
@@ -80,7 +80,6 @@
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_SPARSEMEM_VMEMMAP is not set
CONFIG_KSM=y
-CONFIG_TRANSPARENT_HUGEPAGE=y
CONFIG_ZSMALLOC=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/arm64/configs/vendor/bengal-perf_defconfig b/arch/arm64/configs/vendor/bengal-perf_defconfig
index c806e9b..ebfcc59 100644
--- a/arch/arm64/configs/vendor/bengal-perf_defconfig
+++ b/arch/arm64/configs/vendor/bengal-perf_defconfig
@@ -46,6 +46,7 @@
CONFIG_SLAB_FREELIST_RANDOM=y
CONFIG_SLAB_FREELIST_HARDENED=y
CONFIG_PROFILING=y
+# CONFIG_ZONE_DMA32 is not set
CONFIG_HOTPLUG_SIZE_BITS=29
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_BENGAL=y
diff --git a/arch/arm64/configs/vendor/bengal_defconfig b/arch/arm64/configs/vendor/bengal_defconfig
index 3fd9412..06ab3a3 100644
--- a/arch/arm64/configs/vendor/bengal_defconfig
+++ b/arch/arm64/configs/vendor/bengal_defconfig
@@ -47,6 +47,7 @@
CONFIG_SLAB_FREELIST_RANDOM=y
CONFIG_SLAB_FREELIST_HARDENED=y
CONFIG_PROFILING=y
+# CONFIG_ZONE_DMA32 is not set
CONFIG_HOTPLUG_SIZE_BITS=29
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_BENGAL=y
diff --git a/arch/arm64/configs/vendor/kona-perf_defconfig b/arch/arm64/configs/vendor/kona-perf_defconfig
index e14ff9a..e5faae4 100644
--- a/arch/arm64/configs/vendor/kona-perf_defconfig
+++ b/arch/arm64/configs/vendor/kona-perf_defconfig
@@ -59,6 +59,7 @@
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
+CONFIG_ARM64_LSE_ATOMICS=y
# CONFIG_ARM64_VHE is not set
CONFIG_RANDOMIZE_BASE=y
# CONFIG_EFI is not set
@@ -281,6 +282,7 @@
CONFIG_UID_SYS_STATS=y
CONFIG_OKL4_USER_VIRQ=y
CONFIG_WIGIG_SENSING_SPI=m
+CONFIG_QTI_XR_SMRTVWR_MISC=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
@@ -325,6 +327,8 @@
CONFIG_BUS_AUTO_SUSPEND=y
CONFIG_CNSS_QCA6390=y
CONFIG_CNSS_GENL=y
+CONFIG_NVM=y
+CONFIG_NVM_PBLK=y
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
# CONFIG_INPUT_MOUSE is not set
@@ -453,11 +457,14 @@
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_MSM=y
CONFIG_USB_ISP1760=y
CONFIG_USB_ISP1760_HOST_ROLE=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CP210X=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_LINK_LAYER_TEST=y
CONFIG_USB_REDRIVER_NB7VPQ904M=y
diff --git a/arch/arm64/configs/vendor/kona_defconfig b/arch/arm64/configs/vendor/kona_defconfig
index 8e736d2..bfc8ced 100644
--- a/arch/arm64/configs/vendor/kona_defconfig
+++ b/arch/arm64/configs/vendor/kona_defconfig
@@ -60,6 +60,7 @@
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
+CONFIG_ARM64_LSE_ATOMICS=y
# CONFIG_ARM64_VHE is not set
CONFIG_RANDOMIZE_BASE=y
CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y
@@ -293,6 +294,7 @@
CONFIG_UID_SYS_STATS=y
CONFIG_OKL4_USER_VIRQ=y
CONFIG_WIGIG_SENSING_SPI=m
+CONFIG_QTI_XR_SMRTVWR_MISC=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
@@ -337,6 +339,8 @@
CONFIG_BUS_AUTO_SUSPEND=y
CONFIG_CNSS_QCA6390=y
CONFIG_CNSS_GENL=y
+CONFIG_NVM=y
+CONFIG_NVM_PBLK=y
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
# CONFIG_INPUT_MOUSE is not set
@@ -468,11 +472,14 @@
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_MSM=y
CONFIG_USB_ISP1760=y
CONFIG_USB_ISP1760_HOST_ROLE=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CP210X=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_LINK_LAYER_TEST=y
CONFIG_USB_REDRIVER_NB7VPQ904M=y
diff --git a/arch/arm64/configs/vendor/lito-perf_defconfig b/arch/arm64/configs/vendor/lito-perf_defconfig
index 9442cf7..7a7c518 100644
--- a/arch/arm64/configs/vendor/lito-perf_defconfig
+++ b/arch/arm64/configs/vendor/lito-perf_defconfig
@@ -79,6 +79,7 @@
CONFIG_CPU_BOOST=y
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
CONFIG_ARM_QCOM_CPUFREQ_HW=y
+CONFIG_ARM_QCOM_CPUFREQ_HW_DEBUG=y
CONFIG_MSM_TZ_LOG=y
CONFIG_ARM64_CRYPTO=y
CONFIG_CRYPTO_SHA1_ARM64_CE=y
@@ -334,6 +335,8 @@
CONFIG_TABLET_USB_KBTAB=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_SECURE_TOUCH_SYNAPTICS_DSX=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_QPNP_POWER_ON=y
CONFIG_INPUT_UINPUT=y
diff --git a/arch/arm64/configs/vendor/lito_defconfig b/arch/arm64/configs/vendor/lito_defconfig
index 284a869..f98d64d 100644
--- a/arch/arm64/configs/vendor/lito_defconfig
+++ b/arch/arm64/configs/vendor/lito_defconfig
@@ -80,6 +80,7 @@
CONFIG_CPU_BOOST=y
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
CONFIG_ARM_QCOM_CPUFREQ_HW=y
+CONFIG_ARM_QCOM_CPUFREQ_HW_DEBUG=y
CONFIG_MSM_TZ_LOG=y
CONFIG_ARM64_CRYPTO=y
CONFIG_CRYPTO_SHA1_ARM64_CE=y
@@ -341,6 +342,8 @@
CONFIG_TABLET_USB_KBTAB=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_SECURE_TOUCH_SYNAPTICS_DSX=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_QPNP_POWER_ON=y
CONFIG_INPUT_UINPUT=y
@@ -529,6 +532,7 @@
CONFIG_RMNET_IPA3=y
CONFIG_RNDIS_IPA=y
CONFIG_IPA_UT=y
+CONFIG_USB_BAM=y
CONFIG_QCOM_GENI_SE=y
# CONFIG_QCOM_A53PLL is not set
CONFIG_QCOM_CLK_RPMH=y
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index ba45a37..5b7c3f7 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -54,7 +54,7 @@
#define ARM64_WORKAROUND_1463225 33
#define ARM64_SSBS 34
#define ARM64_WORKAROUND_1188873 35
-
-#define ARM64_NCAPS 36
+#define ARM64_WORKAROUND_1542418 36
+#define ARM64_NCAPS 37
#endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index dda6e50..bf57104 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -509,6 +509,11 @@ static inline bool system_supports_sve(void)
cpus_have_const_cap(ARM64_SVE);
}
+static inline bool system_supports_cnp(void)
+{
+ return false;
+}
+
#define ARM64_SSBD_UNKNOWN -1
#define ARM64_SSBD_FORCE_DISABLE 0
#define ARM64_SSBD_KERNEL 1
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index b255844..ce678f9 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -20,6 +20,7 @@
#include <asm/page.h>
#include <asm/memory.h>
+#include <asm/mmu_context.h>
#include <asm/cpufeature.h>
/*
@@ -528,5 +529,19 @@ static inline int hyp_map_aux_data(void)
#define kvm_phys_to_vttbr(addr) phys_to_ttbr(addr)
+static inline void kvm_workaround_1542418_vmid_rollover(void)
+{
+ unsigned long flags;
+
+ if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_1542418) ||
+ !cpus_have_const_cap(ARM64_WORKAROUND_1542418))
+ return;
+
+ local_irq_save(flags);
+ arm64_workaround_1542418_asid_rollover();
+ local_irq_restore(flags);
+
+}
+
#endif /* __ASSEMBLY__ */
#endif /* __ARM64_KVM_MMU_H__ */
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index a1e5168de..b5c2d7a 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -246,6 +246,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
void verify_cpu_asid_bits(void);
void post_ttbr_update_workaround(void);
+void arm64_workaround_1542418_asid_rollover(void);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index e060c27..5be015e 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -96,13 +96,12 @@
#define PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_WRITE)
#define PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
#define PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN)
-#define PAGE_EXECONLY __pgprot(_PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN)
#define __P000 PAGE_NONE
#define __P001 PAGE_READONLY
#define __P010 PAGE_READONLY
#define __P011 PAGE_READONLY
-#define __P100 PAGE_EXECONLY
+#define __P100 PAGE_READONLY_EXEC
#define __P101 PAGE_READONLY_EXEC
#define __P110 PAGE_READONLY_EXEC
#define __P111 PAGE_READONLY_EXEC
@@ -111,7 +110,7 @@
#define __S001 PAGE_READONLY
#define __S010 PAGE_SHARED
#define __S011 PAGE_SHARED
-#define __S100 PAGE_EXECONLY
+#define __S100 PAGE_READONLY_EXEC
#define __S101 PAGE_READONLY_EXEC
#define __S110 PAGE_SHARED_EXEC
#define __S111 PAGE_SHARED_EXEC
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 6a43177..45705d1 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -106,12 +106,8 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define pte_dirty(pte) (pte_sw_dirty(pte) || pte_hw_dirty(pte))
#define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID))
-/*
- * Execute-only user mappings do not have the PTE_USER bit set. All valid
- * kernel mappings have the PTE_UXN bit set.
- */
#define pte_valid_not_user(pte) \
- ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN))
+ ((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
#define pte_valid_young(pte) \
((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))
#define pte_valid_user(pte) \
@@ -127,8 +123,8 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
/*
* p??_access_permitted() is true for valid user mappings (subject to the
- * write permission check) other than user execute-only which do not have the
- * PTE_USER bit set. PROT_NONE mappings do not have the PTE_VALID bit set.
+ * write permission check). PROT_NONE mappings do not have the PTE_VALID bit
+ * set.
*/
#define pte_access_permitted(pte, write) \
(pte_valid_user(pte) && (!(write) || pte_write(pte)))
diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h
index c320f3b..b0d4bfc 100644
--- a/arch/arm64/include/asm/traps.h
+++ b/arch/arm64/include/asm/traps.h
@@ -120,4 +120,6 @@ static inline u32 arm64_ras_serror_get_severity(u32 esr)
bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned int esr);
void __noreturn arm64_serror_panic(struct pt_regs *regs, u32 esr);
+static inline void get_timer_count_hook_init(void) {}
+static inline void get_timer_freq_hook_init(void) {}
#endif
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index cd250ec..dda0989 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -23,6 +23,7 @@
#include <asm/cpu.h>
#include <asm/cputype.h>
#include <asm/cpufeature.h>
+#include <asm/mmu_context.h>
#include <asm/smp_plat.h>
static bool __maybe_unused
@@ -643,6 +644,18 @@ needs_tx2_tvm_workaround(const struct arm64_cpu_capabilities *entry,
return false;
}
+#ifdef CONFIG_ARM64_ERRATUM_1542418
+static void run_workaround_1542418_asid_rollover(const struct arm64_cpu_capabilities *c)
+{
+ /*
+ * If this CPU is affected by the erratum, run the workaround
+ * to protect us in case we are running on a kexec'ed kernel.
+ */
+ if (c->matches(c, SCOPE_LOCAL_CPU))
+ arm64_workaround_1542418_asid_rollover();
+}
+#endif
+
#ifdef CONFIG_HARDEN_EL2_VECTORS
static const struct midr_range arm64_harden_el2_vectors[] = {
@@ -876,6 +889,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
.matches = needs_tx2_tvm_workaround,
},
#endif
+#ifdef CONFIG_ARM64_ERRATUM_1542418
+ {
+ .desc = "ARM erratum 1542418",
+ .capability = ARM64_WORKAROUND_1542418,
+ ERRATA_MIDR_RANGE(MIDR_CORTEX_A77, 0, 0, 1, 0),
+ .cpu_enable = run_workaround_1542418_asid_rollover,
+ },
+#endif
{
}
};
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index e8edbf1..3856d51 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -84,7 +84,8 @@ static void cpu_psci_cpu_die(unsigned int cpu)
static int cpu_psci_cpu_kill(unsigned int cpu)
{
- int err, i;
+ int err;
+ unsigned long start, end;
if (!psci_ops.affinity_info)
return 0;
@@ -94,16 +95,18 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
* while it is dying. So, try again a few times.
*/
- for (i = 0; i < 10; i++) {
+ start = jiffies;
+ end = start + msecs_to_jiffies(100);
+ do {
err = psci_ops.affinity_info(cpu_logical_map(cpu), 0);
if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) {
- pr_info("CPU%d killed.\n", cpu);
+ pr_info("CPU%d killed (polled %d ms)\n", cpu,
+ jiffies_to_msecs(jiffies - start));
return 0;
}
- msleep(10);
- pr_info("Retrying again to check for CPU kill\n");
- }
+ usleep_range(100, 1000);
+ } while (time_before(jiffies, end));
pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n",
cpu, err);
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 6da2bbd..0c073f3 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2174,8 +2174,11 @@ static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
if ((id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM64_SYSREG)
return NULL;
+ if (!index_to_params(id, ¶ms))
+ return NULL;
+
table = get_target_table(vcpu->arch.target, true, &num);
- r = find_reg_by_id(id, ¶ms, table, num);
+ r = find_reg(¶ms, table, num);
if (!r)
r = find_reg(¶ms, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index c127f94..7294200 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -88,6 +88,75 @@ void verify_cpu_asid_bits(void)
}
}
+
+/*
+ * When the CnP is active, the caller must have set the ttbr0 to reserved
+ * before calling this function.
+ * Upon completion, the caller must ensure to:
+ * - restore the ttbr0
+ * - execute isb() to synchronize the change.
+ */
+static void __arm64_workaround_1542418_asid_rollover(void)
+{
+ phys_addr_t ttbr1_baddr;
+ u64 idx, ttbr1; /* ASID is in ttbr1 due to TCR_EL1.A1 */
+
+ if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_1542418) ||
+ !cpus_have_const_cap(ARM64_WORKAROUND_1542418) ||
+ !this_cpu_has_cap(ARM64_WORKAROUND_1542418))
+ return;
+
+ /*
+ * We're about to use an arbitrary set of ASIDs, which may have
+ * live entries in the TLB (and on other CPUs with CnP). Ensure
+ * that we can't allocate conflicting entries using this task's
+ * TTBR0.
+ */
+ if (!system_supports_cnp())
+ cpu_set_reserved_ttbr0();
+ /* else: the caller must have already set this */
+
+ ttbr1 = read_sysreg(ttbr1_el1);
+ ttbr1_baddr = ttbr1 & ~TTBR_ASID_MASK;
+
+ /*
+ * Select 60 asids to invalidate the branch history for this generation.
+ * If kpti is in use we avoid selecting a user asid as
+ * __sdei_asm_entry_trampoline() uses USER_ASID_FLAG to determine if
+ * the NMI interrupted the kpti trampoline. Avoid using the reserved
+ * asid 0.
+ */
+ for (idx = 1; idx <= 61; idx++) {
+ write_sysreg((idx2asid(idx) << 48) | ttbr1_baddr, ttbr1_el1);
+ isb();
+ }
+
+ /* restore the current ASID */
+ write_sysreg(ttbr1, ttbr1_el1);
+
+ /*
+ * Rely on local_flush_tlb_all()'s isb to complete the ASID restore.
+ * check_and_switch_context() will call cpu_switch_mm() to (re)set ttbr0_el1.
+ */
+}
+
+void arm64_workaround_1542418_asid_rollover(void)
+{
+ u64 ttbr0 = read_sysreg(ttbr0_el1);
+
+ lockdep_assert_irqs_disabled();
+
+ /* Mirror check_and_switch_context() */
+ if (system_supports_cnp())
+ cpu_set_reserved_ttbr0();
+
+ __arm64_workaround_1542418_asid_rollover();
+ isb();
+
+ write_sysreg(ttbr0, ttbr0_el1);
+ isb();
+}
+
static void flush_context(unsigned int cpu)
{
int i;
@@ -227,8 +296,10 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
atomic64_set(&mm->context.id, asid);
}
- if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending))
+ if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending)) {
+ __arm64_workaround_1542418_asid_rollover();
local_flush_tlb_all();
+ }
atomic64_set(&per_cpu(active_asids, cpu), asid);
raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 9c94715..296e04b 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -427,7 +427,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
struct mm_struct *mm;
struct siginfo si;
vm_fault_t fault, major = 0;
- unsigned long vm_flags = VM_READ | VM_WRITE;
+ unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC;
unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
struct vm_area_struct *vma = NULL;
diff --git a/arch/mips/include/asm/pgtable-64.h b/arch/mips/include/asm/pgtable-64.h
index 93a9dce..813dfe5 100644
--- a/arch/mips/include/asm/pgtable-64.h
+++ b/arch/mips/include/asm/pgtable-64.h
@@ -18,10 +18,12 @@
#include <asm/fixmap.h>
#define __ARCH_USE_5LEVEL_HACK
-#if defined(CONFIG_PAGE_SIZE_64KB) && !defined(CONFIG_MIPS_VA_BITS_48)
+#if CONFIG_PGTABLE_LEVELS == 2
#include <asm-generic/pgtable-nopmd.h>
-#elif !(defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_MIPS_VA_BITS_48))
+#elif CONFIG_PGTABLE_LEVELS == 3
#include <asm-generic/pgtable-nopud.h>
+#else
+#include <asm-generic/5level-fixup.h>
#endif
/*
@@ -216,6 +218,9 @@ static inline unsigned long pgd_page_vaddr(pgd_t pgd)
return pgd_val(pgd);
}
+#define pgd_phys(pgd) virt_to_phys((void *)pgd_val(pgd))
+#define pgd_page(pgd) (pfn_to_page(pgd_phys(pgd) >> PAGE_SHIFT))
+
static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address)
{
return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(address);
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index 4993db4..ee26f9a 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -49,8 +49,26 @@ struct thread_info {
.addr_limit = KERNEL_DS, \
}
-/* How to get the thread information struct from C. */
+/*
+ * A pointer to the struct thread_info for the currently executing thread is
+ * held in register $28/$gp.
+ *
+ * We declare __current_thread_info as a global register variable rather than a
+ * local register variable within current_thread_info() because clang doesn't
+ * support explicit local register variables.
+ *
+ * When building the VDSO we take care not to declare the global register
+ * variable because this causes GCC to not preserve the value of $28/$gp in
+ * functions that change its value (which is common in the PIC VDSO when
+ * accessing the GOT). Since the VDSO shouldn't be accessing
+ * __current_thread_info anyway we declare it extern in order to cause a link
+ * failure if it's referenced.
+ */
+#ifdef __VDSO__
+extern struct thread_info *__current_thread_info;
+#else
register struct thread_info *__current_thread_info __asm__("$28");
+#endif
static inline struct thread_info *current_thread_info(void)
{
diff --git a/arch/mips/net/ebpf_jit.c b/arch/mips/net/ebpf_jit.c
index 9bda82ed..3832c46 100644
--- a/arch/mips/net/ebpf_jit.c
+++ b/arch/mips/net/ebpf_jit.c
@@ -586,6 +586,7 @@ static void emit_const_to_reg(struct jit_ctx *ctx, int dst, u64 value)
static int emit_bpf_tail_call(struct jit_ctx *ctx, int this_idx)
{
int off, b_off;
+ int tcc_reg;
ctx->flags |= EBPF_SEEN_TC;
/*
@@ -598,14 +599,14 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int this_idx)
b_off = b_imm(this_idx + 1, ctx);
emit_instr(ctx, bne, MIPS_R_AT, MIPS_R_ZERO, b_off);
/*
- * if (--TCC < 0)
+ * if (TCC-- < 0)
* goto out;
*/
/* Delay slot */
- emit_instr(ctx, daddiu, MIPS_R_T5,
- (ctx->flags & EBPF_TCC_IN_V1) ? MIPS_R_V1 : MIPS_R_S4, -1);
+ tcc_reg = (ctx->flags & EBPF_TCC_IN_V1) ? MIPS_R_V1 : MIPS_R_S4;
+ emit_instr(ctx, daddiu, MIPS_R_T5, tcc_reg, -1);
b_off = b_imm(this_idx + 1, ctx);
- emit_instr(ctx, bltz, MIPS_R_T5, b_off);
+ emit_instr(ctx, bltz, tcc_reg, b_off);
/*
* prog = array->ptrs[index];
* if (prog == NULL)
diff --git a/arch/parisc/include/asm/cmpxchg.h b/arch/parisc/include/asm/cmpxchg.h
index f627c37..ab5c215 100644
--- a/arch/parisc/include/asm/cmpxchg.h
+++ b/arch/parisc/include/asm/cmpxchg.h
@@ -44,8 +44,14 @@ __xchg(unsigned long x, __volatile__ void *ptr, int size)
** if (((unsigned long)p & 0xf) == 0)
** return __ldcw(p);
*/
-#define xchg(ptr, x) \
- ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+#define xchg(ptr, x) \
+({ \
+ __typeof__(*(ptr)) __ret; \
+ __typeof__(*(ptr)) _x_ = (x); \
+ __ret = (__typeof__(*(ptr))) \
+ __xchg((unsigned long)_x_, (ptr), sizeof(*(ptr))); \
+ __ret; \
+})
/* bug catcher for when unsupported size is used - won't link */
extern void __cmpxchg_called_with_bad_pointer(void);
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
index 5eb979d..a1a5e4c 100644
--- a/arch/parisc/kernel/drivers.c
+++ b/arch/parisc/kernel/drivers.c
@@ -789,7 +789,7 @@ EXPORT_SYMBOL(device_to_hwpath);
static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
struct device *parent);
-static void walk_lower_bus(struct parisc_device *dev)
+static void __init walk_lower_bus(struct parisc_device *dev)
{
unsigned long io_io_low, io_io_high;
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index dfcb698..e43321f 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -90,11 +90,13 @@
endif
ifdef CONFIG_PPC64
+ifndef CONFIG_CC_IS_CLANG
cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(call cc-option,-mabi=elfv1)
cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(call cc-option,-mcall-aixdesc)
aflags-$(CONFIG_CPU_BIG_ENDIAN) += $(call cc-option,-mabi=elfv1)
aflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -mabi=elfv2
endif
+endif
ifneq ($(cc-name),clang)
cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -mno-strict-align
@@ -134,6 +136,7 @@
endif
CFLAGS-$(CONFIG_PPC64) := $(call cc-option,-mtraceback=no)
+ifndef CONFIG_CC_IS_CLANG
ifdef CONFIG_CPU_LITTLE_ENDIAN
CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2,$(call cc-option,-mcall-aixdesc))
AFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2)
@@ -142,6 +145,7 @@
CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcall-aixdesc)
AFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv1)
endif
+endif
CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcmodel=medium,$(call cc-option,-mminimal-toc))
CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mno-pointers-to-nested-functions)
diff --git a/arch/powerpc/boot/libfdt_env.h b/arch/powerpc/boot/libfdt_env.h
index 2abc8e8..9757d4f 100644
--- a/arch/powerpc/boot/libfdt_env.h
+++ b/arch/powerpc/boot/libfdt_env.h
@@ -6,6 +6,8 @@
#include <string.h>
#define INT_MAX ((int)(~0U>>1))
+#define UINT32_MAX ((u32)~0U)
+#define INT32_MAX ((s32)(UINT32_MAX >> 1))
#include "of.h"
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index e991821..a061c3d 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -458,9 +458,100 @@ static inline u32 kvmppc_get_xics_latch(void)
return xirr;
}
-static inline void kvmppc_set_host_ipi(int cpu, u8 host_ipi)
+/*
+ * To avoid the need to unnecessarily exit fully to the host kernel, an IPI to
+ * a CPU thread that's running/napping inside of a guest is by default regarded
+ * as a request to wake the CPU (if needed) and continue execution within the
+ * guest, potentially to process new state like externally-generated
+ * interrupts or IPIs sent from within the guest itself (e.g. H_PROD/H_IPI).
+ *
+ * To force an exit to the host kernel, kvmppc_set_host_ipi() must be called
+ * prior to issuing the IPI to set the corresponding 'host_ipi' flag in the
+ * target CPU's PACA. To avoid unnecessary exits to the host, this flag should
+ * be immediately cleared via kvmppc_clear_host_ipi() by the IPI handler on
+ * the receiving side prior to processing the IPI work.
+ *
+ * NOTE:
+ *
+ * We currently issue an smp_mb() at the beginning of kvmppc_set_host_ipi().
+ * This is to guard against sequences such as the following:
+ *
+ * CPU
+ * X: smp_muxed_ipi_set_message():
+ * X: smp_mb()
+ * X: message[RESCHEDULE] = 1
+ * X: doorbell_global_ipi(42):
+ * X: kvmppc_set_host_ipi(42)
+ * X: ppc_msgsnd_sync()/smp_mb()
+ * X: ppc_msgsnd() -> 42
+ * 42: doorbell_exception(): // from CPU X
+ * 42: ppc_msgsync()
+ * 105: smp_muxed_ipi_set_message():
+ * 105: smb_mb()
+ * // STORE DEFERRED DUE TO RE-ORDERING
+ * --105: message[CALL_FUNCTION] = 1
+ * | 105: doorbell_global_ipi(42):
+ * | 105: kvmppc_set_host_ipi(42)
+ * | 42: kvmppc_clear_host_ipi(42)
+ * | 42: smp_ipi_demux_relaxed()
+ * | 42: // returns to executing guest
+ * | // RE-ORDERED STORE COMPLETES
+ * ->105: message[CALL_FUNCTION] = 1
+ * 105: ppc_msgsnd_sync()/smp_mb()
+ * 105: ppc_msgsnd() -> 42
+ * 42: local_paca->kvm_hstate.host_ipi == 0 // IPI ignored
+ * 105: // hangs waiting on 42 to process messages/call_single_queue
+ *
+ * We also issue an smp_mb() at the end of kvmppc_clear_host_ipi(). This is
+ * to guard against sequences such as the following (as well as to create
+ * a read-side pairing with the barrier in kvmppc_set_host_ipi()):
+ *
+ * CPU
+ * X: smp_muxed_ipi_set_message():
+ * X: smp_mb()
+ * X: message[RESCHEDULE] = 1
+ * X: doorbell_global_ipi(42):
+ * X: kvmppc_set_host_ipi(42)
+ * X: ppc_msgsnd_sync()/smp_mb()
+ * X: ppc_msgsnd() -> 42
+ * 42: doorbell_exception(): // from CPU X
+ * 42: ppc_msgsync()
+ * // STORE DEFERRED DUE TO RE-ORDERING
+ * -- 42: kvmppc_clear_host_ipi(42)
+ * | 42: smp_ipi_demux_relaxed()
+ * | 105: smp_muxed_ipi_set_message():
+ * | 105: smb_mb()
+ * | 105: message[CALL_FUNCTION] = 1
+ * | 105: doorbell_global_ipi(42):
+ * | 105: kvmppc_set_host_ipi(42)
+ * | // RE-ORDERED STORE COMPLETES
+ * -> 42: kvmppc_clear_host_ipi(42)
+ * 42: // returns to executing guest
+ * 105: ppc_msgsnd_sync()/smp_mb()
+ * 105: ppc_msgsnd() -> 42
+ * 42: local_paca->kvm_hstate.host_ipi == 0 // IPI ignored
+ * 105: // hangs waiting on 42 to process messages/call_single_queue
+ */
+static inline void kvmppc_set_host_ipi(int cpu)
{
- paca_ptrs[cpu]->kvm_hstate.host_ipi = host_ipi;
+ /*
+ * order stores of IPI messages vs. setting of host_ipi flag
+ *
+ * pairs with the barrier in kvmppc_clear_host_ipi()
+ */
+ smp_mb();
+ paca_ptrs[cpu]->kvm_hstate.host_ipi = 1;
+}
+
+static inline void kvmppc_clear_host_ipi(int cpu)
+{
+ paca_ptrs[cpu]->kvm_hstate.host_ipi = 0;
+ /*
+ * order clearing of host_ipi flag vs. processing of IPI messages
+ *
+ * pairs with the barrier in kvmppc_set_host_ipi()
+ */
+ smp_mb();
}
static inline void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu)
@@ -489,7 +580,10 @@ static inline u32 kvmppc_get_xics_latch(void)
return 0;
}
-static inline void kvmppc_set_host_ipi(int cpu, u8 host_ipi)
+static inline void kvmppc_set_host_ipi(int cpu)
+{}
+
+static inline void kvmppc_clear_host_ipi(int cpu)
{}
static inline void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu)
diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
index 685c723..3198dde 100644
--- a/arch/powerpc/include/asm/spinlock.h
+++ b/arch/powerpc/include/asm/spinlock.h
@@ -19,6 +19,7 @@
*
* (the type definitions are in asm/spinlock_types.h)
*/
+#include <linux/jump_label.h>
#include <linux/irqflags.h>
#ifdef CONFIG_PPC64
#include <asm/paca.h>
@@ -53,10 +54,12 @@
#endif
#ifdef CONFIG_PPC_PSERIES
+DECLARE_STATIC_KEY_FALSE(shared_processor);
+
#define vcpu_is_preempted vcpu_is_preempted
static inline bool vcpu_is_preempted(int cpu)
{
- if (!firmware_has_feature(FW_FEATURE_SPLPAR))
+ if (!static_branch_unlikely(&shared_processor))
return false;
return !!(be32_to_cpu(lppaca_of(cpu).yield_count) & 1);
}
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c
index b6fe883..5828144 100644
--- a/arch/powerpc/kernel/dbell.c
+++ b/arch/powerpc/kernel/dbell.c
@@ -36,7 +36,7 @@ void doorbell_global_ipi(int cpu)
{
u32 tag = get_hard_smp_processor_id(cpu);
- kvmppc_set_host_ipi(cpu, 1);
+ kvmppc_set_host_ipi(cpu);
/* Order previous accesses vs. msgsnd, which is treated as a store */
ppc_msgsnd_sync();
ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
@@ -51,7 +51,7 @@ void doorbell_core_ipi(int cpu)
{
u32 tag = cpu_thread_in_core(cpu);
- kvmppc_set_host_ipi(cpu, 1);
+ kvmppc_set_host_ipi(cpu);
/* Order previous accesses vs. msgsnd, which is treated as a store */
ppc_msgsnd_sync();
ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
@@ -86,7 +86,7 @@ void doorbell_exception(struct pt_regs *regs)
may_hard_irq_enable();
- kvmppc_set_host_ipi(smp_processor_id(), 0);
+ kvmppc_clear_host_ipi(smp_processor_id());
__this_cpu_inc(irq_stat.doorbell_irqs);
smp_ipi_demux_relaxed(); /* already performed the barrier */
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 916ddc4..d37704e 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -634,8 +634,6 @@ void __do_irq(struct pt_regs *regs)
trace_irq_entry(regs);
- check_stack_overflow();
-
/*
* Query the platform PIC for the interrupt & ack it.
*
@@ -667,6 +665,8 @@ void do_IRQ(struct pt_regs *regs)
irqtp = hardirq_ctx[raw_smp_processor_id()];
sirqtp = softirq_ctx[raw_smp_processor_id()];
+ check_stack_overflow();
+
/* Already there ? */
if (unlikely(curtp == irqtp || curtp == sirqtp)) {
__do_irq(regs);
diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c
index a5c5940..6a3dde9 100644
--- a/arch/powerpc/kernel/security.c
+++ b/arch/powerpc/kernel/security.c
@@ -134,32 +134,33 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, cha
thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV);
- if (rfi_flush || thread_priv) {
+ if (rfi_flush) {
struct seq_buf s;
seq_buf_init(&s, buf, PAGE_SIZE - 1);
- seq_buf_printf(&s, "Mitigation: ");
-
- if (rfi_flush)
- seq_buf_printf(&s, "RFI Flush");
-
- if (rfi_flush && thread_priv)
- seq_buf_printf(&s, ", ");
-
+ seq_buf_printf(&s, "Mitigation: RFI Flush");
if (thread_priv)
- seq_buf_printf(&s, "L1D private per thread");
+ seq_buf_printf(&s, ", L1D private per thread");
seq_buf_printf(&s, "\n");
return s.len;
}
+ if (thread_priv)
+ return sprintf(buf, "Vulnerable: L1D private per thread\n");
+
if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) &&
!security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR))
return sprintf(buf, "Not affected\n");
return sprintf(buf, "Vulnerable\n");
}
+
+ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return cpu_show_meltdown(dev, attr, buf);
+}
#endif
ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf)
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 8487ad6..5449e76 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -235,7 +235,7 @@ static u64 scan_dispatch_log(u64 stop_tb)
* Accumulate stolen time by scanning the dispatch trace log.
* Called on entry from user mode.
*/
-void accumulate_stolen_time(void)
+void notrace accumulate_stolen_time(void)
{
u64 sst, ust;
unsigned long save_irq_soft_mask = irq_soft_mask_return();
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c
index 758d1d2..aaafb9f 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_xics.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
@@ -61,7 +61,7 @@ static inline void icp_send_hcore_msg(int hcore, struct kvm_vcpu *vcpu)
hcpu = hcore << threads_shift;
kvmppc_host_rm_ops_hv->rm_core[hcore].rm_data = vcpu;
smp_muxed_ipi_set_message(hcpu, PPC_MSG_RM_HOST_ACTION);
- kvmppc_set_host_ipi(hcpu, 1);
+ kvmppc_set_host_ipi(hcpu);
smp_mb();
kvmhv_rm_send_ipi(hcpu);
}
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index b1007e9..8894c8f 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -296,10 +296,18 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
ret = mmu_hash_ops.hpte_insert(hpteg, vpn, paddr, tprot,
HPTE_V_BOLTED, psize, psize,
ssize);
-
+ if (ret == -1) {
+ /* Try to remove a non bolted entry */
+ ret = mmu_hash_ops.hpte_remove(hpteg);
+ if (ret != -1)
+ ret = mmu_hash_ops.hpte_insert(hpteg, vpn, paddr, tprot,
+ HPTE_V_BOLTED, psize, psize,
+ ssize);
+ }
if (ret < 0)
break;
+ cond_resched();
#ifdef CONFIG_DEBUG_PAGEALLOC
if (debug_pagealloc_enabled() &&
(paddr >> PAGE_SHIFT) < linear_map_hash_count)
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 04ccb27..9a6afd9 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -344,6 +344,14 @@ void __init mem_init(void)
BUILD_BUG_ON(MMU_PAGE_COUNT > 16);
#ifdef CONFIG_SWIOTLB
+ /*
+ * Some platforms (e.g. 85xx) limit DMA-able memory way below
+ * 4G. We force memblock to bottom-up mode to ensure that the
+ * memory allocated in swiotlb_init() is DMA-able.
+ * As it's the last memblock allocation, no need to reset it
+ * back to to-down.
+ */
+ memblock_set_bottom_up(true);
swiotlb_init(0);
#endif
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index fdd9577..3d3c989 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -223,7 +223,7 @@ static void pnv_smp_cpu_kill_self(void)
* for coming online, which are handled via
* generic_check_cpu_restart() calls.
*/
- kvmppc_set_host_ipi(cpu, 0);
+ kvmppc_clear_host_ipi(cpu);
srr1 = pnv_cpu_offline(cpu);
diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c
index 25427a4..502ebcc 100644
--- a/arch/powerpc/platforms/pseries/cmm.c
+++ b/arch/powerpc/platforms/pseries/cmm.c
@@ -425,6 +425,10 @@ static struct bus_type cmm_subsys = {
.dev_name = "cmm",
};
+static void cmm_release_device(struct device *dev)
+{
+}
+
/**
* cmm_sysfs_register - Register with sysfs
*
@@ -440,6 +444,7 @@ static int cmm_sysfs_register(struct device *dev)
dev->id = 0;
dev->bus = &cmm_subsys;
+ dev->release = cmm_release_device;
if ((rc = device_register(dev)))
goto subsys_unregister;
diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
index 74da18d..73ec15c 100644
--- a/arch/powerpc/platforms/pseries/hvconsole.c
+++ b/arch/powerpc/platforms/pseries/hvconsole.c
@@ -62,7 +62,7 @@ EXPORT_SYMBOL(hvc_get_chars);
* @vtermno: The vtermno or unit_address of the adapter from which the data
* originated.
* @buf: The character buffer that contains the character data to send to
- * firmware.
+ * firmware. Must be at least 16 bytes, even if count is less than 16.
* @count: Send this number of characters.
*/
int hvc_put_chars(uint32_t vtermno, const char *buf, int count)
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 67f4915..c2d318d 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -75,6 +75,9 @@
#include "pseries.h"
#include "../../../../drivers/pci/pci.h"
+DEFINE_STATIC_KEY_FALSE(shared_processor);
+EXPORT_SYMBOL_GPL(shared_processor);
+
int CMO_PrPSP = -1;
int CMO_SecPSP = -1;
unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K);
@@ -761,6 +764,10 @@ static void __init pSeries_setup_arch(void)
if (firmware_has_feature(FW_FEATURE_LPAR)) {
vpa_init(boot_cpuid);
+
+ if (lppaca_shared_proc(get_lppaca()))
+ static_branch_enable(&shared_processor);
+
ppc_md.power_save = pseries_lpar_idle;
ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
#ifdef CONFIG_PCI_IOV
diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c
index 37bfbc5..340de58 100644
--- a/arch/powerpc/sysdev/xics/icp-native.c
+++ b/arch/powerpc/sysdev/xics/icp-native.c
@@ -145,7 +145,7 @@ static unsigned int icp_native_get_irq(void)
static void icp_native_cause_ipi(int cpu)
{
- kvmppc_set_host_ipi(cpu, 1);
+ kvmppc_set_host_ipi(cpu);
icp_native_set_qirr(cpu, IPI_PRIORITY);
}
@@ -184,7 +184,7 @@ void icp_native_flush_interrupt(void)
if (vec == XICS_IPI) {
/* Clear pending IPI */
int cpu = smp_processor_id();
- kvmppc_set_host_ipi(cpu, 0);
+ kvmppc_clear_host_ipi(cpu);
icp_native_set_qirr(cpu, 0xff);
} else {
pr_err("XICS: hw interrupt 0x%x to offline cpu, disabling\n",
@@ -205,7 +205,7 @@ static irqreturn_t icp_native_ipi_action(int irq, void *dev_id)
{
int cpu = smp_processor_id();
- kvmppc_set_host_ipi(cpu, 0);
+ kvmppc_clear_host_ipi(cpu);
icp_native_set_qirr(cpu, 0xff);
return smp_ipi_demux();
diff --git a/arch/powerpc/sysdev/xics/icp-opal.c b/arch/powerpc/sysdev/xics/icp-opal.c
index c71d2ea..e3e52cf 100644
--- a/arch/powerpc/sysdev/xics/icp-opal.c
+++ b/arch/powerpc/sysdev/xics/icp-opal.c
@@ -130,7 +130,7 @@ static void icp_opal_cause_ipi(int cpu)
{
int hw_cpu = get_hard_smp_processor_id(cpu);
- kvmppc_set_host_ipi(cpu, 1);
+ kvmppc_set_host_ipi(cpu);
opal_int_set_mfrr(hw_cpu, IPI_PRIORITY);
}
@@ -138,7 +138,7 @@ static irqreturn_t icp_opal_ipi_action(int irq, void *dev_id)
{
int cpu = smp_processor_id();
- kvmppc_set_host_ipi(cpu, 0);
+ kvmppc_clear_host_ipi(cpu);
opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
return smp_ipi_demux();
@@ -161,7 +161,7 @@ void icp_opal_flush_interrupt(void)
if (vec == XICS_IPI) {
/* Clear pending IPI */
int cpu = smp_processor_id();
- kvmppc_set_host_ipi(cpu, 0);
+ kvmppc_clear_host_ipi(cpu);
opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
} else {
pr_err("XICS: hw interrupt 0x%x to offline cpu, "
diff --git a/arch/powerpc/tools/relocs_check.sh b/arch/powerpc/tools/relocs_check.sh
index ec2d5c83..d6c16e7 100755
--- a/arch/powerpc/tools/relocs_check.sh
+++ b/arch/powerpc/tools/relocs_check.sh
@@ -23,7 +23,7 @@
vmlinux="$2"
bad_relocs=$(
-"$objdump" -R "$vmlinux" |
+$objdump -R "$vmlinux" |
# Only look at relocation lines.
grep -E '\<R_' |
# These relocations are okay
diff --git a/arch/powerpc/tools/unrel_branch_check.sh b/arch/powerpc/tools/unrel_branch_check.sh
index 1e972df..7711475 100755
--- a/arch/powerpc/tools/unrel_branch_check.sh
+++ b/arch/powerpc/tools/unrel_branch_check.sh
@@ -18,14 +18,14 @@
#__end_interrupts should be located within the first 64K
end_intr=0x$(
-"$objdump" -R "$vmlinux" -d --start-address=0xc000000000000000 \
+$objdump -R "$vmlinux" -d --start-address=0xc000000000000000 \
--stop-address=0xc000000000010000 |
grep '\<__end_interrupts>:' |
awk '{print $1}'
)
BRANCHES=$(
-"$objdump" -R "$vmlinux" -D --start-address=0xc000000000000000 \
+$objdump -R "$vmlinux" -D --start-address=0xc000000000000000 \
--stop-address=${end_intr} |
grep -e "^c[0-9a-f]*:[[:space:]]*\([0-9a-f][0-9a-f][[:space:]]\)\{4\}[[:space:]]*b" |
grep -v '\<__start_initialization_multiplatform>' |
diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c
index a840b7d..6d39f64 100644
--- a/arch/riscv/kernel/ftrace.c
+++ b/arch/riscv/kernel/ftrace.c
@@ -142,7 +142,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
*/
old = *parent;
- if (function_graph_enter(old, self_addr, frame_pointer, parent))
+ if (!function_graph_enter(old, self_addr, frame_pointer, parent))
*parent = return_hooker;
}
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index 5ee7337..67838df 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -56,7 +56,12 @@ static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long address)
crst_table_init(table, _REGION2_ENTRY_EMPTY);
return (p4d_t *) table;
}
-#define p4d_free(mm, p4d) crst_table_free(mm, (unsigned long *) p4d)
+
+static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d)
+{
+ if (!mm_p4d_folded(mm))
+ crst_table_free(mm, (unsigned long *) p4d);
+}
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
{
@@ -65,7 +70,12 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
crst_table_init(table, _REGION3_ENTRY_EMPTY);
return (pud_t *) table;
}
-#define pud_free(mm, pud) crst_table_free(mm, (unsigned long *) pud)
+
+static inline void pud_free(struct mm_struct *mm, pud_t *pud)
+{
+ if (!mm_pud_folded(mm))
+ crst_table_free(mm, (unsigned long *) pud);
+}
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
{
@@ -83,6 +93,8 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
+ if (mm_pmd_folded(mm))
+ return;
pgtable_pmd_page_dtor(virt_to_page(pmd));
crst_table_free(mm, (unsigned long *) pmd);
}
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h
index 64539c2..2dc9eb4 100644
--- a/arch/s390/include/asm/timex.h
+++ b/arch/s390/include/asm/timex.h
@@ -10,8 +10,9 @@
#ifndef _ASM_S390_TIMEX_H
#define _ASM_S390_TIMEX_H
-#include <asm/lowcore.h>
+#include <linux/preempt.h>
#include <linux/time64.h>
+#include <asm/lowcore.h>
/* The value of the TOD clock for 1.1.1970. */
#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
@@ -186,15 +187,18 @@ extern unsigned char tod_clock_base[16] __aligned(8);
/**
* get_clock_monotonic - returns current time in clock rate units
*
- * The caller must ensure that preemption is disabled.
* The clock and tod_clock_base get changed via stop_machine.
- * Therefore preemption must be disabled when calling this
- * function, otherwise the returned value is not guaranteed to
- * be monotonic.
+ * Therefore preemption must be disabled, otherwise the returned
+ * value is not guaranteed to be monotonic.
*/
static inline unsigned long long get_tod_clock_monotonic(void)
{
- return get_tod_clock() - *(unsigned long long *) &tod_clock_base[1];
+ unsigned long long tod;
+
+ preempt_disable_notrace();
+ tod = get_tod_clock() - *(unsigned long long *) &tod_clock_base[1];
+ preempt_enable_notrace();
+ return tod;
}
/**
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index b2c68fb..41925f2 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -462,10 +462,11 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
ptr += sprintf(ptr, "%%c%i", value);
else if (operand->flags & OPERAND_VR)
ptr += sprintf(ptr, "%%v%i", value);
- else if (operand->flags & OPERAND_PCREL)
- ptr += sprintf(ptr, "%lx", (signed int) value
- + addr);
- else if (operand->flags & OPERAND_SIGNED)
+ else if (operand->flags & OPERAND_PCREL) {
+ void *pcrel = (void *)((int)value + addr);
+
+ ptr += sprintf(ptr, "%px", pcrel);
+ } else if (operand->flags & OPERAND_SIGNED)
ptr += sprintf(ptr, "%i", value);
else
ptr += sprintf(ptr, "%u", value);
@@ -537,7 +538,7 @@ void show_code(struct pt_regs *regs)
else
*ptr++ = ' ';
addr = regs->psw.addr + start - 32;
- ptr += sprintf(ptr, "%016lx: ", addr);
+ ptr += sprintf(ptr, "%px: ", (void *)addr);
if (start + opsize >= end)
break;
for (i = 0; i < opsize; i++)
@@ -565,7 +566,7 @@ void print_fn_code(unsigned char *code, unsigned long len)
opsize = insn_length(*code);
if (opsize > len)
break;
- ptr += sprintf(ptr, "%p: ", code);
+ ptr += sprintf(ptr, "%px: ", code);
for (i = 0; i < opsize; i++)
ptr += sprintf(ptr, "%02x", code[i]);
*ptr++ = '\t';
diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c
index df92c2a..5bfb1ce 100644
--- a/arch/s390/kernel/perf_cpum_sf.c
+++ b/arch/s390/kernel/perf_cpum_sf.c
@@ -193,7 +193,7 @@ static int realloc_sampling_buffer(struct sf_buffer *sfb,
unsigned long num_sdb, gfp_t gfp_flags)
{
int i, rc;
- unsigned long *new, *tail;
+ unsigned long *new, *tail, *tail_prev = NULL;
if (!sfb->sdbt || !sfb->tail)
return -EINVAL;
@@ -232,6 +232,7 @@ static int realloc_sampling_buffer(struct sf_buffer *sfb,
sfb->num_sdbt++;
/* Link current page to tail of chain */
*tail = (unsigned long)(void *) new + 1;
+ tail_prev = tail;
tail = new;
}
@@ -241,10 +242,22 @@ static int realloc_sampling_buffer(struct sf_buffer *sfb,
* issue, a new realloc call (if required) might succeed.
*/
rc = alloc_sample_data_block(tail, gfp_flags);
- if (rc)
+ if (rc) {
+ /* Undo last SDBT. An SDBT with no SDB at its first
+ * entry but with an SDBT entry instead can not be
+ * handled by the interrupt handler code.
+ * Avoid this situation.
+ */
+ if (tail_prev) {
+ sfb->num_sdbt--;
+ free_page((unsigned long) new);
+ tail = tail_prev;
+ }
break;
+ }
sfb->num_sdb++;
tail++;
+ tail_prev = new = NULL; /* Allocated at least one SBD */
}
/* Link sampling buffer to its origin */
@@ -1248,18 +1261,28 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
*/
if (flush_all && done)
break;
-
- /* If an event overflow happened, discard samples by
- * processing any remaining sample-data-blocks.
- */
- if (event_overflow)
- flush_all = 1;
}
/* Account sample overflows in the event hardware structure */
if (sampl_overflow)
OVERFLOW_REG(hwc) = DIV_ROUND_UP(OVERFLOW_REG(hwc) +
sampl_overflow, 1 + num_sdb);
+
+ /* Perf_event_overflow() and perf_event_account_interrupt() limit
+ * the interrupt rate to an upper limit. Roughly 1000 samples per
+ * task tick.
+ * Hitting this limit results in a large number
+ * of throttled REF_REPORT_THROTTLE entries and the samples
+ * are dropped.
+ * Slightly increase the interval to avoid hitting this limit.
+ */
+ if (event_overflow) {
+ SAMPL_RATE(hwc) += DIV_ROUND_UP(SAMPL_RATE(hwc), 10);
+ debug_sprintf_event(sfdbg, 1, "%s: rate adjustment %ld\n",
+ __func__,
+ DIV_ROUND_UP(SAMPL_RATE(hwc), 10));
+ }
+
if (sampl_overflow || event_overflow)
debug_sprintf_event(sfdbg, 4, "hw_perf_event_update: "
"overflow stats: sample=%llu event=%llu\n",
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index df2413f..ecd2471 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -715,39 +715,67 @@ static void __ref smp_get_core_info(struct sclp_core_info *info, int early)
static int smp_add_present_cpu(int cpu);
-static int __smp_rescan_cpus(struct sclp_core_info *info, int sysfs_add)
+static int smp_add_core(struct sclp_core_entry *core, cpumask_t *avail,
+ bool configured, bool early)
{
struct pcpu *pcpu;
- cpumask_t avail;
- int cpu, nr, i, j;
+ int cpu, nr, i;
u16 address;
nr = 0;
- cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
- cpu = cpumask_first(&avail);
- for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) {
- if (sclp.has_core_type && info->core[i].type != boot_core_type)
+ if (sclp.has_core_type && core->type != boot_core_type)
+ return nr;
+ cpu = cpumask_first(avail);
+ address = core->core_id << smp_cpu_mt_shift;
+ for (i = 0; (i <= smp_cpu_mtid) && (cpu < nr_cpu_ids); i++) {
+ if (pcpu_find_address(cpu_present_mask, address + i))
continue;
- address = info->core[i].core_id << smp_cpu_mt_shift;
- for (j = 0; j <= smp_cpu_mtid; j++) {
- if (pcpu_find_address(cpu_present_mask, address + j))
- continue;
- pcpu = pcpu_devices + cpu;
- pcpu->address = address + j;
- pcpu->state =
- (cpu >= info->configured*(smp_cpu_mtid + 1)) ?
- CPU_STATE_STANDBY : CPU_STATE_CONFIGURED;
- smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
- set_cpu_present(cpu, true);
- if (sysfs_add && smp_add_present_cpu(cpu) != 0)
- set_cpu_present(cpu, false);
- else
- nr++;
- cpu = cpumask_next(cpu, &avail);
- if (cpu >= nr_cpu_ids)
+ pcpu = pcpu_devices + cpu;
+ pcpu->address = address + i;
+ if (configured)
+ pcpu->state = CPU_STATE_CONFIGURED;
+ else
+ pcpu->state = CPU_STATE_STANDBY;
+ smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+ set_cpu_present(cpu, true);
+ if (!early && smp_add_present_cpu(cpu) != 0)
+ set_cpu_present(cpu, false);
+ else
+ nr++;
+ cpumask_clear_cpu(cpu, avail);
+ cpu = cpumask_next(cpu, avail);
+ }
+ return nr;
+}
+
+static int __smp_rescan_cpus(struct sclp_core_info *info, bool early)
+{
+ struct sclp_core_entry *core;
+ cpumask_t avail;
+ bool configured;
+ u16 core_id;
+ int nr, i;
+
+ nr = 0;
+ cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
+ /*
+ * Add IPL core first (which got logical CPU number 0) to make sure
+ * that all SMT threads get subsequent logical CPU numbers.
+ */
+ if (early) {
+ core_id = pcpu_devices[0].address >> smp_cpu_mt_shift;
+ for (i = 0; i < info->configured; i++) {
+ core = &info->core[i];
+ if (core->core_id == core_id) {
+ nr += smp_add_core(core, &avail, true, early);
break;
+ }
}
}
+ for (i = 0; i < info->combined; i++) {
+ configured = i < info->configured;
+ nr += smp_add_core(&info->core[i], &avail, configured, early);
+ }
return nr;
}
@@ -793,7 +821,7 @@ void __init smp_detect_cpus(void)
/* Add CPUs present at boot */
get_online_cpus();
- __smp_rescan_cpus(info, 0);
+ __smp_rescan_cpus(info, true);
put_online_cpus();
memblock_free_early((unsigned long)info, sizeof(*info));
}
@@ -1145,7 +1173,7 @@ int __ref smp_rescan_cpus(void)
smp_get_core_info(info, 0);
get_online_cpus();
mutex_lock(&smp_cpu_state_mutex);
- nr = __smp_rescan_cpus(info, 1);
+ nr = __smp_rescan_cpus(info, false);
mutex_unlock(&smp_cpu_state_mutex);
put_online_cpus();
kfree(info);
diff --git a/arch/s390/purgatory/Makefile b/arch/s390/purgatory/Makefile
index ce6a3f7..fdccb76 100644
--- a/arch/s390/purgatory/Makefile
+++ b/arch/s390/purgatory/Makefile
@@ -13,8 +13,10 @@
$(obj)/mem.o: $(srctree)/arch/s390/lib/mem.S FORCE
$(call if_changed_rule,as_o_S)
-$(obj)/string.o: $(srctree)/arch/s390/lib/string.c FORCE
- $(call if_changed_rule,cc_o_c)
+KCOV_INSTRUMENT := n
+GCOV_PROFILE := n
+UBSAN_SANITIZE := n
+KASAN_SANITIZE := n
LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -nostdlib
LDFLAGS_purgatory.ro += -z nodefaultlib
diff --git a/arch/s390/purgatory/string.c b/arch/s390/purgatory/string.c
new file mode 100644
index 0000000..c98c22a
--- /dev/null
+++ b/arch/s390/purgatory/string.c
@@ -0,0 +1,3 @@
+// SPDX-License-Identifier: GPL-2.0
+#define __HAVE_ARCH_MEMCMP /* arch function */
+#include "../lib/string.c"
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7734.h b/arch/sh/include/cpu-sh4/cpu/sh7734.h
index 96f0246..82b6320 100644
--- a/arch/sh/include/cpu-sh4/cpu/sh7734.h
+++ b/arch/sh/include/cpu-sh4/cpu/sh7734.h
@@ -134,7 +134,7 @@ enum {
GPIO_FN_EX_WAIT1, GPIO_FN_SD1_DAT0_A, GPIO_FN_DREQ2, GPIO_FN_CAN1_TX_C,
GPIO_FN_ET0_LINK_C, GPIO_FN_ET0_ETXD5_A,
GPIO_FN_EX_WAIT0, GPIO_FN_TCLK1_B,
- GPIO_FN_RD_WR, GPIO_FN_TCLK0,
+ GPIO_FN_RD_WR, GPIO_FN_TCLK0, GPIO_FN_CAN_CLK_B, GPIO_FN_ET0_ETXD4,
GPIO_FN_EX_CS5, GPIO_FN_SD1_CMD_A, GPIO_FN_ATADIR, GPIO_FN_QSSL_B,
GPIO_FN_ET0_ETXD3_A,
GPIO_FN_EX_CS4, GPIO_FN_SD1_WP_A, GPIO_FN_ATAWR, GPIO_FN_QMI_QIO1_B,
diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig
index e2b132a..0d86eadb 100644
--- a/arch/x86/configs/x86_64_cuttlefish_defconfig
+++ b/arch/x86/configs/x86_64_cuttlefish_defconfig
@@ -80,7 +80,6 @@
CONFIG_BINFMT_MISC=y
CONFIG_KSM=y
CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
-CONFIG_TRANSPARENT_HUGEPAGE=y
CONFIG_ZSMALLOC=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index c9625bf..4293894 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -375,7 +375,7 @@ int x86_add_exclusive(unsigned int what)
* LBR and BTS are still mutually exclusive.
*/
if (x86_pmu.lbr_pt_coexist && what == x86_lbr_exclusive_pt)
- return 0;
+ goto out;
if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) {
mutex_lock(&pmc_reserve_mutex);
@@ -387,6 +387,7 @@ int x86_add_exclusive(unsigned int what)
mutex_unlock(&pmc_reserve_mutex);
}
+out:
atomic_inc(&active_events);
return 0;
@@ -397,11 +398,15 @@ int x86_add_exclusive(unsigned int what)
void x86_del_exclusive(unsigned int what)
{
+ atomic_dec(&active_events);
+
+ /*
+ * See the comment in x86_add_exclusive().
+ */
if (x86_pmu.lbr_pt_coexist && what == x86_lbr_exclusive_pt)
return;
atomic_dec(&x86_pmu.lbr_exclusive[what]);
- atomic_dec(&active_events);
}
int x86_setup_perfctr(struct perf_event *event)
diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c
index 7139f6b..510f946 100644
--- a/arch/x86/events/intel/bts.c
+++ b/arch/x86/events/intel/bts.c
@@ -71,9 +71,17 @@ struct bts_buffer {
static struct pmu bts_pmu;
+static int buf_nr_pages(struct page *page)
+{
+ if (!PagePrivate(page))
+ return 1;
+
+ return 1 << page_private(page);
+}
+
static size_t buf_size(struct page *page)
{
- return 1 << (PAGE_SHIFT + page_private(page));
+ return buf_nr_pages(page) * PAGE_SIZE;
}
static void *
@@ -91,9 +99,7 @@ bts_buffer_setup_aux(struct perf_event *event, void **pages,
/* count all the high order buffers */
for (pg = 0, nbuf = 0; pg < nr_pages;) {
page = virt_to_page(pages[pg]);
- if (WARN_ON_ONCE(!PagePrivate(page) && nr_pages > 1))
- return NULL;
- pg += 1 << page_private(page);
+ pg += buf_nr_pages(page);
nbuf++;
}
@@ -117,7 +123,7 @@ bts_buffer_setup_aux(struct perf_event *event, void **pages,
unsigned int __nr_pages;
page = virt_to_page(pages[pg]);
- __nr_pages = PagePrivate(page) ? 1 << page_private(page) : 1;
+ __nr_pages = buf_nr_pages(page);
buf->buf[nbuf].page = page;
buf->buf[nbuf].offset = offset;
buf->buf[nbuf].displacement = (pad ? BTS_RECORD_SIZE - pad : 0);
diff --git a/arch/x86/include/asm/crash.h b/arch/x86/include/asm/crash.h
index a7adb2bfb..6b8ad6f 100644
--- a/arch/x86/include/asm/crash.h
+++ b/arch/x86/include/asm/crash.h
@@ -2,6 +2,8 @@
#ifndef _ASM_X86_CRASH_H
#define _ASM_X86_CRASH_H
+struct kimage;
+
int crash_load_segments(struct kimage *image);
int crash_copy_backup_region(struct kimage *image);
int crash_setup_memmap_entries(struct kimage *image,
diff --git a/arch/x86/include/asm/syscall_wrapper.h b/arch/x86/include/asm/syscall_wrapper.h
index 7eb936b..74053d6 100644
--- a/arch/x86/include/asm/syscall_wrapper.h
+++ b/arch/x86/include/asm/syscall_wrapper.h
@@ -196,10 +196,10 @@ struct pt_regs;
* macros to work correctly.
*/
#ifndef SYSCALL_DEFINE0
-#define SYSCALL_DEFINE0(sname) \
- SYSCALL_METADATA(_##sname, 0); \
+#define SYSCALL_DEFINE0(sname) \
+ SYSCALL_METADATA(_##sname, 0); \
asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused);\
- ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO); \
+ ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO); \
asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused)
#endif
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index ab22ede..fa3b85b 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1724,9 +1724,10 @@ static bool io_apic_level_ack_pending(struct mp_chip_data *data)
static inline bool ioapic_irqd_mask(struct irq_data *data)
{
- /* If we are moving the irq we need to mask it */
+ /* If we are moving the IRQ we need to mask it */
if (unlikely(irqd_is_setaffinity_pending(data))) {
- mask_ioapic_irq(data);
+ if (!irqd_irq_masked(data))
+ mask_ioapic_irq(data);
return true;
}
return false;
@@ -1763,7 +1764,9 @@ static inline void ioapic_irqd_unmask(struct irq_data *data, bool masked)
*/
if (!io_apic_level_ack_pending(data->chip_data))
irq_move_masked_irq(data);
- unmask_ioapic_irq(data);
+ /* If the IRQ is masked in the core, leave it: */
+ if (!irqd_irq_masked(data))
+ unmask_ioapic_irq(data);
}
}
#else
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 87ed846..1f69b12 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -812,8 +812,8 @@ static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
if (quirk_no_way_out)
quirk_no_way_out(i, m, regs);
+ m->bank = i;
if (mce_severity(m, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) {
- m->bank = i;
mce_read_aux(m, i);
*msg = tmp;
return 1;
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 5bdfe52..da0b696 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -228,10 +228,10 @@ static void smca_configure(unsigned int bank, unsigned int cpu)
}
/* Return early if this bank was already initialized. */
- if (smca_banks[bank].hwid)
+ if (smca_banks[bank].hwid && smca_banks[bank].hwid->hwid_mcatype != 0)
return;
- if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_IPID(bank), &low, &high)) {
+ if (rdmsr_safe(MSR_AMD64_SMCA_MCx_IPID(bank), &low, &high)) {
pr_warn("Failed to read MCA_IPID for bank %d\n", bank);
return;
}
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index ee229ce..ec6a07b 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -185,7 +185,7 @@ static void therm_throt_process(bool new_event, int event, int level)
/* if we just entered the thermal event */
if (new_event) {
if (event == THERMAL_THROTTLING_EVENT)
- pr_crit("CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n",
+ pr_warn("CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n",
this_cpu,
level == CORE_LEVEL ? "Core" : "Package",
state->count);
diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt
index e0b8593..0a0e911 100644
--- a/arch/x86/lib/x86-opcode-map.txt
+++ b/arch/x86/lib/x86-opcode-map.txt
@@ -333,7 +333,7 @@
06: CLTS
07: SYSRET (o64)
08: INVD
-09: WBINVD
+09: WBINVD | WBNOINVD (F3)
0a:
0b: UD2 (1B)
0c:
@@ -364,7 +364,7 @@
# a ModR/M byte.
1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev
1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv
-1c:
+1c: Grp20 (1A),(1C)
1d:
1e:
1f: NOP Ev
@@ -792,6 +792,8 @@
f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v)
f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v)
f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v)
+f8: MOVDIR64B Gv,Mdqq (66) | ENQCMD Gv,Mdqq (F2) | ENQCMDS Gv,Mdqq (F3)
+f9: MOVDIRI My,Gy
EndTable
Table: 3-byte opcode 2 (0x0f 0x3a)
@@ -943,9 +945,9 @@
EndTable
GrpTable: Grp7
-0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
-1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B)
-2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B)
+0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) | PCONFIG (101),(11B) | ENCLV (000),(11B)
+1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) | ENCLS (111),(11B)
+2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) | ENCLU (111),(11B)
3: LIDT Ms
4: SMSW Mw/Rv
5: rdpkru (110),(11B) | wrpkru (111),(11B)
@@ -1020,7 +1022,7 @@
3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B)
4: XSAVE | ptwrite Ey (F3),(11B)
5: XRSTOR | lfence (11B)
-6: XSAVEOPT | clwb (66) | mfence (11B)
+6: XSAVEOPT | clwb (66) | mfence (11B) | TPAUSE Rd (66),(11B) | UMONITOR Rv (F3),(11B) | UMWAIT Rd (F2),(11B)
7: clflush | clflushopt (66) | sfence (11B)
EndTable
@@ -1051,6 +1053,10 @@
6: vscatterpf1qps/d Wx (66),(ev)
EndTable
+GrpTable: Grp20
+0: cldemote Mb
+EndTable
+
# AMD's Prefetch Group
GrpTable: GrpP
0: PREFETCH
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index 619101a..bf52106 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -660,8 +660,8 @@ void __native_set_fixmap(enum fixed_addresses idx, pte_t pte)
fixmaps_set++;
}
-void native_set_fixmap(unsigned /* enum fixed_addresses */ idx, phys_addr_t phys,
- pgprot_t flags)
+void native_set_fixmap(unsigned /* enum fixed_addresses */ idx,
+ phys_addr_t phys, pgprot_t flags)
{
/* Sanitize 'prot' against any unsupported bits: */
pgprot_val(flags) &= __default_kernel_pte_mask;
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 844d31c..c9873c9 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -259,10 +259,6 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
return;
}
- /* No need to reserve regions that will never be freed. */
- if (md.attribute & EFI_MEMORY_RUNTIME)
- return;
-
size += addr % EFI_PAGE_SIZE;
size = round_up(size, EFI_PAGE_SIZE);
addr = round_down(addr, EFI_PAGE_SIZE);
@@ -292,6 +288,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
early_memunmap(new, new_size);
efi_memmap_install(new_phys, num_entries);
+ e820__range_update(addr, size, E820_TYPE_RAM, E820_TYPE_RESERVED);
+ e820__update_table(e820_table);
}
/*
diff --git a/block/blk-map.c b/block/blk-map.c
index db9373b..9d8627a 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -145,7 +145,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
return 0;
unmap_rq:
- __blk_rq_unmap_user(bio);
+ blk_rq_unmap_user(bio);
fail:
rq->bio = NULL;
return ret;
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 6ca015f..6490b27 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -6,6 +6,7 @@
#include <linux/compat.h>
#include <linux/elevator.h>
#include <linux/hdreg.h>
+#include <linux/pr.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/types.h>
@@ -354,6 +355,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
* but we call blkdev_ioctl, which gets the lock for us
*/
case BLKRRPART:
+ case BLKREPORTZONE:
+ case BLKRESETZONE:
return blkdev_ioctl(bdev, mode, cmd,
(unsigned long)compat_ptr(arg));
case BLKBSZSET_32:
@@ -401,6 +404,14 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case BLKTRACETEARDOWN: /* compatible */
ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
return ret;
+ case IOC_PR_REGISTER:
+ case IOC_PR_RESERVE:
+ case IOC_PR_RELEASE:
+ case IOC_PR_PREEMPT:
+ case IOC_PR_PREEMPT_ABORT:
+ case IOC_PR_CLEAR:
+ return blkdev_ioctl(bdev, mode, cmd,
+ (unsigned long)compat_ptr(arg));
default:
if (disk->fops->compat_ioctl)
ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index a19ff39..870eb5c 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -91,6 +91,17 @@ static const struct dmi_system_id lid_blacklst[] = {
DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"),
},
},
+ {
+ /*
+ * Medion Akoya E2215T, notification of the LID device only
+ * happens on close, not on open and _LID always returns closed.
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "E2215T MD60198"),
+ },
+ .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
+ },
{}
};
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 41324f0..f8150c7 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -816,14 +816,14 @@ static ssize_t counter_set(struct kobject *kobj,
* interface:
* echo unmask > /sys/firmware/acpi/interrupts/gpe00
*/
-#define ACPI_MASKABLE_GPE_MAX 0xFF
+#define ACPI_MASKABLE_GPE_MAX 0x100
static DECLARE_BITMAP(acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) __initdata;
static int __init acpi_gpe_set_masked_gpes(char *val)
{
u8 gpe;
- if (kstrtou8(val, 0, &gpe) || gpe > ACPI_MASKABLE_GPE_MAX)
+ if (kstrtou8(val, 0, &gpe))
return -EINVAL;
set_bit(gpe, acpi_masked_gpes_map);
@@ -835,7 +835,7 @@ void __init acpi_gpe_apply_masked_gpes(void)
{
acpi_handle handle;
acpi_status status;
- u8 gpe;
+ u16 gpe;
for_each_set_bit(gpe, acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) {
status = acpi_get_gpe_device(gpe, &handle);
diff --git a/drivers/ata/ahci_brcm.c b/drivers/ata/ahci_brcm.c
index f3d55777..0192cab 100644
--- a/drivers/ata/ahci_brcm.c
+++ b/drivers/ata/ahci_brcm.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <linux/string.h>
#include "ahci.h"
@@ -84,8 +85,7 @@ enum brcm_ahci_version {
};
enum brcm_ahci_quirks {
- BRCM_AHCI_QUIRK_NO_NCQ = BIT(0),
- BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(1),
+ BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(0),
};
struct brcm_ahci_priv {
@@ -94,6 +94,7 @@ struct brcm_ahci_priv {
u32 port_mask;
u32 quirks;
enum brcm_ahci_version version;
+ struct reset_control *rcdev;
};
static inline u32 brcm_sata_readreg(void __iomem *addr)
@@ -220,19 +221,12 @@ static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv)
brcm_sata_phy_disable(priv, i);
}
-static u32 brcm_ahci_get_portmask(struct platform_device *pdev,
+static u32 brcm_ahci_get_portmask(struct ahci_host_priv *hpriv,
struct brcm_ahci_priv *priv)
{
- void __iomem *ahci;
- struct resource *res;
u32 impl;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci");
- ahci = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ahci))
- return 0;
-
- impl = readl(ahci + HOST_PORTS_IMPL);
+ impl = readl(hpriv->mmio + HOST_PORTS_IMPL);
if (fls(impl) > SATA_TOP_MAX_PHYS)
dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n",
@@ -240,9 +234,6 @@ static u32 brcm_ahci_get_portmask(struct platform_device *pdev,
else if (!impl)
dev_info(priv->dev, "no ports found\n");
- devm_iounmap(&pdev->dev, ahci);
- devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
-
return impl;
}
@@ -292,6 +283,13 @@ static unsigned int brcm_ahci_read_id(struct ata_device *dev,
/* Perform the SATA PHY reset sequence */
brcm_sata_phy_disable(priv, ap->port_no);
+ /* Reset the SATA clock */
+ ahci_platform_disable_clks(hpriv);
+ msleep(10);
+
+ ahci_platform_enable_clks(hpriv);
+ msleep(10);
+
/* Bring the PHY back on */
brcm_sata_phy_enable(priv, ap->port_no);
@@ -354,11 +352,10 @@ static int brcm_ahci_suspend(struct device *dev)
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
struct brcm_ahci_priv *priv = hpriv->plat_data;
- int ret;
- ret = ahci_platform_suspend(dev);
brcm_sata_phys_disable(priv);
- return ret;
+
+ return ahci_platform_suspend(dev);
}
static int brcm_ahci_resume(struct device *dev)
@@ -366,11 +363,44 @@ static int brcm_ahci_resume(struct device *dev)
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
struct brcm_ahci_priv *priv = hpriv->plat_data;
+ int ret;
+
+ /* Make sure clocks are turned on before re-configuration */
+ ret = ahci_platform_enable_clks(hpriv);
+ if (ret)
+ return ret;
brcm_sata_init(priv);
brcm_sata_phys_enable(priv);
brcm_sata_alpm_init(hpriv);
- return ahci_platform_resume(dev);
+
+ /* Since we had to enable clocks earlier on, we cannot use
+ * ahci_platform_resume() as-is since a second call to
+ * ahci_platform_enable_resources() would bump up the resources
+ * (regulators, clocks, PHYs) count artificially so we copy the part
+ * after ahci_platform_enable_resources().
+ */
+ ret = ahci_platform_enable_phys(hpriv);
+ if (ret)
+ goto out_disable_phys;
+
+ ret = ahci_platform_resume_host(dev);
+ if (ret)
+ goto out_disable_platform_phys;
+
+ /* We resumed so update PM runtime state */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+
+out_disable_platform_phys:
+ ahci_platform_disable_phys(hpriv);
+out_disable_phys:
+ brcm_sata_phys_disable(priv);
+ ahci_platform_disable_clks(hpriv);
+ return ret;
}
#endif
@@ -411,44 +441,76 @@ static int brcm_ahci_probe(struct platform_device *pdev)
if (IS_ERR(priv->top_ctrl))
return PTR_ERR(priv->top_ctrl);
- if ((priv->version == BRCM_SATA_BCM7425) ||
- (priv->version == BRCM_SATA_NSP)) {
- priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ;
- priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
- }
-
- brcm_sata_init(priv);
-
- priv->port_mask = brcm_ahci_get_portmask(pdev, priv);
- if (!priv->port_mask)
- return -ENODEV;
-
- brcm_sata_phys_enable(priv);
+ /* Reset is optional depending on platform */
+ priv->rcdev = devm_reset_control_get(&pdev->dev, "ahci");
+ if (!IS_ERR_OR_NULL(priv->rcdev))
+ reset_control_deassert(priv->rcdev);
hpriv = ahci_platform_get_resources(pdev, 0);
- if (IS_ERR(hpriv))
- return PTR_ERR(hpriv);
+ if (IS_ERR(hpriv)) {
+ ret = PTR_ERR(hpriv);
+ goto out_reset;
+ }
+
hpriv->plat_data = priv;
- hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP;
+ hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP | AHCI_HFLAG_NO_WRITE_TO_RO;
+
+ switch (priv->version) {
+ case BRCM_SATA_BCM7425:
+ hpriv->flags |= AHCI_HFLAG_DELAY_ENGINE;
+ /* fall through */
+ case BRCM_SATA_NSP:
+ hpriv->flags |= AHCI_HFLAG_NO_NCQ;
+ priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
+ break;
+ default:
+ break;
+ }
+
+ ret = ahci_platform_enable_clks(hpriv);
+ if (ret)
+ goto out_reset;
+
+ /* Must be first so as to configure endianness including that
+ * of the standard AHCI register space.
+ */
+ brcm_sata_init(priv);
+
+ /* Initializes priv->port_mask which is used below */
+ priv->port_mask = brcm_ahci_get_portmask(hpriv, priv);
+ if (!priv->port_mask) {
+ ret = -ENODEV;
+ goto out_disable_clks;
+ }
+
+ /* Must be done before ahci_platform_enable_phys() */
+ brcm_sata_phys_enable(priv);
brcm_sata_alpm_init(hpriv);
- ret = ahci_platform_enable_resources(hpriv);
+ ret = ahci_platform_enable_phys(hpriv);
if (ret)
- return ret;
-
- if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ)
- hpriv->flags |= AHCI_HFLAG_NO_NCQ;
- hpriv->flags |= AHCI_HFLAG_NO_WRITE_TO_RO;
+ goto out_disable_phys;
ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
&ahci_platform_sht);
if (ret)
- return ret;
+ goto out_disable_platform_phys;
dev_info(dev, "Broadcom AHCI SATA3 registered\n");
return 0;
+
+out_disable_platform_phys:
+ ahci_platform_disable_phys(hpriv);
+out_disable_phys:
+ brcm_sata_phys_disable(priv);
+out_disable_clks:
+ ahci_platform_disable_clks(hpriv);
+out_reset:
+ if (!IS_ERR_OR_NULL(priv->rcdev))
+ reset_control_assert(priv->rcdev);
+ return ret;
}
static int brcm_ahci_remove(struct platform_device *pdev)
@@ -458,12 +520,12 @@ static int brcm_ahci_remove(struct platform_device *pdev)
struct brcm_ahci_priv *priv = hpriv->plat_data;
int ret;
+ brcm_sata_phys_disable(priv);
+
ret = ata_platform_remove_one(pdev);
if (ret)
return ret;
- brcm_sata_phys_disable(priv);
-
return 0;
}
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 5bece97..522b543 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -47,7 +47,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_ops);
* RETURNS:
* 0 on success otherwise a negative error code
*/
-static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
+int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
{
int rc, i;
@@ -72,6 +72,7 @@ static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
}
return rc;
}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_phys);
/**
* ahci_platform_disable_phys - Disable PHYs
@@ -79,7 +80,7 @@ static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
*
* This function disables all PHYs found in hpriv->phys.
*/
-static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
+void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
{
int i;
@@ -88,6 +89,7 @@ static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
phy_exit(hpriv->phys[i]);
}
}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
/**
* ahci_platform_enable_clks - Enable platform clocks
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 133fed8..b45b6f7 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5344,6 +5344,30 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
}
/**
+ * ata_qc_get_active - get bitmask of active qcs
+ * @ap: port in question
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Bitmask of active qcs
+ */
+u64 ata_qc_get_active(struct ata_port *ap)
+{
+ u64 qc_active = ap->qc_active;
+
+ /* ATA_TAG_INTERNAL is sent to hw as tag 0 */
+ if (qc_active & (1ULL << ATA_TAG_INTERNAL)) {
+ qc_active |= (1 << 0);
+ qc_active &= ~(1ULL << ATA_TAG_INTERNAL);
+ }
+
+ return qc_active;
+}
+EXPORT_SYMBOL_GPL(ata_qc_get_active);
+
+/**
* ata_qc_complete_multiple - Complete multiple qcs successfully
* @ap: port in question
* @qc_active: new qc_active mask
@@ -6726,6 +6750,9 @@ void ata_host_detach(struct ata_host *host)
{
int i;
+ /* Ensure ata_port probe has completed */
+ async_synchronize_full();
+
for (i = 0; i < host->n_ports; i++)
ata_port_detach(host->ports[i]);
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 4dc528b..ae52a45 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -1283,7 +1283,7 @@ static void sata_fsl_host_intr(struct ata_port *ap)
i, ioread32(hcr_base + CC),
ioread32(hcr_base + CA));
}
- ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
+ ata_qc_complete_multiple(ap, ata_qc_get_active(ap) ^ done_mask);
return;
} else if ((ap->qc_active & (1ULL << ATA_TAG_INTERNAL))) {
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 73ba8e1..ab2e9f6 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -2840,7 +2840,7 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
}
if (work_done) {
- ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
+ ata_qc_complete_multiple(ap, ata_qc_get_active(ap) ^ done_mask);
/* Update the software queue position index in hardware */
writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 72c9b92..761577d 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1000,7 +1000,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
check_commands = 0;
check_commands &= ~(1 << pos);
}
- ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
+ ata_qc_complete_multiple(ap, ata_qc_get_active(ap) ^ done_mask);
}
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 126c2c5..9cd231a 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -416,18 +416,20 @@ static int lo_read_transfer(struct loop_device *lo, struct request *rq,
return ret;
}
-static int lo_discard(struct loop_device *lo, struct request *rq, loff_t pos)
+static int lo_fallocate(struct loop_device *lo, struct request *rq, loff_t pos,
+ int mode)
{
/*
- * We use punch hole to reclaim the free space used by the
- * image a.k.a. discard. However we do not support discard if
- * encryption is enabled, because it may give an attacker
- * useful information.
+ * We use fallocate to manipulate the space mappings used by the image
+ * a.k.a. discard/zerorange. However we do not support this if
+ * encryption is enabled, because it may give an attacker useful
+ * information.
*/
struct file *file = lo->lo_backing_file;
- int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
int ret;
+ mode |= FALLOC_FL_KEEP_SIZE;
+
if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) {
ret = -EOPNOTSUPP;
goto out;
@@ -596,9 +598,17 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq)
switch (req_op(rq)) {
case REQ_OP_FLUSH:
return lo_req_flush(lo, rq);
- case REQ_OP_DISCARD:
case REQ_OP_WRITE_ZEROES:
- return lo_discard(lo, rq, pos);
+ /*
+ * If the caller doesn't want deallocation, call zeroout to
+ * write zeroes the range. Otherwise, punch them out.
+ */
+ return lo_fallocate(lo, rq, pos,
+ (rq->cmd_flags & REQ_NOUNMAP) ?
+ FALLOC_FL_ZERO_RANGE :
+ FALLOC_FL_PUNCH_HOLE);
+ case REQ_OP_DISCARD:
+ return lo_fallocate(lo, rq, pos, FALLOC_FL_PUNCH_HOLE);
case REQ_OP_WRITE:
if (lo->transfer)
return lo_write_transfer(lo, rq, pos);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 996b1ef..b9d321b 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -1247,10 +1247,10 @@ static int nbd_start_device_ioctl(struct nbd_device *nbd, struct block_device *b
mutex_unlock(&nbd->config_lock);
ret = wait_event_interruptible(config->recv_wq,
atomic_read(&config->recv_threads) == 0);
- if (ret) {
+ if (ret)
sock_shutdown(nbd);
- flush_workqueue(nbd->recv_workq);
- }
+ flush_workqueue(nbd->recv_workq);
+
mutex_lock(&nbd->config_lock);
nbd_bdev_reset(bdev);
/* user requested, ignore socket errors */
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index fd1e19f..3666afa 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -936,6 +936,8 @@ static int xen_blkbk_map(struct xen_blkif_ring *ring,
out_of_memory:
pr_alert("%s: out of memory\n", __func__);
put_free_pages(ring, pages_to_gnt, segs_to_map);
+ for (i = last_map; i < num; i++)
+ pages[i]->handle = BLKBACK_INVALID_HANDLE;
return -ENOMEM;
}
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index 55869b3..25c41ce 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -179,6 +179,15 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
blkif->domid = domid;
atomic_set(&blkif->refcnt, 1);
init_completion(&blkif->drain_complete);
+
+ /*
+ * Because freeing back to the cache may be deferred, it is not
+ * safe to unload the module (and hence destroy the cache) until
+ * this has completed. To prevent premature unloading, take an
+ * extra module reference here and release only when the object
+ * has been freed back to the cache.
+ */
+ __module_get(THIS_MODULE);
INIT_WORK(&blkif->free_work, xen_blkif_deferred_free);
return blkif;
@@ -328,6 +337,7 @@ static void xen_blkif_free(struct xen_blkif *blkif)
/* Make sure everything is drained before shutting down */
kmem_cache_free(xen_blkif_cachep, blkif);
+ module_put(THIS_MODULE);
}
int __init xen_blkif_interface_init(void)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 08936bf..1b0adf5 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -1138,7 +1138,7 @@ static int btusb_open(struct hci_dev *hdev)
if (data->setup_on_usb) {
err = data->setup_on_usb(hdev);
if (err < 0)
- return err;
+ goto setup_fail;
}
data->intf->needs_remote_wakeup = 1;
@@ -1170,6 +1170,7 @@ static int btusb_open(struct hci_dev *hdev)
failed:
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+setup_fail:
usb_autopm_put_interface(data->intf);
return err;
}
diff --git a/drivers/bus/mhi/controllers/mhi_arch_qcom.c b/drivers/bus/mhi/controllers/mhi_arch_qcom.c
index 8dafdd5..aa04fa4 100644
--- a/drivers/bus/mhi/controllers/mhi_arch_qcom.c
+++ b/drivers/bus/mhi/controllers/mhi_arch_qcom.c
@@ -728,9 +728,24 @@ int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl)
}
msm_pcie_l1ss_timeout_enable(pci_dev);
- mhi_cntrl->force_m3_done = true;
MHI_LOG("Exited\n");
return 0;
}
+
+int mhi_arch_link_lpm_disable(struct mhi_controller *mhi_cntrl)
+{
+ struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
+
+ return msm_pcie_prevent_l1(mhi_dev->pci_dev);
+}
+
+int mhi_arch_link_lpm_enable(struct mhi_controller *mhi_cntrl)
+{
+ struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
+
+ msm_pcie_allow_l1(mhi_dev->pci_dev);
+
+ return 0;
+}
diff --git a/drivers/bus/mhi/controllers/mhi_qcom.c b/drivers/bus/mhi/controllers/mhi_qcom.c
index 78959a9..1257338 100644
--- a/drivers/bus/mhi/controllers/mhi_qcom.c
+++ b/drivers/bus/mhi/controllers/mhi_qcom.c
@@ -71,9 +71,6 @@ void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl)
pm_runtime_dont_use_autosuspend(&pci_dev->dev);
pm_runtime_disable(&pci_dev->dev);
- /* reset counter for lpm state changes */
- mhi_dev->lpm_disable_depth = 0;
-
pci_free_irq_vectors(pci_dev);
kfree(mhi_cntrl->irq);
mhi_cntrl->irq = NULL;
@@ -448,89 +445,13 @@ static int mhi_link_status(struct mhi_controller *mhi_cntrl, void *priv)
/* disable PCIe L1 */
static int mhi_lpm_disable(struct mhi_controller *mhi_cntrl, void *priv)
{
- struct mhi_dev *mhi_dev = priv;
- struct pci_dev *pci_dev = mhi_dev->pci_dev;
- int lnkctl = pci_dev->pcie_cap + PCI_EXP_LNKCTL;
- u8 val;
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&mhi_dev->lpm_lock, flags);
-
- /* L1 is already disabled */
- if (mhi_dev->lpm_disable_depth) {
- mhi_dev->lpm_disable_depth++;
- goto lpm_disable_exit;
- }
-
- ret = pci_read_config_byte(pci_dev, lnkctl, &val);
- if (ret) {
- MHI_ERR("Error reading LNKCTL, ret:%d\n", ret);
- goto lpm_disable_exit;
- }
-
- /* L1 is not supported, do not increment lpm_disable_depth */
- if (unlikely(!(val & PCI_EXP_LNKCTL_ASPM_L1)))
- goto lpm_disable_exit;
-
- val &= ~PCI_EXP_LNKCTL_ASPM_L1;
- ret = pci_write_config_byte(pci_dev, lnkctl, val);
- if (ret) {
- MHI_ERR("Error writing LNKCTL to disable LPM, ret:%d\n", ret);
- goto lpm_disable_exit;
- }
-
- mhi_dev->lpm_disable_depth++;
-
-lpm_disable_exit:
- spin_unlock_irqrestore(&mhi_dev->lpm_lock, flags);
-
- return ret;
+ return mhi_arch_link_lpm_disable(mhi_cntrl);
}
/* enable PCIe L1 */
static int mhi_lpm_enable(struct mhi_controller *mhi_cntrl, void *priv)
{
- struct mhi_dev *mhi_dev = priv;
- struct pci_dev *pci_dev = mhi_dev->pci_dev;
- int lnkctl = pci_dev->pcie_cap + PCI_EXP_LNKCTL;
- u8 val;
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&mhi_dev->lpm_lock, flags);
-
- /*
- * Exit if L1 is not supported or is already disabled or
- * decrementing lpm_disable_depth still keeps it above 0
- */
- if (!mhi_dev->lpm_disable_depth)
- goto lpm_enable_exit;
-
- if (mhi_dev->lpm_disable_depth > 1) {
- mhi_dev->lpm_disable_depth--;
- goto lpm_enable_exit;
- }
-
- ret = pci_read_config_byte(pci_dev, lnkctl, &val);
- if (ret) {
- MHI_ERR("Error reading LNKCTL, ret:%d\n", ret);
- goto lpm_enable_exit;
- }
-
- val |= PCI_EXP_LNKCTL_ASPM_L1;
- ret = pci_write_config_byte(pci_dev, lnkctl, val);
- if (ret) {
- MHI_ERR("Error writing LNKCTL to enable LPM, ret:%d\n", ret);
- goto lpm_enable_exit;
- }
-
- mhi_dev->lpm_disable_depth = 0;
-
-lpm_enable_exit:
- spin_unlock_irqrestore(&mhi_dev->lpm_lock, flags);
-
- return ret;
+ return mhi_arch_link_lpm_enable(mhi_cntrl);
}
void mhi_qcom_store_hwinfo(struct mhi_controller *mhi_cntrl)
@@ -769,8 +690,6 @@ static struct mhi_controller *mhi_register_controller(struct pci_dev *pci_dev)
mhi_cntrl->iova_start = memblock_start_of_DRAM();
mhi_cntrl->iova_stop = memblock_end_of_DRAM();
- mhi_cntrl->need_force_m3 = true;
-
/* setup host support for SFR retreival */
if (of_property_read_bool(of_node, "mhi,sfr-support"))
mhi_cntrl->sfr_len = MHI_MAX_SFR_LEN;
@@ -811,7 +730,6 @@ static struct mhi_controller *mhi_register_controller(struct pci_dev *pci_dev)
}
mhi_dev->pci_dev = pci_dev;
- spin_lock_init(&mhi_dev->lpm_lock);
/* setup power management apis */
mhi_cntrl->status_cb = mhi_status_cb;
diff --git a/drivers/bus/mhi/controllers/mhi_qcom.h b/drivers/bus/mhi/controllers/mhi_qcom.h
index 1383bb0..e1d58a8 100644
--- a/drivers/bus/mhi/controllers/mhi_qcom.h
+++ b/drivers/bus/mhi/controllers/mhi_qcom.h
@@ -57,10 +57,6 @@ struct mhi_dev {
/* hardware info */
u32 serial_num;
u32 oem_pk_hash[MHI_BHI_OEMPKHASH_SEG];
-
- unsigned int lpm_disable_depth;
- /* lock to toggle low power modes */
- spinlock_t lpm_lock;
};
void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl);
@@ -70,6 +66,8 @@ void mhi_reg_write_work(struct work_struct *w);
#ifdef CONFIG_ARCH_QCOM
+int mhi_arch_link_lpm_disable(struct mhi_controller *mhi_cntrl);
+int mhi_arch_link_lpm_enable(struct mhi_controller *mhi_cntrl);
void mhi_arch_mission_mode_enter(struct mhi_controller *mhi_cntrl);
int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl);
void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl);
@@ -101,6 +99,16 @@ static inline void mhi_arch_mission_mode_enter(struct mhi_controller *mhi_cntrl)
{
}
+static inline int mhi_arch_link_lpm_disable(struct mhi_controller *mhi_cntrl)
+{
+ return 0;
+}
+
+static inline int mhi_arch_link_lpm_enable(struct mhi_controller *mhi_cntrl)
+{
+ return 0;
+}
+
#endif
#endif /* _MHI_QCOM_ */
diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c
index 8707efc..20bb8f3 100644
--- a/drivers/bus/mhi/core/mhi_init.c
+++ b/drivers/bus/mhi/core/mhi_init.c
@@ -96,6 +96,57 @@ const char *to_mhi_pm_state_str(enum MHI_PM_STATE state)
return mhi_pm_state_str[index];
}
+static ssize_t time_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mhi_device *mhi_dev = to_mhi_device(dev);
+ struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
+ u64 t_host, t_device;
+ int ret;
+
+ ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device);
+ if (ret) {
+ MHI_ERR("Failed to obtain time, ret:%d\n", ret);
+ return ret;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (ticks)\n",
+ t_host, t_device);
+}
+static DEVICE_ATTR_RO(time);
+
+static ssize_t time_us_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mhi_device *mhi_dev = to_mhi_device(dev);
+ struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
+ u64 t_host, t_device;
+ int ret;
+
+ ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device);
+ if (ret) {
+ MHI_ERR("Failed to obtain time, ret:%d\n", ret);
+ return ret;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (us)\n",
+ LOCAL_TICKS_TO_US(t_host),
+ REMOTE_TICKS_TO_US(t_device));
+}
+static DEVICE_ATTR_RO(time_us);
+
+static struct attribute *mhi_tsync_attrs[] = {
+ &dev_attr_time.attr,
+ &dev_attr_time_us.attr,
+ NULL,
+};
+
+static const struct attribute_group mhi_tsync_group = {
+ .attrs = mhi_tsync_attrs,
+};
+
static ssize_t log_level_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -197,15 +248,36 @@ static const struct attribute_group mhi_sysfs_group = {
.attrs = mhi_sysfs_attrs,
};
-int mhi_create_sysfs(struct mhi_controller *mhi_cntrl)
+void mhi_create_sysfs(struct mhi_controller *mhi_cntrl)
{
- return sysfs_create_group(&mhi_cntrl->mhi_dev->dev.kobj,
- &mhi_sysfs_group);
+ sysfs_create_group(&mhi_cntrl->mhi_dev->dev.kobj, &mhi_sysfs_group);
+ if (mhi_cntrl->mhi_tsync)
+ sysfs_create_group(&mhi_cntrl->mhi_dev->dev.kobj,
+ &mhi_tsync_group);
}
void mhi_destroy_sysfs(struct mhi_controller *mhi_cntrl)
{
struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev;
+ struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync;
+ struct tsync_node *tsync, *tmp;
+
+ if (mhi_tsync) {
+ mutex_lock(&mhi_cntrl->tsync_mutex);
+ sysfs_remove_group(&mhi_cntrl->mhi_dev->dev.kobj,
+ &mhi_tsync_group);
+
+ spin_lock(&mhi_tsync->lock);
+ list_for_each_entry_safe(tsync, tmp, &mhi_tsync->head, node) {
+ list_del(&tsync->node);
+ kfree(tsync);
+ }
+ spin_unlock(&mhi_tsync->lock);
+
+ kfree(mhi_cntrl->mhi_tsync);
+ mhi_cntrl->mhi_tsync = NULL;
+ mutex_unlock(&mhi_cntrl->tsync_mutex);
+ }
sysfs_remove_group(&mhi_dev->dev.kobj, &mhi_sysfs_group);
@@ -234,6 +306,21 @@ static int mhi_alloc_aligned_ring(struct mhi_controller *mhi_cntrl,
return 0;
}
+/* MHI protocol require transfer ring to be aligned to ring length */
+static int mhi_alloc_aligned_ring_uncached(
+ struct mhi_controller *mhi_cntrl, struct mhi_ring *ring, u64 len)
+{
+ ring->alloc_size = len + (len - 1);
+ ring->pre_aligned = mhi_alloc_uncached(mhi_cntrl, ring->alloc_size,
+ &ring->dma_handle, GFP_KERNEL);
+ if (!ring->pre_aligned)
+ return -ENOMEM;
+
+ ring->iommu_base = (ring->dma_handle + (len - 1)) & ~(len - 1);
+ ring->base = ring->pre_aligned + (ring->iommu_base - ring->dma_handle);
+ return 0;
+}
+
void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl)
{
int i;
@@ -318,7 +405,11 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl)
continue;
ring = &mhi_event->ring;
- mhi_free_coherent(mhi_cntrl, ring->alloc_size,
+ if (mhi_event->force_uncached)
+ mhi_free_uncached(mhi_cntrl, ring->alloc_size,
+ ring->pre_aligned, ring->dma_handle);
+ else
+ mhi_free_coherent(mhi_cntrl, ring->alloc_size,
ring->pre_aligned, ring->dma_handle);
ring->base = NULL;
ring->iommu_base = 0;
@@ -352,6 +443,11 @@ static int mhi_init_debugfs_mhi_chan_open(struct inode *inode, struct file *fp)
return single_open(fp, mhi_debugfs_mhi_chan_show, inode->i_private);
}
+static int mhi_init_debugfs_mhi_vote_open(struct inode *inode, struct file *fp)
+{
+ return single_open(fp, mhi_debugfs_mhi_vote_show, inode->i_private);
+}
+
static const struct file_operations debugfs_state_ops = {
.open = mhi_init_debugfs_mhi_states_open,
.release = single_release,
@@ -370,6 +466,12 @@ static const struct file_operations debugfs_chan_ops = {
.read = seq_read,
};
+static const struct file_operations debugfs_vote_ops = {
+ .open = mhi_init_debugfs_mhi_vote_open,
+ .release = single_release,
+ .read = seq_read,
+};
+
DEFINE_DEBUGFS_ATTRIBUTE(debugfs_trigger_reset_fops, NULL,
mhi_debugfs_trigger_reset, "%llu\n");
@@ -395,6 +497,8 @@ void mhi_init_debugfs(struct mhi_controller *mhi_cntrl)
&debugfs_ev_ops);
debugfs_create_file_unsafe("chan", 0444, dentry, mhi_cntrl,
&debugfs_chan_ops);
+ debugfs_create_file_unsafe("vote", 0444, dentry, mhi_cntrl,
+ &debugfs_vote_ops);
debugfs_create_file_unsafe("reset", 0444, dentry, mhi_cntrl,
&debugfs_trigger_reset_fops);
mhi_cntrl->dentry = dentry;
@@ -474,7 +578,12 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
ring->el_size = sizeof(struct mhi_tre);
ring->len = ring->el_size * ring->elements;
- ret = mhi_alloc_aligned_ring(mhi_cntrl, ring, ring->len);
+ if (mhi_event->force_uncached)
+ ret = mhi_alloc_aligned_ring_uncached(mhi_cntrl, ring,
+ ring->len);
+ else
+ ret = mhi_alloc_aligned_ring(mhi_cntrl, ring,
+ ring->len);
if (ret)
goto error_alloc_er;
@@ -535,7 +644,11 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
if (mhi_event->offload_ev)
continue;
- mhi_free_coherent(mhi_cntrl, ring->alloc_size,
+ if (mhi_event->force_uncached)
+ mhi_free_uncached(mhi_cntrl, ring->alloc_size,
+ ring->pre_aligned, ring->dma_handle);
+ else
+ mhi_free_coherent(mhi_cntrl, ring->alloc_size,
ring->pre_aligned, ring->dma_handle);
}
mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->er_ctxt) *
@@ -569,42 +682,32 @@ static int mhi_get_er_index(struct mhi_controller *mhi_cntrl,
return -ENOENT;
}
-int mhi_init_timesync(struct mhi_controller *mhi_cntrl)
+static int mhi_init_timesync(struct mhi_controller *mhi_cntrl)
{
struct mhi_timesync *mhi_tsync;
- u32 time_offset, db_offset;
- int ret;
-
- read_lock_bh(&mhi_cntrl->pm_lock);
-
- if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
- ret = -EIO;
- goto exit_timesync;
- }
-
- ret = mhi_get_capability_offset(mhi_cntrl, TIMESYNC_CAP_ID,
- &time_offset);
- if (ret) {
- MHI_LOG("No timesync capability found\n");
- goto exit_timesync;
- }
-
- read_unlock_bh(&mhi_cntrl->pm_lock);
+ u32 time_offset, time_cfg_offset;
+ int ret, er_index;
if (!mhi_cntrl->time_get || !mhi_cntrl->lpm_disable ||
!mhi_cntrl->lpm_enable)
return -EINVAL;
+ ret = mhi_get_capability_offset(mhi_cntrl, TIMESYNC_CAP_ID,
+ &time_offset);
+ if (ret) {
+ MHI_LOG("No timesync capability found\n");
+ return ret;
+ }
+
mhi_cntrl->local_timer_freq = arch_timer_get_cntfrq();
- /* register method supported */
- mhi_tsync = kzalloc(sizeof(*mhi_tsync), GFP_KERNEL);
+ /* register method is supported */
+ mhi_tsync = kzalloc(sizeof(*mhi_tsync), GFP_ATOMIC);
if (!mhi_tsync)
return -ENOMEM;
spin_lock_init(&mhi_tsync->lock);
INIT_LIST_HEAD(&mhi_tsync->head);
- init_completion(&mhi_tsync->completion);
/* save time_offset for obtaining time */
MHI_LOG("TIME OFFS:0x%x\n", time_offset);
@@ -613,61 +716,20 @@ int mhi_init_timesync(struct mhi_controller *mhi_cntrl)
mhi_cntrl->mhi_tsync = mhi_tsync;
- ret = mhi_create_timesync_sysfs(mhi_cntrl);
- if (unlikely(ret)) {
- /* kernel method still work */
- MHI_ERR("Failed to create timesync sysfs nodes\n");
- }
-
- read_lock_bh(&mhi_cntrl->pm_lock);
-
- if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
- ret = -EIO;
- goto exit_timesync;
- }
-
- /* get DB offset if supported, else return */
- ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs,
- time_offset + TIMESYNC_DB_OFFSET, &db_offset);
- if (ret || !db_offset) {
- ret = 0;
- goto exit_timesync;
- }
-
- MHI_LOG("TIMESYNC_DB OFFS:0x%x\n", db_offset);
- mhi_tsync->db = mhi_cntrl->regs + db_offset;
-
- read_unlock_bh(&mhi_cntrl->pm_lock);
-
- /* get time-sync event ring configuration */
- ret = mhi_get_er_index(mhi_cntrl, MHI_ER_TSYNC_ELEMENT_TYPE);
- if (ret < 0) {
+ /* get timesync event ring configuration */
+ er_index = mhi_get_er_index(mhi_cntrl, MHI_ER_TSYNC_ELEMENT_TYPE);
+ if (er_index < 0) {
MHI_LOG("Could not find timesync event ring\n");
- return ret;
+ return er_index;
}
- mhi_tsync->er_index = ret;
+ time_cfg_offset = time_offset + TIMESYNC_CFG_OFFSET;
- ret = mhi_send_cmd(mhi_cntrl, NULL, MHI_CMD_TIMSYNC_CFG);
- if (ret) {
- MHI_ERR("Failed to send time sync cfg cmd\n");
- return ret;
- }
-
- ret = wait_for_completion_timeout(&mhi_tsync->completion,
- msecs_to_jiffies(mhi_cntrl->timeout_ms));
-
- if (!ret || mhi_tsync->ccs != MHI_EV_CC_SUCCESS) {
- MHI_ERR("Failed to get time cfg cmd completion\n");
- return -EIO;
- }
+ /* advertise host support */
+ mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->regs, time_cfg_offset,
+ MHI_TIMESYNC_DB_SETUP(er_index));
return 0;
-
-exit_timesync:
- read_unlock_bh(&mhi_cntrl->pm_lock);
-
- return ret;
}
int mhi_init_sfr(struct mhi_controller *mhi_cntrl)
@@ -832,7 +894,8 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->wake_db, 0, 0);
mhi_cntrl->wake_set = false;
- /* setup bw scale db */
+ /* setup special purpose doorbells (timesync, bw scale) */
+ mhi_cntrl->tsync_db = base + val + (8 * MHI_TIMESYNC_CHAN_DB);
mhi_cntrl->bw_scale_db = base + val + (8 * MHI_BW_SCALE_CHAN_DB);
/* setup channel db addresses */
@@ -865,8 +928,9 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
reg_info[i].mask, reg_info[i].shift,
reg_info[i].val);
- /* setup bandwidth scaling features */
+ /* setup special purpose features such as timesync or bw scaling */
mhi_init_bw_scale(mhi_cntrl);
+ mhi_init_timesync(mhi_cntrl);
return 0;
}
@@ -1028,6 +1092,10 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl,
continue;
mhi_event->er_index = i++;
+
+ mhi_event->force_uncached = of_property_read_bool(child,
+ "mhi,force-uncached");
+
ret = of_property_read_u32(child, "mhi,num-elements",
(u32 *)&mhi_event->ring.elements);
if (ret)
@@ -1474,6 +1542,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl)
}
mhi_dev->dev_type = MHI_CONTROLLER_TYPE;
+ mhi_dev->chan_name = mhi_cntrl->name;
mhi_dev->mhi_cntrl = mhi_cntrl;
dev_set_name(&mhi_dev->dev, "%04x_%02u.%02u.%02u", mhi_dev->dev_id,
mhi_dev->domain, mhi_dev->bus, mhi_dev->slot);
@@ -1836,10 +1905,6 @@ static int mhi_driver_remove(struct device *dev)
mutex_unlock(&mhi_chan->mutex);
}
-
- if (mhi_cntrl->tsync_dev == mhi_dev)
- mhi_cntrl->tsync_dev = NULL;
-
/* relinquish any pending votes for device */
while (atomic_read(&mhi_dev->dev_vote))
mhi_device_put(mhi_dev, MHI_VOTE_DEVICE);
diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h
index 7321b0f..d45bb85 100644
--- a/drivers/bus/mhi/core/mhi_internal.h
+++ b/drivers/bus/mhi/core/mhi_internal.h
@@ -141,14 +141,14 @@ extern struct bus_type mhi_bus_type;
#define CAP_NEXT_CAP_SHIFT (12)
/* MHI Timesync offsets */
-#define TIMESYNC_CFG_OFFSET (0x00)
-#define TIMESYNC_CFG_CAPID_MASK (CAP_CAPID_MASK)
-#define TIMESYNC_CFG_CAPID_SHIFT (CAP_CAPID_SHIFT)
-#define TIMESYNC_CFG_NEXT_OFF_MASK (CAP_NEXT_CAP_MASK)
-#define TIMESYNC_CFG_NEXT_OFF_SHIFT (CAP_NEXT_CAP_SHIFT)
-#define TIMESYNC_CFG_NUMCMD_MASK (0xFF)
-#define TIMESYNC_CFG_NUMCMD_SHIFT (0)
-#define TIMESYNC_DB_OFFSET (0x4)
+#define TIMESYNC_CFG_OFFSET (0x04)
+#define TIMESYNC_CFG_ENABLED_MASK (0x80000000)
+#define TIMESYNC_CFG_ENABLED_SHIFT (31)
+#define TIMESYNC_CFG_CHAN_DB_ID_MASK (0x0000FF00)
+#define TIMESYNC_CFG_CHAN_DB_ID_SHIFT (8)
+#define TIMESYNC_CFG_ER_ID_MASK (0x000000FF)
+#define TIMESYNC_CFG_ER_ID_SHIFT (0)
+
#define TIMESYNC_TIME_LOW_OFFSET (0x8)
#define TIMESYNC_TIME_HIGH_OFFSET (0xC)
@@ -325,12 +325,6 @@ enum mhi_cmd_type {
#define MHI_TRE_CMD_START_DWORD1(chid) ((chid << 24) | \
(MHI_CMD_TYPE_START << 16))
-/* time sync cfg command */
-#define MHI_TRE_CMD_TSYNC_CFG_PTR (0)
-#define MHI_TRE_CMD_TSYNC_CFG_DWORD0 (0)
-#define MHI_TRE_CMD_TSYNC_CFG_DWORD1(er) ((MHI_CMD_TYPE_TSYNC << 16) | \
- (er << 24))
-
/* subsystem failure reason cfg command */
#define MHI_TRE_CMD_SFR_CFG_PTR(ptr) (ptr)
#define MHI_TRE_CMD_SFR_CFG_DWORD0(len) (len)
@@ -351,6 +345,7 @@ enum mhi_cmd_type {
#define MHI_TRE_GET_EV_STATE(tre) (((tre)->dword[0] >> 24) & 0xFF)
#define MHI_TRE_GET_EV_EXECENV(tre) (((tre)->dword[0] >> 24) & 0xFF)
#define MHI_TRE_GET_EV_TSYNC_SEQ(tre) ((tre)->dword[0])
+#define MHI_TRE_GET_EV_TSYNC_UNIT(tre) (((tre)->dword[1] >> 24) & 0xFF)
#define MHI_TRE_GET_EV_TIME(tre) ((tre)->ptr)
#define MHI_TRE_GET_EV_COOKIE(tre) lower_32_bits((tre)->ptr)
#define MHI_TRE_GET_EV_VEID(tre) (((tre)->dword[0] >> 16) & 0xFF)
@@ -375,7 +370,6 @@ enum MHI_CMD {
MHI_CMD_RESET_CHAN,
MHI_CMD_START_CHAN,
MHI_CMD_STOP_CHAN,
- MHI_CMD_TIMSYNC_CFG,
MHI_CMD_SFR_CFG,
};
@@ -530,10 +524,16 @@ enum MHI_XFER_TYPE {
#define NR_OF_CMD_RINGS (1)
#define CMD_EL_PER_RING (128)
#define PRIMARY_CMD_RING (0)
+#define MHI_TIMESYNC_CHAN_DB (125)
#define MHI_BW_SCALE_CHAN_DB (126)
#define MHI_DEV_WAKE_DB (127)
#define MHI_MAX_MTU (0xffff)
+#define MHI_TIMESYNC_DB_SETUP(er_index) ((MHI_TIMESYNC_CHAN_DB << \
+ TIMESYNC_CFG_CHAN_DB_ID_SHIFT) & TIMESYNC_CFG_CHAN_DB_ID_MASK | \
+ (1 << TIMESYNC_CFG_ENABLED_SHIFT) & TIMESYNC_CFG_ENABLED_MASK | \
+ ((er_index) << TIMESYNC_CFG_ER_ID_SHIFT) & TIMESYNC_CFG_ER_ID_MASK)
+
#define MHI_BW_SCALE_SETUP(er_index) ((MHI_BW_SCALE_CHAN_DB << \
BW_SCALE_CFG_CHAN_DB_ID_SHIFT) & BW_SCALE_CFG_CHAN_DB_ID_MASK | \
(1 << BW_SCALE_CFG_ENABLED_SHIFT) & BW_SCALE_CFG_ENABLED_MASK | \
@@ -665,6 +665,9 @@ struct mhi_event {
struct mhi_event *mhi_event,
u32 event_quota);
struct mhi_controller *mhi_cntrl;
+ struct mhi_tre last_cached_tre;
+ u64 last_dev_rp;
+ bool force_uncached;
};
struct mhi_chan {
@@ -714,6 +717,7 @@ struct mhi_chan {
struct tsync_node {
struct list_head node;
u32 sequence;
+ u32 int_sequence;
u64 local_time;
u64 remote_time;
struct mhi_device *mhi_dev;
@@ -722,11 +726,8 @@ struct tsync_node {
};
struct mhi_timesync {
- u32 er_index;
- void __iomem *db;
void __iomem *time_reg;
- enum MHI_EV_CCS ccs;
- struct completion completion;
+ u32 int_sequence;
spinlock_t lock; /* list protection */
struct list_head head;
};
@@ -752,6 +753,7 @@ extern struct mhi_bus mhi_bus;
struct mhi_controller *find_mhi_controller_by_name(const char *name);
/* debug fs related functions */
+int mhi_debugfs_mhi_vote_show(struct seq_file *m, void *d);
int mhi_debugfs_mhi_chan_show(struct seq_file *m, void *d);
int mhi_debugfs_mhi_event_show(struct seq_file *m, void *d);
int mhi_debugfs_mhi_states_show(struct seq_file *m, void *d);
@@ -837,11 +839,8 @@ void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl,
int mhi_get_capability_offset(struct mhi_controller *mhi_cntrl, u32 capability,
u32 *offset);
void *mhi_to_virtual(struct mhi_ring *ring, dma_addr_t addr);
-int mhi_init_timesync(struct mhi_controller *mhi_cntrl);
int mhi_init_sfr(struct mhi_controller *mhi_cntrl);
-int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl);
-void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl);
-int mhi_create_sysfs(struct mhi_controller *mhi_cntrl);
+void mhi_create_sysfs(struct mhi_controller *mhi_cntrl);
void mhi_destroy_sysfs(struct mhi_controller *mhi_cntrl);
int mhi_early_notify_device(struct device *dev, void *data);
void mhi_write_reg_offload(struct mhi_controller *mhi_cntrl,
@@ -879,6 +878,29 @@ static inline void mhi_free_coherent(struct mhi_controller *mhi_cntrl,
dma_free_coherent(mhi_cntrl->dev, size, vaddr, dma_handle);
}
+static inline void *mhi_alloc_uncached(struct mhi_controller *mhi_cntrl,
+ size_t size,
+ dma_addr_t *dma_handle,
+ gfp_t gfp)
+{
+ void *buf = dma_alloc_attrs(mhi_cntrl->dev, size, dma_handle, gfp,
+ DMA_ATTR_FORCE_NON_COHERENT);
+
+ if (buf)
+ atomic_add(size, &mhi_cntrl->alloc_size);
+
+ return buf;
+}
+static inline void mhi_free_uncached(struct mhi_controller *mhi_cntrl,
+ size_t size,
+ void *vaddr,
+ dma_addr_t dma_handle)
+{
+ atomic_sub(size, &mhi_cntrl->alloc_size);
+ dma_free_attrs(mhi_cntrl->dev, size, vaddr, dma_handle,
+ DMA_ATTR_FORCE_NON_COHERENT);
+}
+
static inline void *mhi_alloc_contig_coherent(
struct mhi_controller *mhi_cntrl,
size_t size, dma_addr_t *dma_handle,
diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c
index ecee755..916010f 100644
--- a/drivers/bus/mhi/core/mhi_main.c
+++ b/drivers/bus/mhi/core/mhi_main.c
@@ -852,38 +852,6 @@ int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl)
&mhi_tsync_group);
}
-static void mhi_create_time_sync_dev(struct mhi_controller *mhi_cntrl)
-{
- struct mhi_device *mhi_dev;
- int ret;
-
- if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee))
- return;
-
- mhi_dev = mhi_alloc_device(mhi_cntrl);
- if (!mhi_dev)
- return;
-
- mhi_dev->dev_type = MHI_TIMESYNC_TYPE;
- mhi_dev->chan_name = "TIME_SYNC";
- dev_set_name(&mhi_dev->dev, "%04x_%02u.%02u.%02u_%s", mhi_dev->dev_id,
- mhi_dev->domain, mhi_dev->bus, mhi_dev->slot,
- mhi_dev->chan_name);
-
- /* add if there is a matching DT node */
- mhi_assign_of_node(mhi_cntrl, mhi_dev);
-
- ret = device_add(&mhi_dev->dev);
- if (ret) {
- MHI_ERR("Failed to register dev for chan:%s\n",
- mhi_dev->chan_name);
- mhi_dealloc_device(mhi_cntrl, mhi_dev);
- return;
- }
-
- mhi_cntrl->tsync_dev = mhi_dev;
-}
-
/* bind mhi channels into mhi devices */
void mhi_create_devices(struct mhi_controller *mhi_cntrl)
{
@@ -892,13 +860,6 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl)
struct mhi_device *mhi_dev;
int ret;
- /*
- * we need to create time sync device before creating other
- * devices, because client may try to capture time during
- * clint probe.
- */
- mhi_create_time_sync_dev(mhi_cntrl);
-
mhi_chan = mhi_cntrl->mhi_chan;
for (i = 0; i < mhi_cntrl->max_chan; i++, mhi_chan++) {
if (!mhi_chan->configured || mhi_chan->mhi_dev ||
@@ -1209,7 +1170,6 @@ static void mhi_process_cmd_completion(struct mhi_controller *mhi_cntrl,
struct mhi_ring *mhi_ring = &cmd_ring->ring;
struct mhi_tre *cmd_pkt;
struct mhi_chan *mhi_chan;
- struct mhi_timesync *mhi_tsync;
struct mhi_sfr_info *sfr_info;
enum mhi_cmd_type type;
u32 chan;
@@ -1222,11 +1182,6 @@ static void mhi_process_cmd_completion(struct mhi_controller *mhi_cntrl,
type = MHI_TRE_GET_CMD_TYPE(cmd_pkt);
switch (type) {
- case MHI_CMD_TYPE_TSYNC:
- mhi_tsync = mhi_cntrl->mhi_tsync;
- mhi_tsync->ccs = MHI_TRE_GET_EV_CODE(tre);
- complete(&mhi_tsync->completion);
- break;
case MHI_CMD_TYPE_SFR_CFG:
sfr_info = mhi_cntrl->mhi_sfr;
sfr_info->ccs = MHI_TRE_GET_EV_CODE(tre);
@@ -1343,6 +1298,10 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
TO_MHI_EXEC_STR(event));
switch (event) {
case MHI_EE_SBL:
+ write_lock_irq(&mhi_cntrl->pm_lock);
+ mhi_cntrl->ee = MHI_EE_SBL;
+ write_unlock_irq(&mhi_cntrl->pm_lock);
+ wake_up_all(&mhi_cntrl->state_event);
st = MHI_ST_TRANSITION_SBL;
break;
case MHI_EE_WFW:
@@ -1350,13 +1309,6 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
st = MHI_ST_TRANSITION_MISSION_MODE;
break;
case MHI_EE_RDDM:
- mhi_cntrl->status_cb(mhi_cntrl,
- mhi_cntrl->priv_data,
- MHI_CB_EE_RDDM);
- write_lock_irq(&mhi_cntrl->pm_lock);
- mhi_cntrl->ee = event;
- write_unlock_irq(&mhi_cntrl->pm_lock);
- wake_up_all(&mhi_cntrl->state_event);
break;
default:
MHI_ERR("Unhandled EE event:%s\n",
@@ -1415,7 +1367,16 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl,
MHI_VERB("Processing Event:0x%llx 0x%08x 0x%08x\n",
local_rp->ptr, local_rp->dword[0], local_rp->dword[1]);
+ mhi_event->last_cached_tre.ptr = local_rp->ptr;
+ mhi_event->last_cached_tre.dword[0] = local_rp->dword[0];
+ mhi_event->last_cached_tre.dword[1] = local_rp->dword[1];
+ mhi_event->last_dev_rp = (u64)dev_rp;
+
chan = MHI_TRE_GET_EV_CHID(local_rp);
+ if (chan >= mhi_cntrl->max_chan) {
+ MHI_ERR("invalid channel id %u\n", chan);
+ continue;
+ }
mhi_chan = &mhi_cntrl->mhi_chan[chan];
if (likely(type == MHI_PKT_TYPE_TX_EVENT)) {
@@ -1451,7 +1412,7 @@ int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl,
&mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync;
int count = 0;
- u32 sequence;
+ u32 int_sequence, unit;
u64 remote_time;
if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) {
@@ -1473,28 +1434,29 @@ int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl,
MHI_ASSERT(type != MHI_PKT_TYPE_TSYNC_EVENT, "!TSYNC event");
- sequence = MHI_TRE_GET_EV_TSYNC_SEQ(local_rp);
+ int_sequence = MHI_TRE_GET_EV_TSYNC_SEQ(local_rp);
+ unit = MHI_TRE_GET_EV_TSYNC_UNIT(local_rp);
remote_time = MHI_TRE_GET_EV_TIME(local_rp);
do {
- spin_lock_irq(&mhi_tsync->lock);
+ spin_lock(&mhi_tsync->lock);
tsync_node = list_first_entry_or_null(&mhi_tsync->head,
struct tsync_node, node);
- MHI_ASSERT(!tsync_node, "Unexpected Event");
-
- if (unlikely(!tsync_node))
+ if (!tsync_node) {
+ spin_unlock(&mhi_tsync->lock);
break;
+ }
list_del(&tsync_node->node);
- spin_unlock_irq(&mhi_tsync->lock);
+ spin_unlock(&mhi_tsync->lock);
/*
* device may not able to process all time sync commands
* host issue and only process last command it receive
*/
- if (tsync_node->sequence == sequence) {
+ if (tsync_node->int_sequence == int_sequence) {
tsync_node->cb_func(tsync_node->mhi_dev,
- sequence,
+ tsync_node->sequence,
tsync_node->local_time,
remote_time);
kfree(tsync_node);
@@ -1537,9 +1499,6 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl,
goto exit_no_lock;
}
- if (mhi_cntrl->need_force_m3 && !mhi_cntrl->force_m3_done)
- goto exit_no_lock;
-
ret = __mhi_device_get_sync(mhi_cntrl);
if (ret)
goto exit_no_lock;
@@ -1714,14 +1673,21 @@ irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev)
MHI_VERB("Enter\n");
write_lock_irq(&mhi_cntrl->pm_lock);
- if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
- state = mhi_get_mhi_state(mhi_cntrl);
- ee = mhi_cntrl->ee;
- mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl);
- MHI_LOG("local ee: %s device ee:%s dev_state:%s\n",
- TO_MHI_EXEC_STR(ee),
- TO_MHI_EXEC_STR(mhi_cntrl->ee),
- TO_MHI_STATE_STR(state));
+ if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
+ write_unlock_irq(&mhi_cntrl->pm_lock);
+ goto exit_intvec;
+ }
+
+ state = mhi_get_mhi_state(mhi_cntrl);
+ ee = mhi_get_exec_env(mhi_cntrl);
+ MHI_LOG("local ee:%s device ee:%s dev_state:%s\n",
+ TO_MHI_EXEC_STR(mhi_cntrl->ee),
+ TO_MHI_EXEC_STR(ee),
+ TO_MHI_STATE_STR(state));
+
+ if (mhi_cntrl->power_down) {
+ write_unlock_irq(&mhi_cntrl->pm_lock);
+ goto exit_intvec;
}
if (state == MHI_STATE_SYS_ERR) {
@@ -1731,20 +1697,28 @@ irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev)
}
write_unlock_irq(&mhi_cntrl->pm_lock);
- /* if device in rddm don't bother processing sys error */
- if (mhi_cntrl->ee == MHI_EE_RDDM && ee != MHI_EE_DISABLE_TRANSITION) {
- if (mhi_cntrl->ee != ee) {
- mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data,
- MHI_CB_EE_RDDM);
- wake_up_all(&mhi_cntrl->state_event);
-
- /* notify critical clients with early notifications */
- mhi_control_error(mhi_cntrl);
+ if (ee == MHI_EE_RDDM) {
+ write_lock_irq(&mhi_cntrl->pm_lock);
+ if (mhi_cntrl->ee == MHI_EE_RDDM) {
+ write_unlock_irq(&mhi_cntrl->pm_lock);
+ goto exit_intvec;
}
+ mhi_cntrl->ee = MHI_EE_RDDM;
+ write_unlock_irq(&mhi_cntrl->pm_lock);
+
+ MHI_ERR("RDDM event occurred!\n");
+ mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data,
+ MHI_CB_EE_RDDM);
+ wake_up_all(&mhi_cntrl->state_event);
+
+ /* notify critical clients with early notifications */
+ mhi_control_error(mhi_cntrl);
+
goto exit_intvec;
}
- if (pm_state == MHI_PM_SYS_ERR_DETECT) {
+ /* if device is in RDDM, don't bother processing SYS_ERR */
+ if (ee != MHI_EE_RDDM && pm_state == MHI_PM_SYS_ERR_DETECT) {
wake_up_all(&mhi_cntrl->state_event);
/* for fatal errors, we let controller decide next step */
@@ -1765,9 +1739,15 @@ irqreturn_t mhi_intvec_handlr(int irq_number, void *dev)
{
struct mhi_controller *mhi_cntrl = dev;
+ u32 in_reset = -1;
/* wake up any events waiting for state change */
MHI_VERB("Enter\n");
+ if (unlikely(mhi_cntrl->initiate_mhi_reset)) {
+ mhi_read_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
+ MHICTRL_RESET_MASK, MHICTRL_RESET_SHIFT, &in_reset);
+ mhi_cntrl->initiate_mhi_reset = !!in_reset;
+ }
wake_up_all(&mhi_cntrl->state_event);
MHI_VERB("Exit\n");
@@ -1820,12 +1800,6 @@ int mhi_send_cmd(struct mhi_controller *mhi_cntrl,
cmd_tre->dword[0] = MHI_TRE_CMD_STOP_DWORD0;
cmd_tre->dword[1] = MHI_TRE_CMD_STOP_DWORD1(chan);
break;
- case MHI_CMD_TIMSYNC_CFG:
- cmd_tre->ptr = MHI_TRE_CMD_TSYNC_CFG_PTR;
- cmd_tre->dword[0] = MHI_TRE_CMD_TSYNC_CFG_DWORD0;
- cmd_tre->dword[1] = MHI_TRE_CMD_TSYNC_CFG_DWORD1
- (mhi_cntrl->mhi_tsync->er_index);
- break;
case MHI_CMD_SFR_CFG:
sfr_info = mhi_cntrl->mhi_sfr;
cmd_tre->ptr = MHI_TRE_CMD_SFR_CFG_PTR
@@ -2270,6 +2244,49 @@ int mhi_debugfs_mhi_chan_show(struct seq_file *m, void *d)
return 0;
}
+/* show bus/device votes for a specific device */
+int mhi_device_vote_show(struct device *dev, void *data)
+{
+ struct mhi_device *mhi_dev;
+ struct mhi_controller *mhi_cntrl;
+
+ if (dev->bus != &mhi_bus_type)
+ return 0;
+
+ mhi_dev = to_mhi_device(dev);
+ mhi_cntrl = mhi_dev->mhi_cntrl;
+
+ /* we dont care about timesync or similar special devices */
+ if (mhi_dev->dev_type == MHI_TIMESYNC_TYPE)
+ return 0;
+
+ seq_printf((struct seq_file *)data, "%s: device:%u, bus:%u\n",
+ mhi_dev->chan_name, atomic_read(&mhi_dev->dev_vote),
+ atomic_read(&mhi_dev->bus_vote));
+
+ return 0;
+}
+
+int mhi_debugfs_mhi_vote_show(struct seq_file *m, void *d)
+{
+ struct mhi_controller *mhi_cntrl = m->private;
+ struct mhi_device *mhi_dev;
+
+ if (!mhi_cntrl)
+ return 0;
+
+ mhi_dev = mhi_cntrl->mhi_dev;
+
+ seq_printf(m, "At %llu ns:\n", sched_clock());
+ seq_printf(m, "%s: device:%u, bus:%u\n", mhi_dev->chan_name,
+ atomic_read(&mhi_dev->dev_vote),
+ atomic_read(&mhi_dev->bus_vote));
+
+ device_for_each_child(mhi_cntrl->dev, m, mhi_device_vote_show);
+
+ return 0;
+}
+
/* move channel to start state */
int mhi_prepare_for_transfer(struct mhi_device *mhi_dev)
{
@@ -2534,6 +2551,7 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev,
ret = -EIO;
goto error_invalid_state;
}
+ read_unlock_bh(&mhi_cntrl->pm_lock);
/* disable link level low power modes */
ret = mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data);
@@ -2556,6 +2574,7 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev,
mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data);
+ read_lock_bh(&mhi_cntrl->pm_lock);
error_invalid_state:
mhi_cntrl->wake_put(mhi_cntrl, false);
read_unlock_bh(&mhi_cntrl->pm_lock);
@@ -2591,13 +2610,23 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,
mutex_lock(&mhi_cntrl->tsync_mutex);
if (!mhi_tsync) {
ret = -EIO;
- goto err_unlock;
+ goto error_unlock;
}
/* tsync db can only be rung in M0 state */
ret = __mhi_device_get_sync(mhi_cntrl);
if (ret)
- goto err_unlock;
+ goto error_unlock;
+
+ read_lock_bh(&mhi_cntrl->pm_lock);
+ if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
+ MHI_ERR("MHI is not in active state, pm_state:%s\n",
+ to_mhi_pm_state_str(mhi_cntrl->pm_state));
+ ret = -EIO;
+ read_unlock_bh(&mhi_cntrl->pm_lock);
+ goto error_no_mem;
+ }
+ read_unlock_bh(&mhi_cntrl->pm_lock);
/*
* technically we can use GFP_KERNEL, but wants to avoid
@@ -2609,24 +2638,26 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,
goto error_no_mem;
}
+ mhi_tsync->int_sequence++;
+ if (mhi_tsync->int_sequence == 0xFFFFFFFF)
+ mhi_tsync->int_sequence = 0;
+
tsync_node->sequence = sequence;
+ tsync_node->int_sequence = mhi_tsync->int_sequence;
tsync_node->cb_func = cb_func;
tsync_node->mhi_dev = mhi_dev;
/* disable link level low power modes */
- mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data);
-
- read_lock_bh(&mhi_cntrl->pm_lock);
- if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
- MHI_ERR("MHI is not in active state, pm_state:%s\n",
- to_mhi_pm_state_str(mhi_cntrl->pm_state));
- ret = -EIO;
+ ret = mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data);
+ if (ret) {
+ MHI_ERR("LPM disable request failed for %s!\n",
+ mhi_dev->chan_name);
goto error_invalid_state;
}
- spin_lock_irq(&mhi_tsync->lock);
+ spin_lock(&mhi_tsync->lock);
list_add_tail(&tsync_node->node, &mhi_tsync->head);
- spin_unlock_irq(&mhi_tsync->lock);
+ spin_unlock(&mhi_tsync->lock);
/*
* time critical code, delay between these two steps should be
@@ -2637,26 +2668,25 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,
tsync_node->local_time =
mhi_cntrl->time_get(mhi_cntrl, mhi_cntrl->priv_data);
- writel_relaxed_no_log(tsync_node->sequence, mhi_tsync->db);
+ writel_relaxed_no_log(tsync_node->int_sequence, mhi_cntrl->tsync_db);
/* write must go thru immediately */
wmb();
local_irq_enable();
preempt_enable();
+ mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data);
+
ret = 0;
error_invalid_state:
if (ret)
kfree(tsync_node);
- read_unlock_bh(&mhi_cntrl->pm_lock);
- mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data);
-
error_no_mem:
read_lock_bh(&mhi_cntrl->pm_lock);
mhi_cntrl->wake_put(mhi_cntrl, false);
read_unlock_bh(&mhi_cntrl->pm_lock);
-err_unlock:
+error_unlock:
mutex_unlock(&mhi_cntrl->tsync_mutex);
return ret;
}
diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c
index bfd15ab..ab31083 100644
--- a/drivers/bus/mhi/core/mhi_pm.c
+++ b/drivers/bus/mhi/core/mhi_pm.c
@@ -167,6 +167,7 @@ void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl,
if (state == MHI_STATE_RESET) {
mhi_write_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
MHICTRL_RESET_MASK, MHICTRL_RESET_SHIFT, 1);
+ mhi_cntrl->initiate_mhi_reset = true;
} else {
mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
(state << MHICTRL_MHISTATE_SHIFT));
@@ -471,12 +472,16 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl)
ee = mhi_get_exec_env(mhi_cntrl);
write_unlock_irq(&mhi_cntrl->pm_lock);
- if (!MHI_IN_MISSION_MODE(ee))
+ if (!MHI_IN_MISSION_MODE(ee)) {
+ MHI_ERR("Invalid EE:%s\n", TO_MHI_EXEC_STR(ee));
return -EIO;
+ }
mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data,
MHI_CB_EE_MISSION_MODE);
+ write_lock_irq(&mhi_cntrl->pm_lock);
mhi_cntrl->ee = ee;
+ write_unlock_irq(&mhi_cntrl->pm_lock);
wake_up_all(&mhi_cntrl->state_event);
@@ -520,23 +525,22 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl)
read_unlock_bh(&mhi_cntrl->pm_lock);
- /* setup support for additional features (SFR, timesync, etc.) */
+ /* setup support for additional features */
mhi_init_sfr(mhi_cntrl);
- mhi_init_timesync(mhi_cntrl);
if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
mhi_timesync_log(mhi_cntrl);
mhi_special_events_pending(mhi_cntrl);
+ /* setup sysfs nodes for userspace votes */
+ mhi_create_sysfs(mhi_cntrl);
+
MHI_LOG("Adding new devices\n");
/* add supported devices */
mhi_create_devices(mhi_cntrl);
- /* setup sysfs nodes for userspace votes */
- mhi_create_sysfs(mhi_cntrl);
-
read_lock_bh(&mhi_cntrl->pm_lock);
error_mission_mode:
@@ -584,8 +588,6 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
mhi_cntrl->ee = MHI_EE_DISABLE_TRANSITION;
mhi_cntrl->dev_state = MHI_STATE_RESET;
}
- /* notify controller of power down regardless of state transitions */
- mhi_cntrl->power_down = true;
write_unlock_irq(&mhi_cntrl->pm_lock);
/* wake up any threads waiting for state transitions */
@@ -601,20 +603,18 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
/* trigger MHI RESET so device will not access host ddr */
if (MHI_REG_ACCESS_VALID(prev_state)) {
- u32 in_reset = -1;
unsigned long timeout = msecs_to_jiffies(mhi_cntrl->timeout_ms);
MHI_LOG("Trigger device into MHI_RESET\n");
+
+ write_lock_irq(&mhi_cntrl->pm_lock);
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET);
+ write_unlock_irq(&mhi_cntrl->pm_lock);
/* wait for reset to be cleared */
ret = wait_event_timeout(mhi_cntrl->state_event,
- mhi_read_reg_field(mhi_cntrl,
- mhi_cntrl->regs, MHICTRL,
- MHICTRL_RESET_MASK,
- MHICTRL_RESET_SHIFT, &in_reset)
- || !in_reset, timeout);
- if ((!ret || in_reset) && cur_state == MHI_PM_SYS_ERR_PROCESS) {
+ !mhi_cntrl->initiate_mhi_reset, timeout);
+ if (!ret && cur_state == MHI_PM_SYS_ERR_PROCESS) {
MHI_CRITICAL("Device failed to exit RESET state\n");
mutex_unlock(&mhi_cntrl->pm_mutex);
return;
@@ -624,7 +624,11 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
* device cleares INTVEC as part of RESET processing,
* re-program it
*/
- mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_INTVEC, 0);
+ if (!mhi_cntrl->initiate_mhi_reset)
+ mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->bhi,
+ BHI_INTVEC, 0);
+
+ mhi_cntrl->initiate_mhi_reset = false;
}
MHI_LOG("Waiting for all pending event ring processing to complete\n");
@@ -649,17 +653,12 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
wake_up_all(&mhi_cntrl->state_event);
flush_work(&mhi_cntrl->special_work);
- mhi_cntrl->force_m3_done = false;
-
if (sfr_info && sfr_info->buf_addr) {
mhi_free_coherent(mhi_cntrl, sfr_info->len, sfr_info->buf_addr,
sfr_info->dma_addr);
sfr_info->buf_addr = NULL;
}
- /* remove support for time sync */
- mhi_destroy_timesync(mhi_cntrl);
-
mutex_lock(&mhi_cntrl->pm_mutex);
MHI_ASSERT(atomic_read(&mhi_cntrl->dev_wake), "dev_wake != 0");
@@ -837,6 +836,10 @@ void mhi_process_sys_err(struct mhi_controller *mhi_cntrl)
return;
}
+ write_lock_irq(&mhi_cntrl->pm_lock);
+ mhi_cntrl->power_down = true;
+ write_unlock_irq(&mhi_cntrl->pm_lock);
+
mhi_queue_disable_transition(mhi_cntrl, MHI_PM_SYS_ERR_PROCESS);
}
@@ -862,14 +865,9 @@ void mhi_pm_st_worker(struct work_struct *work)
if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl);
write_unlock_irq(&mhi_cntrl->pm_lock);
- if (MHI_IN_PBL(mhi_cntrl->ee))
- mhi_fw_load_handler(mhi_cntrl);
+ mhi_fw_load_handler(mhi_cntrl);
break;
case MHI_ST_TRANSITION_SBL:
- write_lock_irq(&mhi_cntrl->pm_lock);
- mhi_cntrl->ee = MHI_EE_SBL;
- write_unlock_irq(&mhi_cntrl->pm_lock);
- wake_up_all(&mhi_cntrl->state_event);
mhi_create_devices(mhi_cntrl);
break;
case MHI_ST_TRANSITION_MISSION_MODE:
@@ -956,6 +954,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
}
mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_INTVEC, 0);
+ mhi_cntrl->power_down = false;
mhi_cntrl->pm_state = MHI_PM_POR;
mhi_cntrl->ee = MHI_EE_MAX;
current_ee = mhi_get_exec_env(mhi_cntrl);
@@ -983,6 +982,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
return 0;
error_bhi_offset:
+ mhi_cntrl->power_down = true;
mhi_deinit_free_irq(mhi_cntrl);
error_setup_irq:
@@ -1049,21 +1049,23 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
enum MHI_PM_STATE cur_state;
enum MHI_PM_STATE transition_state = MHI_PM_SHUTDOWN_PROCESS;
+ mutex_lock(&mhi_cntrl->pm_mutex);
+
+ write_lock_irq(&mhi_cntrl->pm_lock);
+ mhi_cntrl->power_down = true;
/* if it's not graceful shutdown, force MHI to a linkdown state */
if (!graceful) {
- mutex_lock(&mhi_cntrl->pm_mutex);
- write_lock_irq(&mhi_cntrl->pm_lock);
cur_state = mhi_tryset_pm_state(mhi_cntrl,
MHI_PM_LD_ERR_FATAL_DETECT);
- write_unlock_irq(&mhi_cntrl->pm_lock);
- mutex_unlock(&mhi_cntrl->pm_mutex);
if (cur_state != MHI_PM_LD_ERR_FATAL_DETECT)
MHI_ERR("Failed to move to state:%s from:%s\n",
to_mhi_pm_state_str(MHI_PM_LD_ERR_FATAL_DETECT),
to_mhi_pm_state_str(mhi_cntrl->pm_state));
-
transition_state = MHI_PM_SHUTDOWN_NO_ACCESS;
}
+ write_unlock_irq(&mhi_cntrl->pm_lock);
+
+ mutex_unlock(&mhi_cntrl->pm_mutex);
mhi_queue_disable_transition(mhi_cntrl, transition_state);
@@ -1219,11 +1221,17 @@ int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client)
enum MHI_PM_STATE new_state;
struct mhi_chan *itr, *tmp;
- if (mhi_cntrl->pm_state == MHI_PM_DISABLE)
+ read_lock_bh(&mhi_cntrl->pm_lock);
+ if (mhi_cntrl->pm_state == MHI_PM_DISABLE) {
+ read_unlock_bh(&mhi_cntrl->pm_lock);
return -EINVAL;
+ }
- if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))
+ if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
+ read_unlock_bh(&mhi_cntrl->pm_lock);
return -EIO;
+ }
+ read_unlock_bh(&mhi_cntrl->pm_lock);
/* do a quick check to see if any pending votes to keep us busy */
if (atomic_read(&mhi_cntrl->pending_pkts)) {
@@ -1251,6 +1259,12 @@ int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client)
goto error_suspend;
}
+ /* check pm state before saving it */
+ if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
+ ret = -EIO;
+ goto error_suspend;
+ }
+
/* anytime after this, we will resume thru runtime pm framework */
MHI_LOG("Allowing Fast M3 transition\n");
@@ -1400,17 +1414,23 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client)
struct mhi_event *mhi_event;
int i;
+ read_lock_bh(&mhi_cntrl->pm_lock);
MHI_LOG("Entered with pm_state:%s dev_state:%s\n",
to_mhi_pm_state_str(mhi_cntrl->pm_state),
TO_MHI_STATE_STR(mhi_cntrl->dev_state));
- if (mhi_cntrl->pm_state == MHI_PM_DISABLE)
+ if (mhi_cntrl->pm_state == MHI_PM_DISABLE) {
+ read_unlock_bh(&mhi_cntrl->pm_lock);
return 0;
+ }
- if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))
+ if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
+ read_unlock_bh(&mhi_cntrl->pm_lock);
return -EIO;
+ }
MHI_ASSERT(mhi_cntrl->pm_state != MHI_PM_M3, "mhi_pm_state != M3");
+ read_unlock_bh(&mhi_cntrl->pm_lock);
/* notify any clients we're about to exit lpm */
if (notify_client) {
@@ -1424,10 +1444,19 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client)
/* do not process control events */
tasklet_disable(&mhi_cntrl->mhi_event->task);
+ /* check if we entered error state again before doing the restore */
write_lock_irq(&mhi_cntrl->pm_lock);
+
+ if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
+ write_unlock_irq(&mhi_cntrl->pm_lock);
+ tasklet_enable(&mhi_cntrl->mhi_event->task);
+ return -EIO;
+ }
+
/* restore the states */
mhi_cntrl->pm_state = mhi_cntrl->saved_pm_state;
mhi_cntrl->dev_state = mhi_cntrl->saved_dev_state;
+
write_unlock_irq(&mhi_cntrl->pm_lock);
switch (mhi_cntrl->pm_state) {
@@ -1439,6 +1468,12 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client)
mhi_cntrl->wake_get(mhi_cntrl, true);
mhi_cntrl->wake_put(mhi_cntrl, true);
read_unlock_bh(&mhi_cntrl->pm_lock);
+ break;
+ default:
+ MHI_ERR("Unexpected PM state:%s after restore\n",
+ to_mhi_pm_state_str(mhi_cntrl->pm_state));
+ tasklet_enable(&mhi_cntrl->mhi_event->task);
+ return -EIO;
}
/* now it's safe to process ctrl events */
@@ -1505,6 +1540,7 @@ void mhi_device_get(struct mhi_device *mhi_dev, int vote)
if (vote & MHI_VOTE_DEVICE) {
read_lock_bh(&mhi_cntrl->pm_lock);
mhi_cntrl->wake_get(mhi_cntrl, true);
+ MHI_LOG("dev_wake %d\n", atomic_read(&mhi_cntrl->dev_wake));
read_unlock_bh(&mhi_cntrl->pm_lock);
atomic_inc(&mhi_dev->dev_vote);
}
@@ -1558,6 +1594,7 @@ void mhi_device_put(struct mhi_device *mhi_dev, int vote)
mhi_trigger_resume(mhi_cntrl);
mhi_cntrl->wake_put(mhi_cntrl, false);
+ MHI_LOG("dev_wake %d\n", atomic_read(&mhi_cntrl->dev_wake));
read_unlock_bh(&mhi_cntrl->pm_lock);
}
diff --git a/drivers/bus/mhi/devices/mhi_uci.c b/drivers/bus/mhi/devices/mhi_uci.c
index 7dbb4d7..d16ba5c 100644
--- a/drivers/bus/mhi/devices/mhi_uci.c
+++ b/drivers/bus/mhi/devices/mhi_uci.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.*/
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.*/
#include <linux/cdev.h>
#include <linux/device.h>
@@ -50,6 +50,7 @@ struct uci_dev {
bool enabled;
u32 tiocm;
void *ipc_log;
+ enum MHI_DEBUG_LEVEL *ipc_log_lvl;
};
struct mhi_uci_drv {
@@ -64,36 +65,33 @@ enum MHI_DEBUG_LEVEL msg_lvl = MHI_MSG_LVL_ERROR;
#ifdef CONFIG_MHI_DEBUG
-#define IPC_LOG_LVL (MHI_MSG_LVL_VERBOSE)
#define MHI_UCI_IPC_LOG_PAGES (25)
-
-#else
-
-#define IPC_LOG_LVL (MHI_MSG_LVL_ERROR)
-#define MHI_UCI_IPC_LOG_PAGES (1)
-
-#endif
-
-#ifdef CONFIG_MHI_DEBUG
-
#define MSG_VERB(fmt, ...) do { \
if (msg_lvl <= MHI_MSG_LVL_VERBOSE) \
pr_err("[D][%s] " fmt, __func__, ##__VA_ARGS__); \
- if (uci_dev->ipc_log && (IPC_LOG_LVL <= MHI_MSG_LVL_VERBOSE)) \
- ipc_log_string(uci_dev->ipc_log, "[D][%s] " fmt, \
- __func__, ##__VA_ARGS__); \
+ if (uci_dev->ipc_log && uci_dev->ipc_log_lvl && \
+ (*uci_dev->ipc_log_lvl <= MHI_MSG_LVL_VERBOSE)) \
+ ipc_log_string(uci_dev->ipc_log, \
+ "[D][%s] " fmt, __func__, ##__VA_ARGS__); \
} while (0)
#else
-#define MSG_VERB(fmt, ...)
+#define MHI_UCI_IPC_LOG_PAGES (1)
+#define MSG_VERB(fmt, ...) do { \
+ if (uci_dev->ipc_log && uci_dev->ipc_log_lvl && \
+ (*uci_dev->ipc_log_lvl <= MHI_MSG_LVL_VERBOSE)) \
+ ipc_log_string(uci_dev->ipc_log, \
+ "[D][%s] " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
#endif
#define MSG_LOG(fmt, ...) do { \
if (msg_lvl <= MHI_MSG_LVL_INFO) \
pr_err("[I][%s] " fmt, __func__, ##__VA_ARGS__); \
- if (uci_dev->ipc_log && (IPC_LOG_LVL <= MHI_MSG_LVL_INFO)) \
+ if (uci_dev->ipc_log && uci_dev->ipc_log_lvl && \
+ (*uci_dev->ipc_log_lvl <= MHI_MSG_LVL_INFO)) \
ipc_log_string(uci_dev->ipc_log, "[I][%s] " fmt, \
__func__, ##__VA_ARGS__); \
} while (0)
@@ -101,7 +99,8 @@ enum MHI_DEBUG_LEVEL msg_lvl = MHI_MSG_LVL_ERROR;
#define MSG_ERR(fmt, ...) do { \
if (msg_lvl <= MHI_MSG_LVL_ERROR) \
pr_err("[E][%s] " fmt, __func__, ##__VA_ARGS__); \
- if (uci_dev->ipc_log && (IPC_LOG_LVL <= MHI_MSG_LVL_ERROR)) \
+ if (uci_dev->ipc_log && uci_dev->ipc_log_lvl && \
+ (*uci_dev->ipc_log_lvl <= MHI_MSG_LVL_ERROR)) \
ipc_log_string(uci_dev->ipc_log, "[E][%s] " fmt, \
__func__, ##__VA_ARGS__); \
} while (0)
@@ -571,6 +570,7 @@ static int mhi_uci_probe(struct mhi_device *mhi_dev,
const struct mhi_device_id *id)
{
struct uci_dev *uci_dev;
+ struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
int minor;
char node_name[32];
int dir;
@@ -606,6 +606,7 @@ static int mhi_uci_probe(struct mhi_device *mhi_dev,
mhi_dev->ul_chan_id);
uci_dev->ipc_log = ipc_log_context_create(MHI_UCI_IPC_LOG_PAGES,
node_name, 0);
+ uci_dev->ipc_log_lvl = &mhi_cntrl->log_lvl;
for (dir = 0; dir < 2; dir++) {
struct uci_chan *uci_chan = (dir) ?
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 933268b..d394738 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -996,6 +996,12 @@ static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype *tracks)
tracks->xa = 0;
tracks->error = 0;
cd_dbg(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n");
+
+ if (!CDROM_CAN(CDC_PLAY_AUDIO)) {
+ tracks->error = CDS_NO_INFO;
+ return;
+ }
+
/* Grab the TOC header so we can see how many tracks there are */
ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header);
if (ret) {
@@ -1162,7 +1168,8 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev,
ret = open_for_data(cdi);
if (ret)
goto err;
- cdrom_mmc3_profile(cdi);
+ if (CDROM_CAN(CDC_GENERIC_PACKET))
+ cdrom_mmc3_profile(cdi);
if (mode & FMODE_WRITE) {
ret = -EROFS;
if (cdrom_open_write(cdi))
@@ -2882,6 +2889,9 @@ int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written)
it doesn't give enough information or fails. then we return
the toc contents. */
use_toc:
+ if (!CDROM_CAN(CDC_PLAY_AUDIO))
+ return -ENOSYS;
+
toc.cdte_format = CDROM_MSF;
toc.cdte_track = CDROM_LEADOUT;
if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc)))
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 171dff1..ac55873 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -261,6 +261,7 @@ struct overlap {
uintptr_t mstart;
uintptr_t mend;
uintptr_t offset;
+ int do_cmo; /*used for cache maintenance of inrout buffers*/
};
struct smq_invoke_ctx {
@@ -1269,6 +1270,9 @@ static int context_build_overlap(struct smq_invoke_ctx *ctx)
if (ctx->overps[i]->end > max.end) {
max.end = ctx->overps[i]->end;
} else {
+ if (max.raix + 1 <= inbufs &&
+ ctx->overps[i]->raix + 1 > inbufs)
+ ctx->overps[i]->do_cmo = 1;
ctx->overps[i]->mend = 0;
ctx->overps[i]->mstart = 0;
}
@@ -1858,11 +1862,12 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
if (map && (map->attr & FASTRPC_ATTR_FORCE_NOFLUSH))
continue;
- if (rpra && rpra[i].buf.len &&
- ctx->overps[oix]->mstart) {
+ if (rpra && rpra[i].buf.len && (ctx->overps[oix]->mstart ||
+ ctx->overps[oix]->do_cmo == 1)) {
if (map && map->buf) {
- if ((buf_page_size(ctx->overps[oix]->mend -
- ctx->overps[oix]->mstart)) == map->size) {
+ if (((buf_page_size(ctx->overps[oix]->mend -
+ ctx->overps[oix]->mstart)) == map->size) ||
+ ctx->overps[oix]->do_cmo) {
dma_buf_begin_cpu_access(map->buf,
DMA_TO_DEVICE);
dma_buf_end_cpu_access(map->buf,
@@ -2000,10 +2005,11 @@ static void inv_args(struct smq_invoke_ctx *ctx)
buf_page_start(rpra[over].buf.pv)) {
continue;
}
- if (ctx->overps[i]->mstart) {
+ if (ctx->overps[i]->mstart || ctx->overps[i]->do_cmo == 1) {
if (map && map->buf) {
- if ((buf_page_size(ctx->overps[i]->mend -
- ctx->overps[i]->mstart)) == map->size) {
+ if (((buf_page_size(ctx->overps[i]->mend -
+ ctx->overps[i]->mstart)) == map->size) ||
+ ctx->overps[i]->do_cmo) {
dma_buf_begin_cpu_access(map->buf,
DMA_TO_DEVICE);
dma_buf_end_cpu_access(map->buf,
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 771c91d..6638358 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -537,6 +537,7 @@ static int diag_remove_client_entry(struct file *file)
return -EINVAL;
}
+ mutex_lock(&driver->diagchar_mutex);
diagpriv_data = file->private_data;
for (i = 0; i < driver->num_clients; i++)
if (diagpriv_data && diagpriv_data->pid ==
@@ -546,11 +547,13 @@ static int diag_remove_client_entry(struct file *file)
DIAG_LOG(DIAG_DEBUG_USERSPACE,
"pid %d, not present in client map\n",
diagpriv_data->pid);
+ mutex_unlock(&driver->diagchar_mutex);
mutex_unlock(&driver->diag_file_mutex);
return -EINVAL;
}
DIAG_LOG(DIAG_DEBUG_USERSPACE, "diag: %s process exit with pid = %d\n",
driver->client_map[i].name, diagpriv_data->pid);
+ mutex_unlock(&driver->diagchar_mutex);
/*
* clean up any DCI registrations, if this is a DCI client
* This will specially help in case of ungraceful exit of any DCI client
@@ -4297,7 +4300,7 @@ static void diag_debug_init(void)
* to be logged to IPC
*/
diag_debug_mask = DIAG_DEBUG_PERIPHERALS | DIAG_DEBUG_DCI |
- DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE;
+ DIAG_DEBUG_MHI | DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE;
}
#else
static void diag_debug_init(void)
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index d4af0e6..7635f6d 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -111,7 +111,7 @@ static int diagfwd_bridge_mux_write_done(unsigned char *buf, int len,
return -EINVAL;
ch = &bridge_info[buf_ctx];
if (ch->dev_ops && ch->dev_ops->fwd_complete) {
- DIAG_LOG(DIAG_DEBUG_MHI,
+ DIAG_LOG(DIAG_DEBUG_BRIDGE,
"Write done completion received for buf %pK len:%d\n",
buf, len);
ch->dev_ops->fwd_complete(ch->id, ch->ctxt, buf, len, 0);
diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c
index 39eb9c1..4cdda50 100644
--- a/drivers/char/diag/diagfwd_mhi.c
+++ b/drivers/char/diag/diagfwd_mhi.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/slab.h>
@@ -192,9 +192,12 @@ static void mhi_buf_tbl_remove(struct diag_mhi_info *mhi_info, int type,
list_del(&item->link);
if (type == TYPE_MHI_READ_CH) {
DIAG_LOG(DIAG_DEBUG_MHI,
- "Callback received on buffer:%pK from mhi\n", buf);
+ "Freeing read channel buffer: %pK\n", buf);
diagmem_free(driver, item->buf, mhi_info->mempool);
}
+ DIAG_LOG(DIAG_DEBUG_MHI,
+ "Removing %s channel item entry from table: %pK\n",
+ mhi_info->name, buf);
kfree(item);
found = 1;
}
@@ -232,7 +235,7 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info)
&mhi_info->read_done_list, link) {
if (tp->buf == buf) {
DIAG_LOG(DIAG_DEBUG_MHI,
- "buffer:%pK removed from table for ch:%s\n",
+ "Read buffer:%pK removed from table for ch:%s\n",
buf, mhi_info->name);
list_del(&tp->link);
kfree(tp);
@@ -254,6 +257,9 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info)
item = list_entry(start, struct diag_mhi_buf_tbl_t,
link);
list_del(&item->link);
+ DIAG_LOG(DIAG_DEBUG_MHI,
+ "Write buffer %pK removed from table for ch: %s\n",
+ buf, mhi_info->name);
diag_remote_dev_write_done(mhi_info->dev_id, item->buf,
item->len, mhi_info->id);
kfree(item);
@@ -280,6 +286,9 @@ static int __mhi_close(struct diag_mhi_info *mhi_info, int close_flag)
if (close_flag == CLOSE_CHANNELS) {
mutex_lock(&mhi_info->ch_mutex);
+ DIAG_LOG(DIAG_DEBUG_MHI,
+ "diag: %s mhi channel closed, calling mhi unprepare\n",
+ mhi_info->name);
mhi_unprepare_from_transfer(mhi_info->mhi_dev);
mutex_unlock(&mhi_info->ch_mutex);
}
@@ -293,15 +302,20 @@ static int mhi_close(int token, int ch)
int dev_idx = get_id_from_token(token);
if (dev_idx < 0 || dev_idx >= NUM_MHI_DEV) {
- pr_err("diag: In %s, invalid index %d\n", __func__, dev_idx);
+ pr_err("diag: %s: invalid index %d\n", __func__, dev_idx);
return -EINVAL;
}
- if (ch < 0 || ch >= NUM_MHI_CHAN)
- pr_err("diag: In %s, invalid channel %d\n", __func__, ch);
+ if (ch < 0 || ch >= NUM_MHI_CHAN) {
+ pr_err("diag: %s: invalid channel %d\n", __func__, ch);
+ return -EINVAL;
+ }
- if (!diag_mhi[dev_idx][ch].enabled)
+ if (!diag_mhi[dev_idx][ch].enabled) {
+ pr_err("diag: %s: invalid device node for index: %d, ch: %d\n",
+ __func__, dev_idx, ch);
return -ENODEV;
+ }
/*
* This function is called whenever the channel needs to be closed
* explicitly by Diag. Close both the read and write channels (denoted
@@ -334,9 +348,16 @@ static int __mhi_open(struct diag_mhi_info *mhi_info, int token, int open_flag)
return -ENODEV;
if (open_flag == OPEN_CHANNELS) {
if ((atomic_read(&(mhi_info->read_ch.opened))) &&
- (atomic_read(&(mhi_info->write_ch.opened))))
+ (atomic_read(&(mhi_info->write_ch.opened)))) {
+ DIAG_LOG(DIAG_DEBUG_MHI,
+ "Read and write channel already open: %s\n",
+ mhi_info->name);
return 0;
+ }
mutex_lock(&mhi_info->ch_mutex);
+ DIAG_LOG(DIAG_DEBUG_MHI,
+ "Prepare mhi for transfer on port: %s\n",
+ mhi_info->name);
err = mhi_prepare_for_transfer(mhi_info->mhi_dev);
mutex_unlock(&mhi_info->ch_mutex);
if (err) {
@@ -346,9 +367,9 @@ static int __mhi_open(struct diag_mhi_info *mhi_info, int token, int open_flag)
}
atomic_set(&mhi_info->read_ch.opened, 1);
atomic_set(&mhi_info->write_ch.opened, 1);
- DIAG_LOG(DIAG_DEBUG_BRIDGE,
- "opened mhi read/write channel, port: %d\n",
- mhi_info->id);
+ DIAG_LOG(DIAG_DEBUG_MHI,
+ "opened mhi read/write channel, port: %s\n",
+ mhi_info->name);
} else if (open_flag == CHANNELS_OPENED) {
if (!atomic_read(&(mhi_info->read_ch.opened)) ||
!atomic_read(&(mhi_info->write_ch.opened))) {
@@ -438,7 +459,7 @@ static void mhi_read_done_work_fn(struct work_struct *work)
spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags);
if (!buf)
break;
- DIAG_LOG(DIAG_DEBUG_BRIDGE,
+ DIAG_LOG(DIAG_DEBUG_MHI,
"read from mhi port %d buf %pK len:%d\n",
mhi_info->id, buf, len);
/*
@@ -504,7 +525,7 @@ static void mhi_read_work_fn(struct work_struct *work)
goto fail;
}
- DIAG_LOG(DIAG_DEBUG_BRIDGE,
+ DIAG_LOG(DIAG_DEBUG_MHI,
"queueing a read buf %pK, ch: %s\n",
buf, mhi_info->name);
@@ -553,54 +574,65 @@ static int mhi_write(int token, int ch, unsigned char *buf, int len, int ctxt)
unsigned long flags;
struct diag_mhi_ch_t *ch_info = NULL;
int dev_idx = get_id_from_token(token);
+ struct diag_mhi_info *mhi_info = NULL;
if (dev_idx < 0 || dev_idx >= NUM_MHI_DEV) {
- pr_err_ratelimited("diag: In %s, invalid index %d\n", __func__,
+ pr_err_ratelimited("diag: %s: invalid index %d\n", __func__,
dev_idx);
return -EINVAL;
}
if (ch < 0 || ch >= NUM_MHI_CHAN) {
- pr_err_ratelimited("diag: In %s, invalid chan %d\n", __func__,
+ pr_err_ratelimited("diag: %s: invalid chan %d\n", __func__,
ch);
return -EINVAL;
}
if (!buf || len <= 0) {
- pr_err("diag: In %s, ch %d, invalid buf %pK len %d\n",
+ pr_err("diag: %s: ch: %d, invalid buf %pK len %d\n",
__func__, dev_idx, buf, len);
return -EINVAL;
}
- if (!diag_mhi[dev_idx][ch].enabled) {
- pr_err_ratelimited("diag: In %s, MHI channel %s is not enabled\n",
- __func__, diag_mhi[dev_idx][ch].name);
+ mhi_info = &diag_mhi[dev_idx][ch];
+
+ if (!mhi_info) {
+ pr_err_ratelimited("diag: %s, Invalid MHI info\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (!mhi_info->enabled) {
+ pr_err_ratelimited("diag: %s: MHI channel %s is not enabled\n",
+ __func__, mhi_info->name);
return -EIO;
}
- ch_info = &diag_mhi[dev_idx][ch].write_ch;
+ ch_info = &mhi_info->write_ch;
if (!(atomic_read(&(ch_info->opened)))) {
- pr_err_ratelimited("diag: In %s, MHI write channel %s is not open\n",
- __func__, diag_mhi[dev_idx][ch].name);
+ pr_err_ratelimited("diag: %s: MHI write channel %s is not open\n",
+ __func__, mhi_info->name);
return -EIO;
}
spin_lock_irqsave(&ch_info->lock, flags);
- err = mhi_buf_tbl_add(&diag_mhi[dev_idx][ch], TYPE_MHI_WRITE_CH, buf,
+ err = mhi_buf_tbl_add(mhi_info, TYPE_MHI_WRITE_CH, buf,
len);
if (err) {
spin_unlock_irqrestore(&ch_info->lock, flags);
goto fail;
}
+ DIAG_LOG(DIAG_DEBUG_MHI, "diag: queueing a write buf %pK, ch: %s\n",
+ buf, mhi_info->name);
- err = mhi_queue_transfer(diag_mhi[dev_idx][ch].mhi_dev, DMA_TO_DEVICE,
+ err = mhi_queue_transfer(mhi_info->mhi_dev, DMA_TO_DEVICE,
buf, len, mhi_flags);
spin_unlock_irqrestore(&ch_info->lock, flags);
if (err) {
DIAG_LOG(DIAG_DEBUG_MHI,
- "diag: Cannot write to MHI channel %s, len %d, err: %d\n",
- __func__, diag_mhi[dev_idx][ch].name, len, err);
- mhi_buf_tbl_remove(&diag_mhi[dev_idx][ch], TYPE_MHI_WRITE_CH,
+ "diag: Cannot write to MHI channel: %s, len %d, err: %d\n",
+ mhi_info->name, len, err);
+ mhi_buf_tbl_remove(mhi_info, TYPE_MHI_WRITE_CH,
buf, len);
goto fail;
}
@@ -688,7 +720,7 @@ static void diag_mhi_read_cb(struct mhi_device *mhi_dev,
spin_lock_irqsave(&mhi_info->read_ch.lock, flags);
tp = kmalloc(sizeof(*tp), GFP_ATOMIC);
if (!tp) {
- DIAG_LOG(DIAG_DEBUG_BRIDGE,
+ DIAG_LOG(DIAG_DEBUG_MHI,
"no mem for list\n");
spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags);
return;
@@ -697,7 +729,7 @@ static void diag_mhi_read_cb(struct mhi_device *mhi_dev,
&mhi_info->read_ch.buf_tbl, link) {
if (item->buf == buf) {
DIAG_LOG(DIAG_DEBUG_MHI,
- "Callback received on buffer:%pK from mhi\n",
+ "Read callback received on buffer:%pK from mhi\n",
buf);
tp->buf = buf;
tp->len = result->bytes_xferd;
@@ -737,6 +769,9 @@ static void diag_mhi_write_cb(struct mhi_device *mhi_dev,
__func__);
return;
}
+ DIAG_LOG(DIAG_DEBUG_MHI,
+ "Write callback received on buffer:%pK from mhi\n",
+ buf);
mhi_buf_tbl_remove(mhi_info, TYPE_MHI_WRITE_CH, buf,
result->bytes_xferd);
diag_remote_dev_write_done(mhi_info->dev_id, buf,
@@ -756,6 +791,11 @@ static void diag_mhi_remove(struct mhi_device *mhi_dev)
return;
if (!mhi_info->enabled)
return;
+
+ DIAG_LOG(DIAG_DEBUG_MHI,
+ "Remove called on mhi channel: %s\n",
+ mhi_info->name);
+
__mhi_close(mhi_info, CHANNELS_CLOSED);
spin_lock_irqsave(&mhi_info->lock, flags);
mhi_info->enabled = 0;
@@ -796,11 +836,11 @@ static int diag_mhi_probe(struct mhi_device *mhi_dev,
}
mhi_info = &diag_mhi[dev_idx][ch];
- DIAG_LOG(DIAG_DEBUG_BRIDGE,
+ DIAG_LOG(DIAG_DEBUG_MHI,
"received probe for dev:%d ch:%d\n",
dev_idx, ch);
mhi_info->mhi_dev = mhi_dev;
- DIAG_LOG(DIAG_DEBUG_BRIDGE,
+ DIAG_LOG(DIAG_DEBUG_MHI,
"diag: mhi device is ready to open\n");
spin_lock_irqsave(&mhi_info->lock, flags);
mhi_info->enabled = 1;
@@ -884,7 +924,7 @@ int diag_mhi_init(void)
ch, dev_idx, err);
goto fail;
}
- DIAG_LOG(DIAG_DEBUG_BRIDGE,
+ DIAG_LOG(DIAG_DEBUG_MHI,
"mhi dev %d port %d initialized\n",
dev_idx, ch);
}
diff --git a/drivers/char/hw_random/omap3-rom-rng.c b/drivers/char/hw_random/omap3-rom-rng.c
index 38b7190..648e39c 100644
--- a/drivers/char/hw_random/omap3-rom-rng.c
+++ b/drivers/char/hw_random/omap3-rom-rng.c
@@ -121,7 +121,8 @@ static int omap3_rom_rng_remove(struct platform_device *pdev)
{
cancel_delayed_work_sync(&idle_work);
hwrng_unregister(&omap3_rom_rng_ops);
- clk_disable_unprepare(rng_clk);
+ if (!rng_idle)
+ clk_disable_unprepare(rng_clk);
return 0;
}
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 84c17f9..91f2d92 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -447,6 +447,8 @@ enum ipmi_stat_indexes {
#define IPMI_IPMB_NUM_SEQ 64
struct ipmi_smi {
+ struct module *owner;
+
/* What interface number are we? */
int intf_num;
@@ -1139,6 +1141,11 @@ int ipmi_create_user(unsigned int if_num,
if (rv)
goto out_kfree;
+ if (!try_module_get(intf->owner)) {
+ rv = -ENODEV;
+ goto out_kfree;
+ }
+
/* Note that each existing user holds a refcount to the interface. */
kref_get(&intf->refcount);
@@ -1269,6 +1276,7 @@ static void _ipmi_destroy_user(struct ipmi_user *user)
}
kref_put(&intf->refcount, intf_free);
+ module_put(intf->owner);
}
int ipmi_destroy_user(struct ipmi_user *user)
@@ -2384,7 +2392,7 @@ static int __get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc)
* been recently fetched, this will just use the cached data. Otherwise
* it will run a new fetch.
*
- * Except for the first time this is called (in ipmi_register_smi()),
+ * Except for the first time this is called (in ipmi_add_smi()),
* this will always return good data;
*/
static int __bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc,
@@ -3304,10 +3312,11 @@ static void redo_bmc_reg(struct work_struct *work)
kref_put(&intf->refcount, intf_free);
}
-int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
- void *send_info,
- struct device *si_dev,
- unsigned char slave_addr)
+int ipmi_add_smi(struct module *owner,
+ const struct ipmi_smi_handlers *handlers,
+ void *send_info,
+ struct device *si_dev,
+ unsigned char slave_addr)
{
int i, j;
int rv;
@@ -3333,7 +3342,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
return rv;
}
-
+ intf->owner = owner;
intf->bmc = &intf->tmp_bmc;
INIT_LIST_HEAD(&intf->bmc->intfs);
mutex_init(&intf->bmc->dyn_mutex);
@@ -3440,7 +3449,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
return rv;
}
-EXPORT_SYMBOL(ipmi_register_smi);
+EXPORT_SYMBOL(ipmi_add_smi);
static void deliver_smi_err_response(struct ipmi_smi *intf,
struct ipmi_smi_msg *msg,
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
index 2eb88b0..673c6de 100644
--- a/drivers/clk/clk-gpio.c
+++ b/drivers/clk/clk-gpio.c
@@ -248,7 +248,7 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
else
clk = clk_register_gpio_gate(&pdev->dev, node->name,
parent_names ? parent_names[0] : NULL, gpiod,
- 0);
+ CLK_SET_RATE_PARENT);
if (IS_ERR(clk))
return PTR_ERR(clk);
diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c
index d40b63e7..b44c4cf 100644
--- a/drivers/clk/pxa/clk-pxa27x.c
+++ b/drivers/clk/pxa/clk-pxa27x.c
@@ -463,6 +463,7 @@ struct dummy_clk {
};
static struct dummy_clk dummy_clks[] __initdata = {
DUMMY_CLK(NULL, "pxa27x-gpio", "osc_32_768khz"),
+ DUMMY_CLK(NULL, "pxa-rtc", "osc_32_768khz"),
DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"),
DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"),
};
diff --git a/drivers/clk/qcom/camcc-kona.c b/drivers/clk/qcom/camcc-kona.c
index c661977..4f14288 100644
--- a/drivers/clk/qcom/camcc-kona.c
+++ b/drivers/clk/qcom/camcc-kona.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.*/
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.*/
#define pr_fmt(fmt) "clk: %s: " fmt, __func__
@@ -181,7 +181,7 @@ static const struct alpha_pll_config cam_cc_pll0_config = {
.alpha = 0x8000,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
- .config_ctl_hi1_val = 0x029A699C,
+ .config_ctl_hi1_val = 0x329A699C,
.user_ctl_val = 0x00003100,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x00000000,
@@ -257,7 +257,7 @@ static const struct alpha_pll_config cam_cc_pll1_config = {
.alpha = 0x4000,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
- .config_ctl_hi1_val = 0x029A699C,
+ .config_ctl_hi1_val = 0x329A699C,
.user_ctl_val = 0x00000100,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x00000000,
@@ -326,7 +326,7 @@ static const struct alpha_pll_config cam_cc_pll2_config_sm8250_v2 = {
.cal_l = 0x4B,
.alpha = 0x0,
.config_ctl_val = 0x08200920,
- .config_ctl_hi_val = 0x05008011,
+ .config_ctl_hi_val = 0x05002015,
.config_ctl_hi1_val = 0x00000000,
.user_ctl_val = 0x00000100,
.user_ctl_hi_val = 0x00000000,
@@ -347,9 +347,9 @@ static struct clk_alpha_pll cam_cc_pll2 = {
.vdd_class = &vdd_mx,
.num_rate_max = VDD_NUM,
.rate_max = (unsigned long[VDD_NUM]) {
- [VDD_LOWER] = 1600000000,
- [VDD_LOW] = 2000000000,
- [VDD_NOMINAL] = 2900000000,
+ [VDD_LOWER] = 1800000000,
+ [VDD_LOW] = 2400000000,
+ [VDD_NOMINAL] = 3000000000,
[VDD_HIGH] = 3600000000},
},
},
@@ -382,7 +382,7 @@ static const struct alpha_pll_config cam_cc_pll3_config = {
.alpha = 0x7555,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
- .config_ctl_hi1_val = 0x029A699C,
+ .config_ctl_hi1_val = 0x329A699C,
.user_ctl_val = 0x00000100,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x00000000,
@@ -437,7 +437,7 @@ static const struct alpha_pll_config cam_cc_pll4_config = {
.alpha = 0x7555,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
- .config_ctl_hi1_val = 0x029A699C,
+ .config_ctl_hi1_val = 0x329A699C,
.user_ctl_val = 0x00000100,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x00000000,
@@ -2803,6 +2803,7 @@ static int cam_cc_kona_probe(struct platform_device *pdev)
}
dev_info(&pdev->dev, "Registered CAM CC clocks\n");
+
return ret;
}
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index dcdba93..e104484 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -345,6 +345,8 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
if (clk_flags & CLK_SET_RATE_PARENT) {
rate = f->freq;
if (f->pre_div) {
+ if (!rate)
+ rate = req->rate;
rate /= 2;
rate *= f->pre_div + 1;
}
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index d1bdfe3..9e72243 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, Linaro Limited
- * Copyright (c) 2014, 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2016-2020, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -857,11 +857,109 @@ static const struct rpm_smd_clk_desc rpm_clk_bengal = {
.num_clks = ARRAY_SIZE(bengal_clks),
};
+DEFINE_CLK_SMD_RPM_XO_BUFFER(scuba, ln_bb_clk2, ln_bb_clk2_a, 0x2);
+DEFINE_CLK_SMD_RPM_XO_BUFFER(scuba, rf_clk3, rf_clk3_a, 6);
+
+DEFINE_CLK_SMD_RPM(scuba, qpic_clk, qpic_a_clk, RPM_SMD_QPIC_CLK, 0);
+
+/* Scuba */
+static struct clk_hw *scuba_clks[] = {
+ [RPM_SMD_XO_CLK_SRC] = &bengal_bi_tcxo.hw,
+ [RPM_SMD_XO_A_CLK_SRC] = &bengal_bi_tcxo_ao.hw,
+ [RPM_SMD_SNOC_CLK] = &bengal_snoc_clk.hw,
+ [RPM_SMD_SNOC_A_CLK] = &bengal_snoc_a_clk.hw,
+ [RPM_SMD_BIMC_CLK] = &bengal_bimc_clk.hw,
+ [RPM_SMD_BIMC_A_CLK] = &bengal_bimc_a_clk.hw,
+ [RPM_SMD_QDSS_CLK] = &bengal_qdss_clk.hw,
+ [RPM_SMD_QDSS_A_CLK] = &bengal_qdss_a_clk.hw,
+ [RPM_SMD_LN_BB_CLK2] = &scuba_ln_bb_clk2.hw,
+ [RPM_SMD_LN_BB_CLK2_A] = &scuba_ln_bb_clk2_a.hw,
+ [RPM_SMD_RF_CLK3] = &scuba_rf_clk3.hw,
+ [RPM_SMD_RF_CLK3_A] = &scuba_rf_clk3_a.hw,
+ [RPM_SMD_CNOC_CLK] = &bengal_cnoc_clk.hw,
+ [RPM_SMD_CNOC_A_CLK] = &bengal_cnoc_a_clk.hw,
+ [RPM_SMD_IPA_CLK] = &bengal_ipa_clk.hw,
+ [RPM_SMD_IPA_A_CLK] = &bengal_ipa_a_clk.hw,
+ [RPM_SMD_QUP_CLK] = &bengal_qup_clk.hw,
+ [RPM_SMD_QUP_A_CLK] = &bengal_qup_a_clk.hw,
+ [RPM_SMD_MMRT_CLK] = &bengal_mmrt_clk.hw,
+ [RPM_SMD_MMRT_A_CLK] = &bengal_mmrt_a_clk.hw,
+ [RPM_SMD_MMNRT_CLK] = &bengal_mmnrt_clk.hw,
+ [RPM_SMD_MMNRT_A_CLK] = &bengal_mmnrt_a_clk.hw,
+ [RPM_SMD_SNOC_PERIPH_CLK] = &bengal_snoc_periph_clk.hw,
+ [RPM_SMD_SNOC_PERIPH_A_CLK] = &bengal_snoc_periph_a_clk.hw,
+ [RPM_SMD_SNOC_LPASS_CLK] = &bengal_snoc_lpass_clk.hw,
+ [RPM_SMD_SNOC_LPASS_A_CLK] = &bengal_snoc_lpass_a_clk.hw,
+ [RPM_SMD_CE1_CLK] = &bengal_ce1_clk.hw,
+ [RPM_SMD_CE1_A_CLK] = &bengal_ce1_a_clk.hw,
+ [RPM_SMD_QPIC_CLK] = &scuba_qpic_clk.hw,
+ [RPM_SMD_QPIC_A_CLK] = &scuba_qpic_a_clk.hw,
+ [CNOC_MSMBUS_CLK] = &cnoc_msmbus_clk.hw,
+ [CNOC_MSMBUS_A_CLK] = &cnoc_msmbus_a_clk.hw,
+ [SNOC_KEEPALIVE_A_CLK] = &snoc_keepalive_a_clk.hw,
+ [CNOC_KEEPALIVE_A_CLK] = &cnoc_keepalive_a_clk.hw,
+ [SNOC_MSMBUS_CLK] = &snoc_msmbus_clk.hw,
+ [SNOC_MSMBUS_A_CLK] = &snoc_msmbus_a_clk.hw,
+ [BIMC_MSMBUS_CLK] = &bimc_msmbus_clk.hw,
+ [BIMC_MSMBUS_A_CLK] = &bimc_msmbus_a_clk.hw,
+ [CPP_MMNRT_MSMBUS_CLK] = &cpp_mmnrt_msmbus_clk.hw,
+ [CPP_MMNRT_MSMBUS_A_CLK] = &cpp_mmnrt_msmbus_a_clk.hw,
+ [JPEG_MMNRT_MSMBUS_CLK] = &jpeg_mmnrt_msmbus_clk.hw,
+ [JPEG_MMNRT_MSMBUS_A_CLK] = &jpeg_mmnrt_msmbus_a_clk.hw,
+ [VENUS_MMNRT_MSMBUS_CLK] = &venus_mmnrt_msmbus_clk.hw,
+ [VENUS_MMNRT_MSMBUS_A_CLK] = &venus_mmnrt_msmbus_a_clk.hw,
+ [ARM9_MMNRT_MSMBUS_CLK] = &arm9_mmnrt_msmbus_clk.hw,
+ [ARM9_MMNRT_MSMBUS_A_CLK] = &arm9_mmnrt_msmbus_a_clk.hw,
+ [VFE_MMRT_MSMBUS_CLK] = &vfe_mmrt_msmbus_clk.hw,
+ [VFE_MMRT_MSMBUS_A_CLK] = &vfe_mmrt_msmbus_a_clk.hw,
+ [MDP_MMRT_MSMBUS_CLK] = &mdp_mmrt_msmbus_clk.hw,
+ [MDP_MMRT_MSMBUS_A_CLK] = &mdp_mmrt_msmbus_a_clk.hw,
+ [QUP0_MSMBUS_SNOC_PERIPH_CLK] = &qup0_msmbus_snoc_periph_clk.hw,
+ [QUP0_MSMBUS_SNOC_PERIPH_A_CLK] = &qup0_msmbus_snoc_periph_a_clk.hw,
+ [QUP1_MSMBUS_SNOC_PERIPH_CLK] = &qup1_msmbus_snoc_periph_clk.hw,
+ [QUP1_MSMBUS_SNOC_PERIPH_A_CLK] = &qup1_msmbus_snoc_periph_a_clk.hw,
+ [DAP_MSMBUS_SNOC_PERIPH_CLK] = &dap_msmbus_snoc_periph_clk.hw,
+ [DAP_MSMBUS_SNOC_PERIPH_A_CLK] = &dap_msmbus_snoc_periph_a_clk.hw,
+ [SDC1_MSMBUS_SNOC_PERIPH_CLK] = &sdc1_msmbus_snoc_periph_clk.hw,
+ [SDC1_MSMBUS_SNOC_PERIPH_A_CLK] = &sdc1_msmbus_snoc_periph_a_clk.hw,
+ [SDC2_MSMBUS_SNOC_PERIPH_CLK] = &sdc2_msmbus_snoc_periph_clk.hw,
+ [SDC2_MSMBUS_SNOC_PERIPH_A_CLK] = &sdc2_msmbus_snoc_periph_a_clk.hw,
+ [CRYPTO_MSMBUS_SNOC_PERIPH_CLK] = &crypto_msmbus_snoc_periph_clk.hw,
+ [CRYPTO_MSMBUS_SNOC_PERIPH_A_CLK] =
+ &crypto_msmbus_snoc_periph_a_clk.hw,
+ [SDC1_SLV_MSMBUS_SNOC_PERIPH_CLK] =
+ &sdc1_slv_msmbus_snoc_periph_clk.hw,
+ [SDC1_SLV_MSMBUS_SNOC_PERIPH_A_CLK] =
+ &sdc1_slv_msmbus_snoc_periph_a_clk.hw,
+ [SDC2_SLV_MSMBUS_SNOC_PERIPH_CLK] =
+ &sdc2_slv_msmbus_snoc_periph_clk.hw,
+ [SDC2_SLV_MSMBUS_SNOC_PERIPH_A_CLK] =
+ &sdc2_slv_msmbus_snoc_periph_a_clk.hw,
+ [MCD_CE1_CLK] = &mcd_ce1_clk.hw,
+ [QCEDEV_CE1_CLK] = &qcedev_ce1_clk.hw,
+ [QCRYPTO_CE1_CLK] = &qcrypto_ce1_clk.hw,
+ [QSEECOM_CE1_CLK] = &qseecom_ce1_clk.hw,
+ [SCM_CE1_CLK] = &scm_ce1_clk.hw,
+ [CXO_SMD_OTG_CLK] = &bi_tcxo_otg_clk.hw,
+ [CXO_SMD_PIL_PRONTO_CLK] = &bi_tcxo_pil_pronto_clk.hw,
+ [CXO_SMD_PIL_MSS_CLK] = &bi_tcxo_pil_mss_clk.hw,
+ [CXO_SMD_WLAN_CLK] = &bi_tcxo_wlan_clk.hw,
+ [CXO_SMD_PIL_LPASS_CLK] = &bi_tcxo_pil_lpass_clk.hw,
+ [CXO_SMD_PIL_CDSP_CLK] = &bi_tcxo_pil_cdsp_clk.hw,
+};
+
+static const struct rpm_smd_clk_desc rpm_clk_scuba = {
+ .clks = scuba_clks,
+ .num_rpm_clks = RPM_SMD_QPIC_A_CLK,
+ .num_clks = ARRAY_SIZE(scuba_clks),
+};
+
static const struct of_device_id rpm_smd_clk_match_table[] = {
{ .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 },
{ .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 },
{ .compatible = "qcom,rpmcc-msm8996", .data = &rpm_clk_msm8996 },
{ .compatible = "qcom,rpmcc-bengal", .data = &rpm_clk_bengal},
+ { .compatible = "qcom,rpmcc-scuba", .data = &rpm_clk_scuba},
{ }
};
MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table);
@@ -872,15 +970,17 @@ static int rpm_smd_clk_probe(struct platform_device *pdev)
struct clk *clk;
struct rpm_cc *rcc;
struct clk_onecell_data *data;
- int ret, is_bengal;
+ int ret, is_bengal, is_scuba;
size_t num_clks, i;
struct clk_hw **hw_clks;
const struct rpm_smd_clk_desc *desc;
-
is_bengal = of_device_is_compatible(pdev->dev.of_node,
"qcom,rpmcc-bengal");
- if (is_bengal) {
+
+ is_scuba = of_device_is_compatible(pdev->dev.of_node,
+ "qcom,rpmcc-scuba");
+ if (is_bengal || is_scuba) {
ret = clk_vote_bimc(&bengal_bimc_clk.hw, INT_MAX);
if (ret < 0)
return ret;
@@ -949,7 +1049,7 @@ static int rpm_smd_clk_probe(struct platform_device *pdev)
if (ret)
goto err;
- if (is_bengal) {
+ if (is_bengal || is_scuba) {
/*
* Keep an active vote on CXO in case no other driver
* votes for it.
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index 1a87ad0..da45867 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -32,6 +32,9 @@ struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate)
if (!f)
return NULL;
+ if (!f->freq)
+ return f;
+
for (; f->freq; f++)
if (rate <= f->freq)
return f;
diff --git a/drivers/clk/qcom/dispcc-kona.c b/drivers/clk/qcom/dispcc-kona.c
index 5eb750c..7fe1886 100644
--- a/drivers/clk/qcom/dispcc-kona.c
+++ b/drivers/clk/qcom/dispcc-kona.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */
#define pr_fmt(fmt) "clk: %s: " fmt, __func__
@@ -208,10 +208,11 @@ static struct pll_vco lucid_vco[] = {
static const struct alpha_pll_config disp_cc_pll0_config = {
.l = 0x47,
+ .cal_l = 0x44,
.alpha = 0xE000,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
- .config_ctl_hi1_val = 0x029A699C,
+ .config_ctl_hi1_val = 0x329A699C,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x00000000,
@@ -241,10 +242,11 @@ static struct clk_alpha_pll disp_cc_pll0 = {
static const struct alpha_pll_config disp_cc_pll1_config = {
.l = 0x1F,
+ .cal_l = 0x44,
.alpha = 0x4000,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
- .config_ctl_hi1_val = 0x029A699C,
+ .config_ctl_hi1_val = 0x329A699C,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x00000000,
@@ -481,8 +483,7 @@ static struct clk_rcg2 disp_cc_mdss_dp_link1_clk_src = {
.num_rate_max = VDD_NUM,
.rate_max = (unsigned long[VDD_NUM]) {
[VDD_MIN] = 19200,
- [VDD_LOWER] = 162000,
- [VDD_LOW] = 270000,
+ [VDD_LOWER] = 270000,
[VDD_LOW_L1] = 540000,
[VDD_NOMINAL] = 810000},
},
@@ -504,8 +505,7 @@ static struct clk_rcg2 disp_cc_mdss_dp_link_clk_src = {
.num_rate_max = VDD_NUM,
.rate_max = (unsigned long[VDD_NUM]) {
[VDD_MIN] = 19200,
- [VDD_LOWER] = 162000,
- [VDD_LOW] = 270000,
+ [VDD_LOWER] = 270000,
[VDD_LOW_L1] = 540000,
[VDD_NOMINAL] = 810000},
},
@@ -527,7 +527,7 @@ static struct clk_rcg2 disp_cc_mdss_dp_pixel1_clk_src = {
.rate_max = (unsigned long[VDD_NUM]) {
[VDD_MIN] = 19200,
[VDD_LOWER] = 337500,
- [VDD_LOW_L1] = 675000},
+ [VDD_NOMINAL] = 675000},
},
};
@@ -547,7 +547,7 @@ static struct clk_rcg2 disp_cc_mdss_dp_pixel2_clk_src = {
.rate_max = (unsigned long[VDD_NUM]) {
[VDD_MIN] = 19200,
[VDD_LOWER] = 337500,
- [VDD_LOW_L1] = 675000},
+ [VDD_NOMINAL] = 675000},
},
};
diff --git a/drivers/clk/qcom/dispcc-lito.c b/drivers/clk/qcom/dispcc-lito.c
index 0d4f4b7..95c9264 100644
--- a/drivers/clk/qcom/dispcc-lito.c
+++ b/drivers/clk/qcom/dispcc-lito.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2019, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */
#define pr_fmt(fmt) "clk: %s: " fmt, __func__
@@ -144,9 +144,9 @@ static struct pll_vco lucid_vco[] = {
};
static const struct alpha_pll_config disp_cc_pll0_config = {
- .l = 0x47,
+ .l = 0x35,
.cal_l = 0x44,
- .alpha = 0xE000,
+ .alpha = 0xE800,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
.config_ctl_hi1_val = 0x329A699C,
@@ -456,7 +456,7 @@ static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = {
static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = {
F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
- F(345000000, P_DISP_CC_PLL0_OUT_MAIN, 4, 0, 0),
+ F(345000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
F(460000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
{ }
};
@@ -526,12 +526,18 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = {
},
};
+static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src[] = {
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
static struct clk_rcg2 disp_cc_mdss_rot_clk_src = {
.cmd_rcgr = 0x20e0,
.mnd_width = 0,
.hid_width = 5,
.parent_map = disp_cc_parent_map_3,
- .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src,
+ .freq_tbl = ftbl_disp_cc_mdss_rot_clk_src,
.enable_safe_config = true,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_rot_clk_src",
@@ -543,9 +549,7 @@ static struct clk_rcg2 disp_cc_mdss_rot_clk_src = {
.num_rate_max = VDD_NUM,
.rate_max = (unsigned long[VDD_NUM]) {
[VDD_LOWER] = 200000000,
- [VDD_LOW] = 300000000,
- [VDD_LOW_L1] = 345000000,
- [VDD_NOMINAL] = 460000000},
+ [VDD_LOW] = 300000000},
},
};
diff --git a/drivers/clk/qcom/gcc-bengal.c b/drivers/clk/qcom/gcc-bengal.c
index 69d1087..b8c5ea4 100644
--- a/drivers/clk/qcom/gcc-bengal.c
+++ b/drivers/clk/qcom/gcc-bengal.c
@@ -347,10 +347,11 @@ static struct pll_vco brammo_vco[] = {
};
static struct pll_vco default_vco[] = {
- { 1000000000, 2000000000, 0 },
- { 750000000, 1500000000, 1 },
{ 500000000, 1000000000, 2 },
- { 250000000, 500000000, 3 },
+};
+
+static struct pll_vco alpha_vco[] = {
+ { 750000000, 1500000000, 1 },
};
static const u8 clk_alpha_pll_regs_offset[][PLL_OFF_MAX_REGS] = {
@@ -452,8 +453,8 @@ static const struct alpha_pll_config gpll10_config = {
static struct clk_alpha_pll gpll10 = {
.offset = 0xa000,
- .vco_table = default_vco,
- .num_vco = ARRAY_SIZE(default_vco),
+ .vco_table = alpha_vco,
+ .num_vco = ARRAY_SIZE(alpha_vco),
.regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
.clkr = {
.enable_reg = 0x79000,
@@ -754,6 +755,7 @@ static struct clk_alpha_pll_postdiv gpll8_out_main = {
.name = "gpll8_out_main",
.parent_names = (const char *[]){ "gpll8" },
.num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
.ops = &clk_alpha_pll_postdiv_ro_ops,
},
};
diff --git a/drivers/clk/qcom/gpucc-kona.c b/drivers/clk/qcom/gpucc-kona.c
index d40b2f0..4e9c6a0 100644
--- a/drivers/clk/qcom/gpucc-kona.c
+++ b/drivers/clk/qcom/gpucc-kona.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.*/
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.*/
#define pr_fmt(fmt) "clk: %s: " fmt, __func__
@@ -66,13 +66,59 @@ static struct pll_vco lucid_vco[] = {
{ 249600000, 2000000000, 0 },
};
+static const struct alpha_pll_config gpu_cc_pll0_config = {
+ .l = 0x13,
+ .cal_l = 0x44,
+ .alpha = 0xCAAA,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x329A699C,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static const struct alpha_pll_config gpu_cc_pll0_config_sm8250_v2 = {
+ .l = 0x14,
+ .cal_l = 0x44,
+ .alpha = 0x5000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x329A699C,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll gpu_cc_pll0 = {
+ .offset = 0x0,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll0",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_ops,
+ .vdd_class = &vdd_mx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_MIN] = 615000000,
+ [VDD_LOW] = 1066000000,
+ [VDD_LOW_L1] = 1600000000,
+ [VDD_NOMINAL] = 2000000000},
+ },
+ },
+};
+
static const struct alpha_pll_config gpu_cc_pll1_config = {
.l = 0x1A,
.cal_l = 0x44,
.alpha = 0xAAA,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
- .config_ctl_hi1_val = 0x029A699C,
+ .config_ctl_hi1_val = 0x329A699C,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x00000000,
@@ -398,10 +444,33 @@ static const struct qcom_cc_desc gpu_cc_kona_desc = {
static const struct of_device_id gpu_cc_kona_match_table[] = {
{ .compatible = "qcom,gpucc-kona" },
+ { .compatible = "qcom,gpucc-kona-v2" },
{ }
};
MODULE_DEVICE_TABLE(of, gpu_cc_kona_match_table);
+static void gpu_cc_kona_fixup_konav2(struct regmap *regmap)
+{
+ clk_lucid_pll_configure(&gpu_cc_pll0, regmap,
+ &gpu_cc_pll0_config_sm8250_v2);
+}
+
+static int gpu_cc_kona_fixup(struct platform_device *pdev,
+ struct regmap *regmap)
+{
+ const char *compat = NULL;
+ int compatlen = 0;
+
+ compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+ if (!compat || (compatlen <= 0))
+ return -EINVAL;
+
+ if (!strcmp(compat, "qcom,gpucc-kona-v2"))
+ gpu_cc_kona_fixup_konav2(regmap);
+
+ return 0;
+}
+
static int gpu_cc_kona_probe(struct platform_device *pdev)
{
struct regmap *regmap;
@@ -435,6 +504,9 @@ static int gpu_cc_kona_probe(struct platform_device *pdev)
value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT;
regmap_update_bits(regmap, gpu_cc_cx_gmu_clk.clkr.enable_reg,
mask, value);
+ ret = gpu_cc_kona_fixup(pdev, regmap);
+ if (ret)
+ return ret;
ret = qcom_cc_really_probe(pdev, &gpu_cc_kona_desc, regmap);
if (ret) {
diff --git a/drivers/clk/qcom/npucc-lagoon.c b/drivers/clk/qcom/npucc-lagoon.c
index 1281e7d..3c35830 100644
--- a/drivers/clk/qcom/npucc-lagoon.c
+++ b/drivers/clk/qcom/npucc-lagoon.c
@@ -103,6 +103,10 @@ static const u32 crc_reg_val[] = {
CRC_MND_CFG_SETTING, CRC_SID_FSM_CTRL_SETTING,
};
+static struct pll_vco fabia_vco[] = {
+ { 249600000, 2000000000, 0 },
+};
+
/* 537.60MHz Configuration */
static struct alpha_pll_config npu_cc_pll0_config = {
.l = 0x1C,
@@ -119,6 +123,8 @@ static struct alpha_pll_config npu_cc_pll0_config = {
static struct clk_alpha_pll npu_cc_pll0 = {
.offset = 0x0,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
.config = &npu_cc_pll0_config,
.clkr = {
@@ -152,6 +158,8 @@ static struct alpha_pll_config npu_cc_pll1_config = {
static struct clk_alpha_pll npu_cc_pll1 = {
.offset = 0x400,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
.config = &npu_cc_pll1_config,
.clkr = {
@@ -185,6 +193,8 @@ static struct alpha_pll_config npu_q6ss_pll_config = {
static struct clk_alpha_pll npu_q6ss_pll = {
.offset = 0x0,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
.config = &npu_q6ss_pll_config,
.clkr = {
diff --git a/drivers/clk/qcom/videocc-kona.c b/drivers/clk/qcom/videocc-kona.c
index 4616556..c090961 100644
--- a/drivers/clk/qcom/videocc-kona.c
+++ b/drivers/clk/qcom/videocc-kona.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.*/
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.*/
#define pr_fmt(fmt) "clk: %s: " fmt, __func__
@@ -126,7 +126,7 @@ static const struct alpha_pll_config video_pll0_config = {
.alpha = 0x8000,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
- .config_ctl_hi1_val = 0x029A699C,
+ .config_ctl_hi1_val = 0x329A699C,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x00000000,
@@ -160,7 +160,7 @@ static const struct alpha_pll_config video_pll1_config = {
.alpha = 0xFAAA,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
- .config_ctl_hi1_val = 0x029A699C,
+ .config_ctl_hi1_val = 0x329A699C,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x00000000,
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 4d37f01..25e2967 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -376,6 +376,14 @@
the Allwinner A64 SoC. The workaround will only be active if the
allwinner,erratum-unknown1 property is found in the timer node.
+config ARM_ARCH_TIMER_VCT_ACCESS
+ bool "Support for ARM architected timer virtual counter access in userspace"
+ default n
+ depends on ARM_ARCH_TIMER
+ help
+ This option enables support for reading the ARM architected timer's
+ virtual counter in userspace.
+
config ARM_GLOBAL_TIMER
bool "Support for the ARM global timer" if COMPILE_TEST
select TIMER_OF if OF
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 924a14d..c7f38cf 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -29,6 +29,7 @@
#include <linux/acpi.h>
#include <asm/arch_timer.h>
+#include <asm/traps.h>
#include <asm/virt.h>
#include <clocksource/arm_arch_timer.h>
@@ -871,7 +872,8 @@ static void arch_counter_set_user_access(void)
* need to be workaround. The vdso may have been already
* disabled though.
*/
- if (arch_timer_this_cpu_has_cntvct_wa())
+ if (arch_timer_this_cpu_has_cntvct_wa() ||
+ !IS_ENABLED(CONFIG_ARM_ARCH_TIMER_VCT_ACCESS))
pr_info("CPU%d: Trapping CNTVCT access\n", smp_processor_id());
else
cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
@@ -1519,6 +1521,8 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
ret = arch_timer_mem_frame_register(frame);
if (!ret && !arch_timer_needs_of_probing())
ret = arch_timer_common_init();
+ get_timer_count_hook_init();
+ get_timer_freq_hook_init();
out:
kfree(timer_mem);
return ret;
diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c
index 38cd2fe..0ce7607 100644
--- a/drivers/clocksource/asm9260_timer.c
+++ b/drivers/clocksource/asm9260_timer.c
@@ -198,6 +198,10 @@ static int __init asm9260_timer_init(struct device_node *np)
}
clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ pr_err("Failed to get clk!\n");
+ return PTR_ERR(clk);
+ }
ret = clk_prepare_enable(clk);
if (ret) {
diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c
index 06ed88a..6e2cb36 100644
--- a/drivers/clocksource/timer-of.c
+++ b/drivers/clocksource/timer-of.c
@@ -199,7 +199,7 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to)
}
if (!to->clkevt.name)
- to->clkevt.name = np->name;
+ to->clkevt.name = np->full_name;
to->np = np;
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 5864245..2ca0cab 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -310,6 +310,16 @@
The driver implements the cpufreq interface for this HW engine.
Say Y if you want to support CPUFreq HW.
+config ARM_QCOM_CPUFREQ_HW_DEBUG
+ bool "QCOM CPUFreq HW debug"
+ depends on ARM_QCOM_CPUFREQ_HW
+ help
+ Support for the CPUFreq HW debug.
+ CPUFreq HW debug provide the support to capture trace packets for
+ various clock domain and trace type could be set to periodic and
+ xor if applicable.
+ Say Y if you want to support CPUFreq HW Trace.
+
config CPU_FREQ_MSM
bool "MSM CPUFreq support"
depends on CPU_FREQ
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index cc98603..addf17b 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -91,6 +91,7 @@
obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o
obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o
+obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW_DEBUG) += qcom-cpufreq-hw-debug.o
##################################################################################
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 5c02ee1..b050316 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2522,6 +2522,13 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
if (cpufreq_disabled())
return -ENODEV;
+ /*
+ * The cpufreq core depends heavily on the availability of device
+ * structure, make sure they are available before proceeding further.
+ */
+ if (!get_cpu_device(0))
+ return -EPROBE_DEFER;
+
if (!driver_data || !driver_data->verify || !driver_data->init ||
!(driver_data->setpolicy || driver_data->target_index ||
driver_data->target) ||
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index f4880a4..d8c3595 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -12,6 +12,7 @@
#include <linux/cpu_cooling.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_opp.h>
@@ -295,20 +296,32 @@ static void imx6q_opp_check_speed_grading(struct device *dev)
#define OCOTP_CFG3_6ULL_SPEED_792MHZ 0x2
#define OCOTP_CFG3_6ULL_SPEED_900MHZ 0x3
-static void imx6ul_opp_check_speed_grading(struct device *dev)
+static int imx6ul_opp_check_speed_grading(struct device *dev)
{
- struct device_node *np;
- void __iomem *base;
u32 val;
+ int ret = 0;
- np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp");
- if (!np)
- return;
+ if (of_find_property(dev->of_node, "nvmem-cells", NULL)) {
+ ret = nvmem_cell_read_u32(dev, "speed_grade", &val);
+ if (ret)
+ return ret;
+ } else {
+ struct device_node *np;
+ void __iomem *base;
- base = of_iomap(np, 0);
- if (!base) {
- dev_err(dev, "failed to map ocotp\n");
- goto put_node;
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp");
+ if (!np)
+ return -ENOENT;
+
+ base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!base) {
+ dev_err(dev, "failed to map ocotp\n");
+ return -EFAULT;
+ }
+
+ val = readl_relaxed(base + OCOTP_CFG3);
+ iounmap(base);
}
/*
@@ -319,7 +332,6 @@ static void imx6ul_opp_check_speed_grading(struct device *dev)
* 2b'11: 900000000Hz on i.MX6ULL only;
* We need to set the max speed of ARM according to fuse map.
*/
- val = readl_relaxed(base + OCOTP_CFG3);
val >>= OCOTP_CFG3_SPEED_SHIFT;
val &= 0x3;
@@ -339,9 +351,7 @@ static void imx6ul_opp_check_speed_grading(struct device *dev)
dev_warn(dev, "failed to disable 900MHz OPP\n");
}
- iounmap(base);
-put_node:
- of_node_put(np);
+ return ret;
}
static int imx6q_cpufreq_probe(struct platform_device *pdev)
@@ -399,10 +409,18 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
}
if (of_machine_is_compatible("fsl,imx6ul") ||
- of_machine_is_compatible("fsl,imx6ull"))
- imx6ul_opp_check_speed_grading(cpu_dev);
- else
+ of_machine_is_compatible("fsl,imx6ull")) {
+ ret = imx6ul_opp_check_speed_grading(cpu_dev);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ if (ret) {
+ dev_err(cpu_dev, "failed to read ocotp: %d\n",
+ ret);
+ return ret;
+ }
+ } else {
imx6q_opp_check_speed_grading(cpu_dev);
+ }
/* Because we have added the OPPs here, we must free them */
free_opp = true;
diff --git a/drivers/cpufreq/qcom-cpufreq-hw-debug.c b/drivers/cpufreq/qcom-cpufreq-hw-debug.c
new file mode 100644
index 0000000..d51acca
--- /dev/null
+++ b/drivers/cpufreq/qcom-cpufreq-hw-debug.c
@@ -0,0 +1,624 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#define pr_fmt(fmt) "cpufreq_hw_debug: %s: " fmt, __func__
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/uaccess.h>
+#include <soc/qcom/scm.h>
+
+enum trace_type {
+ XOR_PACKET,
+ PERIODIC_PACKET,
+};
+
+enum clock_domain {
+ CLKDOM0,
+ CLKDOM1,
+ CLKDOM2,
+ CLKDOM3,
+
+ CLK_DOMAIN_SIZE,
+};
+
+enum debug_trace_regs_data {
+ GLOBAL_CTRL_OFFSET,
+ CLKDOM_CTRL_OFFSET,
+ PERIODIC_TIMER_CTRL_OFFSET,
+
+ PERIODIC_TRACE_ENABLE_BIT,
+ CPUFREQ_HW_TRACE_ENABLE_BIT,
+
+ REG_PERF_STATE,
+ REG_CYCLE_CNTR,
+ REG_PSTATE_STATUS,
+
+ REG_ARRAY_SIZE,
+};
+
+struct cpufreq_hwregs {
+ void __iomem *base[REG_ARRAY_SIZE];
+ int domain_cnt;
+ struct dentry *debugfs_base;
+};
+
+struct cpufreq_register_data {
+ char *name;
+ u16 offset;
+};
+
+#define CLKDOM0_TRACE_PACKET_SHIFT 0
+#define CLKDOM1_TRACE_PACKET_SHIFT 3
+#define CLKDOM2_TRACE_PACKET_SHIFT 6
+#define CLKDOM3_TRACE_PACKET_SHIFT 9
+#define CLKDOM_TRACE_PACKET_WIDTH 2
+#define MAX_DEBUG_BUF_LEN 50
+#define MAX_PKT_SIZE 5
+#define CLKDOMAIN_SET_VAL(val, packet_sel, shift) \
+ ((val & ~GENMASK(shift + CLKDOM_TRACE_PACKET_WIDTH, shift)) \
+ | (packet_sel << shift))
+#define CLKDOMAIN_CLEAR_VAL(val, packet_sel, shift) \
+ ((val & ~GENMASK(shift + CLKDOM_TRACE_PACKET_WIDTH, shift)))
+
+static struct cpufreq_hwregs *hw_regs;
+static char debug_buf[MAX_DEBUG_BUF_LEN];
+static const u16 *offsets;
+
+static const u16 cpufreq_qcom_std_data[REG_ARRAY_SIZE] = {
+ [GLOBAL_CTRL_OFFSET] = 0x10,
+ [CLKDOM_CTRL_OFFSET] = 0x14,
+ [PERIODIC_TIMER_CTRL_OFFSET] = 0x1C,
+ [REG_PERF_STATE] = 0x920,
+ [REG_CYCLE_CNTR] = 0x9c0,
+ [REG_PSTATE_STATUS] = 0x700,
+ [CPUFREQ_HW_TRACE_ENABLE_BIT] = 16,
+ [PERIODIC_TRACE_ENABLE_BIT] = 17,
+};
+
+static const u16 cpufreq_qcom_std_epss_data[REG_ARRAY_SIZE] = {
+ [REG_PERF_STATE] = 0x320,
+ [REG_CYCLE_CNTR] = 0x3c4,
+ [REG_PSTATE_STATUS] = 0x020,
+};
+
+static int clock_timer_set(void *data, u64 val)
+{
+ u32 base;
+ int ret;
+
+ if (!data)
+ return -EINVAL;
+
+ base = *((u32 *)data);
+
+ ret = scm_io_write(base + offsets[PERIODIC_TIMER_CTRL_OFFSET], val);
+ if (ret)
+ pr_err("failed(0x%x) to set clk timer\n", ret);
+
+ return ret;
+}
+
+static int clock_timer_get(void *data, u64 *val)
+{
+ u32 base;
+
+ if (!data)
+ return -EINVAL;
+
+ base = *((u32 *)data);
+
+ *val = scm_io_read(base + offsets[PERIODIC_TIMER_CTRL_OFFSET]);
+
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(clock_timer_fops, clock_timer_get, clock_timer_set,
+ "%llu\n");
+
+static ssize_t trace_type_set(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ u32 regval, base;
+ int ret;
+
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ if (!file->private_data)
+ return -EINVAL;
+
+ base = *((u32 *)file->private_data);
+
+ if (count < MAX_DEBUG_BUF_LEN) {
+ if (copy_from_user(debug_buf, (void __user *) buf,
+ MAX_DEBUG_BUF_LEN))
+ return -EFAULT;
+ }
+ debug_buf[count] = '\0';
+
+ regval = scm_io_read(base + offsets[GLOBAL_CTRL_OFFSET]);
+ if (!strcmp(debug_buf, "periodic\n")) {
+ regval |= BIT(offsets[PERIODIC_TRACE_ENABLE_BIT]);
+ } else if (!strcmp(debug_buf, "xor\n")) {
+ regval &= ~BIT(offsets[PERIODIC_TRACE_ENABLE_BIT]);
+ } else {
+ pr_err("error, supported trace mode types: 'periodic' or 'xor'\n");
+ return -EINVAL;
+ }
+
+ ret = scm_io_write(base + offsets[GLOBAL_CTRL_OFFSET], regval);
+ if (ret)
+ pr_err("failed(0x%x) to set cpufreq clk timer\n", ret);
+
+ return count;
+}
+
+static ssize_t trace_type_get(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ int len;
+ u32 regval, base;
+
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ if (!file->private_data)
+ return -EINVAL;
+
+ base = *((u32 *)file->private_data);
+
+ regval = scm_io_read(base + offsets[GLOBAL_CTRL_OFFSET]);
+ if (regval && offsets[PERIODIC_TRACE_ENABLE_BIT])
+ len = snprintf(debug_buf, sizeof(debug_buf), "periodic\n");
+ else
+ len = snprintf(debug_buf, sizeof(debug_buf), "xor\n");
+
+ return simple_read_from_buffer((void __user *) buf, count, ppos,
+ (void *) debug_buf, len);
+}
+
+static int trace_type_open(struct inode *inode, struct file *file)
+{
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ file->private_data = inode->i_private;
+
+ return 0;
+}
+
+static const struct file_operations clk_trace_type_fops = {
+ .read = trace_type_get,
+ .open = trace_type_open,
+ .write = trace_type_set,
+};
+
+void __domain_packet_set(u32 *clkdom_regval, u32 *pktsel_regval, int clkdomain,
+ int pktsel, int packet_sel_shift, int enable)
+{
+ if (!!enable) {
+ *clkdom_regval |= BIT(clkdomain);
+ *pktsel_regval = CLKDOMAIN_SET_VAL(*pktsel_regval, pktsel,
+ packet_sel_shift);
+ } else {
+ *clkdom_regval &= ~BIT(clkdomain);
+ *pktsel_regval &= CLKDOMAIN_CLEAR_VAL(*pktsel_regval, pktsel,
+ packet_sel_shift);
+ }
+}
+
+static ssize_t domain_packet_set(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned int filled, clk_domain, packet_sel, enable = 1;
+ u32 clkdom_regval, pktsel_regval, base;
+ char buf[MAX_DEBUG_BUF_LEN];
+ int ret;
+
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ if (!file->private_data)
+ return -EINVAL;
+
+ base = *((u32 *)file->private_data);
+
+ if (count < MAX_DEBUG_BUF_LEN) {
+ if (copy_from_user(buf, ubuf, count))
+ return -EFAULT;
+ }
+
+ buf[count] = '\0';
+ filled = sscanf(buf, "%u %u %u", &clk_domain, &packet_sel, &enable);
+ if (clk_domain > CLK_DOMAIN_SIZE || packet_sel > MAX_PKT_SIZE) {
+ pr_err("Clock domain and source selection not in range\n");
+ return -EINVAL;
+ }
+
+ clkdom_regval = scm_io_read(base + offsets[GLOBAL_CTRL_OFFSET]);
+ pktsel_regval = scm_io_read(base + offsets[CLKDOM_CTRL_OFFSET]);
+
+
+ switch (clk_domain) {
+ case CLKDOM0:
+ __domain_packet_set(&clkdom_regval, &pktsel_regval, CLKDOM0,
+ packet_sel, CLKDOM0_TRACE_PACKET_SHIFT, enable);
+ break;
+ case CLKDOM1:
+ __domain_packet_set(&clkdom_regval, &pktsel_regval, CLKDOM1,
+ packet_sel, CLKDOM1_TRACE_PACKET_SHIFT, enable);
+ break;
+ case CLKDOM2:
+ __domain_packet_set(&clkdom_regval, &pktsel_regval, CLKDOM2,
+ packet_sel, CLKDOM2_TRACE_PACKET_SHIFT, enable);
+ break;
+ case CLKDOM3:
+ __domain_packet_set(&clkdom_regval, &pktsel_regval, CLKDOM3,
+ packet_sel, CLKDOM3_TRACE_PACKET_SHIFT, enable);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = scm_io_write(base + offsets[GLOBAL_CTRL_OFFSET], clkdom_regval);
+ if (ret)
+ pr_err("failed(0x%x) to set cpufreq domain\n", ret);
+
+ ret = scm_io_write(base + offsets[CLKDOM_CTRL_OFFSET], pktsel_regval);
+ if (ret)
+ pr_err("failed(0x%x) to set cpufreq trace packet\n", ret);
+
+ return count;
+}
+
+static ssize_t domain_packet_get(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ u32 base, clkdom_regval, pktsel_regval;
+ int len;
+
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ if (!file->private_data)
+ return -EINVAL;
+
+ base = *((u32 *)file->private_data);
+
+ clkdom_regval = scm_io_read(base + offsets[GLOBAL_CTRL_OFFSET]);
+ pktsel_regval = scm_io_read(base + offsets[CLKDOM_CTRL_OFFSET]);
+
+ len = snprintf(debug_buf, sizeof(debug_buf),
+ "GLOBAL_TRACE_CTRL = 0x%x\nCLKDOM_TRACE_CTRL = 0x%x\n",
+ clkdom_regval, pktsel_regval);
+
+ return simple_read_from_buffer((void __user *) buf, count, ppos,
+ (void *) debug_buf, len);
+}
+
+static int domain_packet_open(struct inode *inode, struct file *file)
+{
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ file->private_data = inode->i_private;
+
+ return 0;
+}
+
+static const struct file_operations clock_domian_packet_set = {
+ .write = domain_packet_set,
+ .open = domain_packet_open,
+ .read = domain_packet_get,
+};
+
+static int cpufreq_hw_trace_enable_set(void *data, u64 val)
+{
+ u32 regval, base;
+ int ret;
+
+ if (!data)
+ return -EINVAL;
+
+ base = *((u32 *)data);
+
+ regval = scm_io_read(base + offsets[GLOBAL_CTRL_OFFSET]);
+ if (!!val)
+ regval |= BIT(offsets[CPUFREQ_HW_TRACE_ENABLE_BIT]);
+ else
+ regval &= ~BIT(offsets[CPUFREQ_HW_TRACE_ENABLE_BIT]);
+
+ ret = scm_io_write(base + offsets[GLOBAL_CTRL_OFFSET], regval);
+ if (ret)
+ pr_err("failed(0x%x) to set cpufreq hw trace\n", ret);
+
+ return ret;
+}
+
+static int cpufreq_hw_trace_enable_get(void *data, u64 *val)
+{
+ u32 regval, base;
+
+ if (!data)
+ return -EINVAL;
+
+ base = *((u32 *)data);
+
+ regval = scm_io_read(base + offsets[GLOBAL_CTRL_OFFSET]);
+ *val = (regval & BIT(offsets[CPUFREQ_HW_TRACE_ENABLE_BIT])) >>
+ offsets[CPUFREQ_HW_TRACE_ENABLE_BIT];
+
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(clock_trace_enable, cpufreq_hw_trace_enable_get,
+ cpufreq_hw_trace_enable_set, "%llu\n");
+
+static int print_cpufreq_hw_trace_regs(struct seq_file *s, void *unused)
+{
+ u32 base;
+ int i;
+
+ static struct cpufreq_register_data data[] = {
+ {"GLOBAL_TRACE_CTRL", GLOBAL_CTRL_OFFSET},
+ {"CLKDOM_TRACE_CTRL", CLKDOM_CTRL_OFFSET},
+ {"PERIODIC_TIMER_TIMER", PERIODIC_TIMER_CTRL_OFFSET},
+ };
+
+ if (!s->private)
+ return -EINVAL;
+
+ base = *((u32 *)s->private);
+
+ for (i = 0; i < ARRAY_SIZE(data); i++) {
+ seq_printf(s, "%25s: 0x%.8x\n", data[i].name,
+ scm_io_read(base + offsets[data[i].offset]));
+ }
+
+ return 0;
+}
+
+static int print_trace_reg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, print_cpufreq_hw_trace_regs, inode->i_private);
+}
+
+static const struct file_operations cpufreq_trace_register_fops = {
+ .open = print_trace_reg_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int print_cpufreq_hw_debug_regs(struct seq_file *s, void *unused)
+{
+ int i, j;
+ u32 regval;
+
+ static struct cpufreq_register_data data[] = {
+ {"PERF_STATE_DESIRED", REG_PERF_STATE},
+ {"CYCLE_CNTR_VAL", REG_CYCLE_CNTR},
+ {"PSTATE_STATUS", REG_PSTATE_STATUS},
+ };
+
+ for (i = 0; i < hw_regs->domain_cnt; i++) {
+ seq_printf(s, "FREQUENCY DOMAIN %d\n", i);
+ for (j = 0; j < ARRAY_SIZE(data); j++) {
+ regval = readl_relaxed(hw_regs->base[i] +
+ offsets[data[j].offset]);
+ seq_printf(s, "%25s: 0x%.8x\n", data[j].name, regval);
+ }
+ }
+
+ return 0;
+}
+
+static int print_cpufreq_hw_reg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, print_cpufreq_hw_debug_regs, NULL);
+}
+
+static const struct file_operations cpufreq_debug_register_fops = {
+ .open = print_cpufreq_hw_reg_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int cpufreq_panic_callback(struct notifier_block *nfb,
+ unsigned long event, void *unused)
+{
+ int i, j;
+ u32 regval;
+
+ static struct cpufreq_register_data data[] = {
+ {"PERF_STATE_DESIRED", REG_PERF_STATE},
+ {"CYCLE_CNTR_VAL", REG_CYCLE_CNTR},
+ {"PSTATE_STATUS", REG_PSTATE_STATUS},
+ };
+
+ for (i = 0; i < hw_regs->domain_cnt; i++) {
+ pr_err("FREQUENCY DOMAIN %d\n", i);
+ for (j = 0; j < ARRAY_SIZE(data); j++) {
+ regval = readl_relaxed(hw_regs->base[i] +
+ offsets[data[j].offset]);
+ pr_err("%25s: 0x%.8x\n", data[j].name, regval);
+ }
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block cpufreq_panic_notifier = {
+ .notifier_call = cpufreq_panic_callback,
+ .priority = 1,
+};
+
+static int cpufreq_get_hwregs(struct platform_device *pdev)
+{
+ struct of_phandle_args args;
+ struct property *prop;
+ struct resource res;
+ void __iomem *base;
+ int i, ret;
+
+ offsets = of_device_get_match_data(&pdev->dev);
+ if (!offsets)
+ return -EINVAL;
+
+ hw_regs = devm_kzalloc(&pdev->dev, sizeof(*hw_regs), GFP_KERNEL);
+ if (!hw_regs)
+ return -ENOMEM;
+
+ prop = of_find_property(pdev->dev.of_node, "qcom,freq-hw-domain", NULL);
+ hw_regs->domain_cnt = prop->length / (2 * sizeof(prop->length));
+
+ for (i = 0; i < hw_regs->domain_cnt; i++) {
+ ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
+ "qcom,freq-hw-domain", 1, i, &args);
+ of_node_put(pdev->dev.of_node);
+ if (ret)
+ return ret;
+
+ ret = of_address_to_resource(args.np, args.args[0], &res);
+ if (ret)
+ return ret;
+
+ base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
+ if (!base)
+ return -ENOMEM;
+
+ hw_regs->base[i] = base;
+ }
+
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &cpufreq_panic_notifier);
+
+ return 0;
+}
+
+static int enable_cpufreq_hw_trace_debug(struct platform_device *pdev,
+ bool is_secure)
+{
+ struct resource *res;
+ void *base;
+ int ret;
+
+ ret = cpufreq_get_hwregs(pdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to map cpufreq hw regs\n");
+ return ret;
+ }
+
+ hw_regs->debugfs_base = debugfs_create_dir("qcom-cpufreq-hw", NULL);
+ if (!hw_regs->debugfs_base) {
+ dev_err(&pdev->dev, "Failed to create debugfs entry\n");
+ return -ENODEV;
+ }
+
+ if (!debugfs_create_file("print_cpufreq_debug_regs", 0444,
+ hw_regs->debugfs_base, NULL, &cpufreq_debug_register_fops))
+ goto debugfs_fail;
+
+ if (!is_secure || of_device_is_compatible(pdev->dev.of_node,
+ "qcom,cpufreq-hw-epss-debug"))
+ return 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "domain-top");
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get domain-top register base\n");
+ return 0;
+ }
+
+ base = &(res->start);
+
+ if (!debugfs_create_file("print_cpufreq_trace_regs", 0444,
+ hw_regs->debugfs_base, base, &cpufreq_trace_register_fops))
+ goto debugfs_fail;
+
+ if (!debugfs_create_file("clock_domain_packet_sel", 0444,
+ hw_regs->debugfs_base, base, &clock_domian_packet_set))
+ goto debugfs_fail;
+
+ if (!debugfs_create_file("trace_enable", 0444, hw_regs->debugfs_base,
+ base, &clock_trace_enable))
+ goto debugfs_fail;
+
+ if (!debugfs_create_file("clock_timer", 0444,
+ hw_regs->debugfs_base, base, &clock_timer_fops))
+ goto debugfs_fail;
+
+ if (!debugfs_create_file("trace_type", 0444,
+ hw_regs->debugfs_base, base, &clk_trace_type_fops))
+ goto debugfs_fail;
+
+ return 0;
+
+debugfs_fail:
+ dev_err(&pdev->dev, "Failed to create debugfs entry so cleaning up\n");
+ debugfs_remove_recursive(hw_regs->debugfs_base);
+ return -ENODEV;
+}
+
+static int qcom_cpufreq_hw_debug_probe(struct platform_device *pdev)
+{
+ bool is_secure = scm_is_secure_device();
+
+ return enable_cpufreq_hw_trace_debug(pdev, is_secure);
+}
+
+static int qcom_cpufreq_hw_debug_remove(struct platform_device *pdev)
+{
+ debugfs_remove_recursive(hw_regs->debugfs_base);
+ return 0;
+}
+
+static const struct of_device_id qcom_cpufreq_hw_debug_trace_match[] = {
+ { .compatible = "qcom,cpufreq-hw-debug-trace",
+ .data = &cpufreq_qcom_std_data },
+ { .compatible = "qcom,cpufreq-hw-epss-debug",
+ .data = &cpufreq_qcom_std_epss_data },
+ {}
+};
+
+static struct platform_driver qcom_cpufreq_hw_debug = {
+ .probe = qcom_cpufreq_hw_debug_probe,
+ .remove = qcom_cpufreq_hw_debug_remove,
+ .driver = {
+ .name = "qcom-cpufreq-hw-debug",
+ .of_match_table = qcom_cpufreq_hw_debug_trace_match,
+ },
+};
+
+static int __init qcom_cpufreq_hw_debug_trace_init(void)
+{
+ return platform_driver_register(&qcom_cpufreq_hw_debug);
+}
+fs_initcall(qcom_cpufreq_hw_debug_trace_init);
+
+static void __exit qcom_cpufreq_hw_debug_trace_exit(void)
+{
+ return platform_driver_unregister(&qcom_cpufreq_hw_debug);
+}
+module_exit(qcom_cpufreq_hw_debug_trace_exit);
+
+MODULE_DESCRIPTION("QTI clock driver for CPUFREQ HW debug");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index f662914..53a7803 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -148,7 +148,7 @@ struct atmel_aes_xts_ctx {
u32 key2[AES_KEYSIZE_256 / sizeof(u32)];
};
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
struct atmel_aes_authenc_ctx {
struct atmel_aes_base_ctx base;
struct atmel_sha_authenc_ctx *auth;
@@ -160,7 +160,7 @@ struct atmel_aes_reqctx {
u32 lastc[AES_BLOCK_SIZE / sizeof(u32)];
};
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
struct atmel_aes_authenc_reqctx {
struct atmel_aes_reqctx base;
@@ -489,7 +489,7 @@ static inline bool atmel_aes_is_encrypt(const struct atmel_aes_dev *dd)
return (dd->flags & AES_FLAGS_ENCRYPT);
}
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
static void atmel_aes_authenc_complete(struct atmel_aes_dev *dd, int err);
#endif
@@ -518,7 +518,7 @@ static void atmel_aes_set_iv_as_last_ciphertext_block(struct atmel_aes_dev *dd)
static inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err)
{
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
if (dd->ctx->is_aead)
atmel_aes_authenc_complete(dd, err);
#endif
@@ -1983,7 +1983,7 @@ static struct crypto_alg aes_xts_alg = {
}
};
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
/* authenc aead functions */
static int atmel_aes_authenc_start(struct atmel_aes_dev *dd);
@@ -2470,7 +2470,7 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd)
{
int i;
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
if (dd->caps.has_authenc)
for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++)
crypto_unregister_aead(&aes_authenc_algs[i]);
@@ -2517,7 +2517,7 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
goto err_aes_xts_alg;
}
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
if (dd->caps.has_authenc) {
for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++) {
err = crypto_register_aead(&aes_authenc_algs[i]);
@@ -2529,7 +2529,7 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
return 0;
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
/* i = ARRAY_SIZE(aes_authenc_algs); */
err_aes_authenc_alg:
for (j = 0; j < i; j++)
@@ -2720,7 +2720,7 @@ static int atmel_aes_probe(struct platform_device *pdev)
atmel_aes_get_cap(aes_dd);
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
if (aes_dd->caps.has_authenc && !atmel_sha_authenc_is_ready()) {
err = -EPROBE_DEFER;
goto iclk_unprepare;
diff --git a/drivers/crypto/atmel-authenc.h b/drivers/crypto/atmel-authenc.h
index 2a60d12..7f6742d 100644
--- a/drivers/crypto/atmel-authenc.h
+++ b/drivers/crypto/atmel-authenc.h
@@ -23,7 +23,7 @@
#ifndef __ATMEL_AUTHENC_H__
#define __ATMEL_AUTHENC_H__
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
#include <crypto/authenc.h>
#include <crypto/hash.h>
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index 8a19df2..ef125d4 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -2215,7 +2215,7 @@ static struct ahash_alg sha_hmac_algs[] = {
},
};
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
/* authenc functions */
static int atmel_sha_authenc_init2(struct atmel_sha_dev *dd);
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
index 5cf64746..22e4918 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
@@ -81,7 +81,8 @@ static int sun4i_ss_opti_poll(struct skcipher_request *areq)
oi = 0;
oo = 0;
do {
- todo = min3(rx_cnt, ileft, (mi.length - oi) / 4);
+ todo = min(rx_cnt, ileft);
+ todo = min_t(size_t, todo, (mi.length - oi) / 4);
if (todo) {
ileft -= todo;
writesl(ss->base + SS_RXFIFO, mi.addr + oi, todo);
@@ -96,7 +97,8 @@ static int sun4i_ss_opti_poll(struct skcipher_request *areq)
rx_cnt = SS_RXFIFO_SPACES(spaces);
tx_cnt = SS_TXFIFO_SPACES(spaces);
- todo = min3(tx_cnt, oleft, (mo.length - oo) / 4);
+ todo = min(tx_cnt, oleft);
+ todo = min_t(size_t, todo, (mo.length - oo) / 4);
if (todo) {
oleft -= todo;
readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo);
@@ -220,7 +222,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq)
* todo is the number of consecutive 4byte word that we
* can read from current SG
*/
- todo = min3(rx_cnt, ileft / 4, (mi.length - oi) / 4);
+ todo = min(rx_cnt, ileft / 4);
+ todo = min_t(size_t, todo, (mi.length - oi) / 4);
if (todo && !ob) {
writesl(ss->base + SS_RXFIFO, mi.addr + oi,
todo);
@@ -234,8 +237,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq)
* we need to be able to write all buf in one
* pass, so it is why we min() with rx_cnt
*/
- todo = min3(rx_cnt * 4 - ob, ileft,
- mi.length - oi);
+ todo = min(rx_cnt * 4 - ob, ileft);
+ todo = min_t(size_t, todo, mi.length - oi);
memcpy(buf + ob, mi.addr + oi, todo);
ileft -= todo;
oi += todo;
@@ -255,7 +258,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq)
spaces = readl(ss->base + SS_FCSR);
rx_cnt = SS_RXFIFO_SPACES(spaces);
tx_cnt = SS_TXFIFO_SPACES(spaces);
- dev_dbg(ss->dev, "%x %u/%u %u/%u cnt=%u %u/%u %u/%u cnt=%u %u\n",
+ dev_dbg(ss->dev,
+ "%x %u/%zu %u/%u cnt=%u %u/%zu %u/%u cnt=%u %u\n",
mode,
oi, mi.length, ileft, areq->cryptlen, rx_cnt,
oo, mo.length, oleft, areq->cryptlen, tx_cnt, ob);
@@ -263,7 +267,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq)
if (!tx_cnt)
continue;
/* todo in 4bytes word */
- todo = min3(tx_cnt, oleft / 4, (mo.length - oo) / 4);
+ todo = min(tx_cnt, oleft / 4);
+ todo = min_t(size_t, todo, (mo.length - oo) / 4);
if (todo) {
readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo);
oleft -= todo * 4;
@@ -287,7 +292,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq)
* no more than remaining buffer
* no need to test against oleft
*/
- todo = min(mo.length - oo, obl - obo);
+ todo = min_t(size_t,
+ mo.length - oo, obl - obo);
memcpy(mo.addr + oo, bufo + obo, todo);
oleft -= todo;
obo += todo;
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
index f6936bb..1a72426 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
@@ -276,8 +276,8 @@ static int sun4i_hash(struct ahash_request *areq)
*/
while (op->len < 64 && i < end) {
/* how many bytes we can read from current SG */
- in_r = min3(mi.length - in_i, end - i,
- 64 - op->len);
+ in_r = min(end - i, 64 - op->len);
+ in_r = min_t(size_t, mi.length - in_i, in_r);
memcpy(op->buf + op->len, mi.addr + in_i, in_r);
op->len += in_r;
i += in_r;
@@ -297,8 +297,8 @@ static int sun4i_hash(struct ahash_request *areq)
}
if (mi.length - in_i > 3 && i < end) {
/* how many bytes we can read from current SG */
- in_r = min3(mi.length - in_i, areq->nbytes - i,
- ((mi.length - in_i) / 4) * 4);
+ in_r = min_t(size_t, mi.length - in_i, areq->nbytes - i);
+ in_r = min_t(size_t, ((mi.length - in_i) / 4) * 4, in_r);
/* how many bytes we can write in the device*/
todo = min3((u32)(end - i) / 4, rx_cnt, (u32)in_r / 4);
writesl(ss->base + SS_RXFIFO, mi.addr + in_i, todo);
@@ -324,8 +324,8 @@ static int sun4i_hash(struct ahash_request *areq)
if ((areq->nbytes - i) < 64) {
while (i < areq->nbytes && in_i < mi.length && op->len < 64) {
/* how many bytes we can read from current SG */
- in_r = min3(mi.length - in_i, areq->nbytes - i,
- 64 - op->len);
+ in_r = min(areq->nbytes - i, 64 - op->len);
+ in_r = min_t(size_t, mi.length - in_i, in_r);
memcpy(op->buf + op->len, mi.addr + in_i, in_r);
op->len += in_r;
i += in_r;
diff --git a/drivers/crypto/virtio/virtio_crypto_algs.c b/drivers/crypto/virtio/virtio_crypto_algs.c
index 2c573d1..523b712 100644
--- a/drivers/crypto/virtio/virtio_crypto_algs.c
+++ b/drivers/crypto/virtio/virtio_crypto_algs.c
@@ -117,8 +117,6 @@ virtio_crypto_alg_validate_key(int key_len, uint32_t *alg)
*alg = VIRTIO_CRYPTO_CIPHER_AES_CBC;
break;
default:
- pr_err("virtio_crypto: Unsupported key length: %d\n",
- key_len);
return -EINVAL;
}
return 0;
@@ -498,6 +496,11 @@ static int virtio_crypto_ablkcipher_encrypt(struct ablkcipher_request *req)
/* Use the first data virtqueue as default */
struct data_queue *data_vq = &vcrypto->data_vq[0];
+ if (!req->nbytes)
+ return 0;
+ if (req->nbytes % AES_BLOCK_SIZE)
+ return -EINVAL;
+
vc_req->dataq = data_vq;
vc_req->alg_cb = virtio_crypto_dataq_sym_callback;
vc_sym_req->ablkcipher_ctx = ctx;
@@ -518,6 +521,11 @@ static int virtio_crypto_ablkcipher_decrypt(struct ablkcipher_request *req)
/* Use the first data virtqueue as default */
struct data_queue *data_vq = &vcrypto->data_vq[0];
+ if (!req->nbytes)
+ return 0;
+ if (req->nbytes % AES_BLOCK_SIZE)
+ return -EINVAL;
+
vc_req->dataq = data_vq;
vc_req->alg_cb = virtio_crypto_dataq_sym_callback;
vc_sym_req->ablkcipher_ctx = ctx;
diff --git a/drivers/crypto/vmx/Makefile b/drivers/crypto/vmx/Makefile
index cab32cf..709670d 100644
--- a/drivers/crypto/vmx/Makefile
+++ b/drivers/crypto/vmx/Makefile
@@ -3,13 +3,13 @@
vmx-crypto-objs := vmx.o aesp8-ppc.o ghashp8-ppc.o aes.o aes_cbc.o aes_ctr.o aes_xts.o ghash.o
ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
-TARGET := linux-ppc64le
+override flavour := linux-ppc64le
else
-TARGET := linux-ppc64
+override flavour := linux-ppc64
endif
quiet_cmd_perl = PERL $@
- cmd_perl = $(PERL) $(<) $(TARGET) > $(@)
+ cmd_perl = $(PERL) $(<) $(flavour) > $(@)
targets += aesp8-ppc.S ghashp8-ppc.S
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 92d42ac..25ef772 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -538,31 +538,30 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
void *devp)
{
struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
- int ret;
- long freq;
+ int err = -EINVAL;
mutex_lock(&devfreq->lock);
- freq = find_available_min_freq(devfreq);
- if (freq < 0) {
- devfreq->scaling_min_freq = 0;
- mutex_unlock(&devfreq->lock);
- return -EINVAL;
- }
- devfreq->scaling_min_freq = freq;
+ devfreq->scaling_min_freq = find_available_min_freq(devfreq);
+ if (!devfreq->scaling_min_freq)
+ goto out;
- freq = find_available_max_freq(devfreq);
- if (freq < 0) {
- devfreq->scaling_max_freq = 0;
- mutex_unlock(&devfreq->lock);
- return -EINVAL;
+ devfreq->scaling_max_freq = find_available_max_freq(devfreq);
+ if (!devfreq->scaling_max_freq) {
+ devfreq->scaling_max_freq = ULONG_MAX;
+ goto out;
}
- devfreq->scaling_max_freq = freq;
- ret = update_devfreq(devfreq);
+ err = update_devfreq(devfreq);
+
+out:
mutex_unlock(&devfreq->lock);
+ if (err)
+ dev_err(devfreq->dev.parent,
+ "failed to update frequency from OPP notifier (%d)\n",
+ err);
- return ret;
+ return NOTIFY_OK;
}
/**
@@ -576,11 +575,6 @@ static void devfreq_dev_release(struct device *dev)
struct devfreq *devfreq = to_devfreq(dev);
mutex_lock(&devfreq_list_lock);
- if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
- mutex_unlock(&devfreq_list_lock);
- dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n");
- return;
- }
list_del(&devfreq->node);
mutex_unlock(&devfreq_list_lock);
@@ -637,6 +631,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
devfreq->dev.parent = dev;
devfreq->dev.class = devfreq_class;
devfreq->dev.release = devfreq_dev_release;
+ INIT_LIST_HEAD(&devfreq->node);
devfreq->profile = profile;
strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
devfreq->previous_freq = profile->initial_freq;
@@ -1075,10 +1070,6 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
}
mutex_lock(&df->event_lock);
- if (df->dev_suspended) {
- ret = -EINVAL;
- goto gov_stop_out;
- }
if (df->governor) {
ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
if (ret) {
@@ -1127,7 +1118,7 @@ static ssize_t available_governors_show(struct device *d,
* The devfreq with immutable governor (e.g., passive) shows
* only own governor.
*/
- if (df->governor->immutable) {
+ if (df->governor && df->governor->immutable) {
count = scnprintf(&buf[count], DEVFREQ_NAME_LEN,
"%s ", df->governor_name);
/*
@@ -1192,16 +1183,14 @@ static ssize_t polling_interval_store(struct device *dev,
unsigned int value;
int ret;
+ if (!df->governor)
+ return -EINVAL;
+
ret = sscanf(buf, "%u", &value);
if (ret != 1)
return -EINVAL;
mutex_lock(&df->event_lock);
- if (!df->governor || df->dev_suspended) {
- dev_warn(dev, "device suspended, operation not allowed\n");
- mutex_unlock(&df->event_lock);
- return -EINVAL;
- }
df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value);
ret = count;
mutex_unlock(&df->event_lock);
@@ -1222,11 +1211,6 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
return -EINVAL;
mutex_lock(&df->event_lock);
- if (df->dev_suspended) {
- dev_warn(dev, "device suspended, min freq not allowed\n");
- mutex_unlock(&df->event_lock);
- return -EINVAL;
- }
mutex_lock(&df->lock);
if (value) {
@@ -1273,11 +1257,6 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
return -EINVAL;
mutex_lock(&df->event_lock);
- if (df->dev_suspended) {
- mutex_unlock(&df->event_lock);
- dev_warn(dev, "device suspended, max freq not allowed\n");
- return -EINVAL;
- }
mutex_lock(&df->lock);
if (value) {
diff --git a/drivers/devfreq/devfreq_qcom_fw.c b/drivers/devfreq/devfreq_qcom_fw.c
index 87e58971..e2242d8 100644
--- a/drivers/devfreq/devfreq_qcom_fw.c
+++ b/drivers/devfreq/devfreq_qcom_fw.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/err.h>
@@ -29,6 +29,7 @@
struct devfreq_qcom_fw {
void __iomem *perf_base;
+ void __iomem *pstate_base;
struct devfreq_dev_profile dp;
struct list_head voters;
struct list_head voter;
@@ -37,6 +38,7 @@ struct devfreq_qcom_fw {
static DEFINE_SPINLOCK(voter_lock);
static unsigned int ftbl_row_size = FTBL_ROW_SIZE;
+static struct device *dev_node;
static int devfreq_qcom_fw_target(struct device *dev, unsigned long *freq,
u32 flags)
@@ -80,6 +82,26 @@ static int devfreq_qcom_fw_target(struct device *dev, unsigned long *freq,
return 0;
}
+static int devfreq_panic_callback(struct notifier_block *nfb,
+ unsigned long event, void *unused)
+{
+ struct devfreq_qcom_fw *d = dev_get_drvdata(dev_node);
+ void __iomem *base;
+
+ pr_err("%s: L3-DOMAIN\n", __func__);
+ base = d->perf_base;
+ pr_err("%25s: 0x%.8x\n", "PERF_STATE_DESIRED", readl_relaxed(base));
+ base = d->pstate_base;
+ pr_err("%25s: 0x%.8x\n", "PSTATE_STATUS", readl_relaxed(base));
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block devfreq_panic_notifier = {
+ .notifier_call = devfreq_panic_callback,
+ .priority = 1,
+};
+
static int devfreq_qcom_fw_get_cur_freq(struct device *dev,
unsigned long *freq)
{
@@ -197,6 +219,29 @@ static int devfreq_qcom_init_hw(struct platform_device *pdev)
goto out;
}
+ if (of_property_read_bool(dev->of_node,
+ "qcom,support-panic-notifier")) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "pstate-base");
+ if (!res) {
+ dev_err(dev, "Unable to find pstate-base!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ d->pstate_base = devm_ioremap(dev, res->start,
+ resource_size(res));
+ if (!d->pstate_base) {
+ dev_err(dev, "Unable to map pstate-base\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &devfreq_panic_notifier);
+ dev_node = dev;
+ }
+
INIT_LIST_HEAD(&d->voters);
dev_set_drvdata(dev, d);
diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c
index c5d21cc..f20b6cf 100644
--- a/drivers/devfreq/governor_bw_hwmon.c
+++ b/drivers/devfreq/governor_bw_hwmon.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2013-2018, 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, 2019-2020, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "bw-hwmon: " fmt
@@ -62,6 +62,7 @@ struct hwmon_node {
ktime_t hist_max_ts;
bool sampled;
bool mon_started;
+ bool init_pending;
struct list_head list;
void *orig_data;
struct bw_hwmon *hw;
@@ -539,8 +540,15 @@ static int start_monitor(struct devfreq *df, bool init)
unsigned long mbps;
int ret;
- node->prev_ts = ktime_get();
+ if (init && df->dev_suspended) {
+ node->init_pending = true;
+ return 0;
+ } else if (!init && node->init_pending) {
+ init = true;
+ node->init_pending = false;
+ }
+ node->prev_ts = ktime_get();
if (init) {
node->prev_ab = 0;
node->resume_freq = 0;
@@ -580,7 +588,8 @@ static void stop_monitor(struct devfreq *df, bool init)
if (init) {
devfreq_monitor_stop(df);
- hw->stop_hwmon(hw);
+ if (!df->dev_suspended)
+ hw->stop_hwmon(hw);
} else {
devfreq_monitor_suspend(df);
hw->suspend_hwmon(hw);
@@ -705,7 +714,7 @@ static int devfreq_bw_hwmon_get_freq(struct devfreq *df,
struct hwmon_node *node = df->data;
/* Suspend/resume sequence */
- if (node && !node->mon_started) {
+ if ((node && !node->mon_started) || df->dev_suspended) {
*freq = node->resume_freq;
*node->dev_ab = node->resume_ab;
return 0;
@@ -877,6 +886,10 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df,
*/
hw = node->hw;
+ if (!node->mon_started || df->dev_suspended) {
+ devfreq_interval_update(df, &sample_ms);
+ break;
+ }
mutex_lock(&node->mon_lock);
node->mon_started = false;
mutex_unlock(&node->mon_lock);
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 8aec137..d56b6b0 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -1427,6 +1427,7 @@ static int xilinx_dma_reset(struct xilinx_dma_chan *chan)
chan->err = false;
chan->idle = true;
+ chan->desc_pendingcount = 0;
chan->desc_submitcount = 0;
return err;
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c
index 574bce6..78c339d 100644
--- a/drivers/edac/ghes_edac.c
+++ b/drivers/edac/ghes_edac.c
@@ -210,6 +210,7 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
/* Cleans the error report buffer */
memset(e, 0, sizeof (*e));
e->error_count = 1;
+ e->grain = 1;
strcpy(e->label, "unknown label");
e->msg = pvt->msg;
e->other_detail = pvt->other_detail;
@@ -305,7 +306,7 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
/* Error grain */
if (mem_err->validation_bits & CPER_MEM_VALID_PA_MASK)
- e->grain = ~(mem_err->physical_addr_mask & ~PAGE_MASK);
+ e->grain = ~mem_err->physical_addr_mask + 1;
/* Memory error location, mapped on e->location */
p = e->location;
@@ -412,8 +413,13 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
if (p > pvt->other_detail)
*(p - 1) = '\0';
+ /* Sanity-check driver-supplied grain value. */
+ if (WARN_ON_ONCE(!e->grain))
+ e->grain = 1;
+
+ grain_bits = fls_long(e->grain - 1);
+
/* Generate the trace event */
- grain_bits = fls_long(e->grain);
snprintf(pvt->detail_location, sizeof(pvt->detail_location),
"APEI location: %s %s", e->location, e->other_detail);
trace_mc_event(type, e->msg, e->label, e->error_count,
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
index 0cfb5a3..2efcd94 100644
--- a/drivers/extcon/extcon-sm5502.c
+++ b/drivers/extcon/extcon-sm5502.c
@@ -69,6 +69,10 @@ struct sm5502_muic_info {
/* Default value of SM5502 register to bring up MUIC device. */
static struct reg_data sm5502_reg_data[] = {
{
+ .reg = SM5502_REG_RESET,
+ .val = SM5502_REG_RESET_MASK,
+ .invert = true,
+ }, {
.reg = SM5502_REG_CONTROL,
.val = SM5502_REG_CONTROL_MASK_INT_MASK,
.invert = false,
diff --git a/drivers/extcon/extcon-sm5502.h b/drivers/extcon/extcon-sm5502.h
index 974b532..12f8b01 100644
--- a/drivers/extcon/extcon-sm5502.h
+++ b/drivers/extcon/extcon-sm5502.h
@@ -241,6 +241,8 @@ enum sm5502_reg {
#define DM_DP_SWITCH_UART ((DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \
| (DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DM_SHIFT))
+#define SM5502_REG_RESET_MASK (0x1)
+
/* SM5502 Interrupts */
enum sm5502_irq {
/* INT1 */
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 82ba110..bbabfca 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -249,7 +249,11 @@ static int fwnet_header_cache(const struct neighbour *neigh,
h = (struct fwnet_header *)((u8 *)hh->hh_data + HH_DATA_OFF(sizeof(*h)));
h->h_proto = type;
memcpy(h->h_dest, neigh->ha, net->addr_len);
- hh->hh_len = FWNET_HLEN;
+
+ /* Pairs with the READ_ONCE() in neigh_resolve_output(),
+ * neigh_hh_output() and neigh_update_hhs().
+ */
+ smp_store_release(&hh->hh_len, FWNET_HLEN);
return 0;
}
diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c
index 24c461d..fd8053f 100644
--- a/drivers/firmware/efi/libstub/gop.c
+++ b/drivers/firmware/efi/libstub/gop.c
@@ -86,30 +86,6 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
}
static efi_status_t
-__gop_query32(efi_system_table_t *sys_table_arg,
- struct efi_graphics_output_protocol_32 *gop32,
- struct efi_graphics_output_mode_info **info,
- unsigned long *size, u64 *fb_base)
-{
- struct efi_graphics_output_protocol_mode_32 *mode;
- efi_graphics_output_protocol_query_mode query_mode;
- efi_status_t status;
- unsigned long m;
-
- m = gop32->mode;
- mode = (struct efi_graphics_output_protocol_mode_32 *)m;
- query_mode = (void *)(unsigned long)gop32->query_mode;
-
- status = __efi_call_early(query_mode, (void *)gop32, mode->mode, size,
- info);
- if (status != EFI_SUCCESS)
- return status;
-
- *fb_base = mode->frame_buffer_base;
- return status;
-}
-
-static efi_status_t
setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
efi_guid_t *proto, unsigned long size, void **gop_handle)
{
@@ -121,7 +97,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
u64 fb_base;
struct efi_pixel_bitmask pixel_info;
int pixel_format;
- efi_status_t status = EFI_NOT_FOUND;
+ efi_status_t status;
u32 *handles = (u32 *)(unsigned long)gop_handle;
int i;
@@ -130,6 +106,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
nr_gops = size / sizeof(u32);
for (i = 0; i < nr_gops; i++) {
+ struct efi_graphics_output_protocol_mode_32 *mode;
struct efi_graphics_output_mode_info *info = NULL;
efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
bool conout_found = false;
@@ -147,9 +124,11 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
if (status == EFI_SUCCESS)
conout_found = true;
- status = __gop_query32(sys_table_arg, gop32, &info, &size,
- ¤t_fb_base);
- if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
+ mode = (void *)(unsigned long)gop32->mode;
+ info = (void *)(unsigned long)mode->info;
+ current_fb_base = mode->frame_buffer_base;
+
+ if ((!first_gop || conout_found) &&
info->pixel_format != PIXEL_BLT_ONLY) {
/*
* Systems that use the UEFI Console Splitter may
@@ -177,7 +156,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
/* Did we find any GOPs? */
if (!first_gop)
- goto out;
+ return EFI_NOT_FOUND;
/* EFI framebuffer */
si->orig_video_isVGA = VIDEO_TYPE_EFI;
@@ -199,32 +178,8 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
si->lfb_size = si->lfb_linelength * si->lfb_height;
si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
-out:
- return status;
-}
-static efi_status_t
-__gop_query64(efi_system_table_t *sys_table_arg,
- struct efi_graphics_output_protocol_64 *gop64,
- struct efi_graphics_output_mode_info **info,
- unsigned long *size, u64 *fb_base)
-{
- struct efi_graphics_output_protocol_mode_64 *mode;
- efi_graphics_output_protocol_query_mode query_mode;
- efi_status_t status;
- unsigned long m;
-
- m = gop64->mode;
- mode = (struct efi_graphics_output_protocol_mode_64 *)m;
- query_mode = (void *)(unsigned long)gop64->query_mode;
-
- status = __efi_call_early(query_mode, (void *)gop64, mode->mode, size,
- info);
- if (status != EFI_SUCCESS)
- return status;
-
- *fb_base = mode->frame_buffer_base;
- return status;
+ return EFI_SUCCESS;
}
static efi_status_t
@@ -239,7 +194,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
u64 fb_base;
struct efi_pixel_bitmask pixel_info;
int pixel_format;
- efi_status_t status = EFI_NOT_FOUND;
+ efi_status_t status;
u64 *handles = (u64 *)(unsigned long)gop_handle;
int i;
@@ -248,6 +203,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
nr_gops = size / sizeof(u64);
for (i = 0; i < nr_gops; i++) {
+ struct efi_graphics_output_protocol_mode_64 *mode;
struct efi_graphics_output_mode_info *info = NULL;
efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
bool conout_found = false;
@@ -265,9 +221,11 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
if (status == EFI_SUCCESS)
conout_found = true;
- status = __gop_query64(sys_table_arg, gop64, &info, &size,
- ¤t_fb_base);
- if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
+ mode = (void *)(unsigned long)gop64->mode;
+ info = (void *)(unsigned long)mode->info;
+ current_fb_base = mode->frame_buffer_base;
+
+ if ((!first_gop || conout_found) &&
info->pixel_format != PIXEL_BLT_ONLY) {
/*
* Systems that use the UEFI Console Splitter may
@@ -295,7 +253,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
/* Did we find any GOPs? */
if (!first_gop)
- goto out;
+ return EFI_NOT_FOUND;
/* EFI framebuffer */
si->orig_video_isVGA = VIDEO_TYPE_EFI;
@@ -317,8 +275,8 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
si->lfb_size = si->lfb_linelength * si->lfb_height;
si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
-out:
- return status;
+
+ return EFI_SUCCESS;
}
/*
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 2c31563..c6fa9b3 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -552,6 +552,31 @@ static int fsi_slave_scan(struct fsi_slave *slave)
return 0;
}
+static unsigned long aligned_access_size(size_t offset, size_t count)
+{
+ unsigned long offset_unit, count_unit;
+
+ /* Criteria:
+ *
+ * 1. Access size must be less than or equal to the maximum access
+ * width or the highest power-of-two factor of offset
+ * 2. Access size must be less than or equal to the amount specified by
+ * count
+ *
+ * The access width is optimal if we can calculate 1 to be strictly
+ * equal while still satisfying 2.
+ */
+
+ /* Find 1 by the bottom bit of offset (with a 4 byte access cap) */
+ offset_unit = BIT(__builtin_ctzl(offset | 4));
+
+ /* Find 2 by the top bit of count */
+ count_unit = BIT(8 * sizeof(unsigned long) - 1 - __builtin_clzl(count));
+
+ /* Constrain the maximum access width to the minimum of both criteria */
+ return BIT(__builtin_ctzl(offset_unit | count_unit));
+}
+
static ssize_t fsi_slave_sysfs_raw_read(struct file *file,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
@@ -567,8 +592,7 @@ static ssize_t fsi_slave_sysfs_raw_read(struct file *file,
return -EINVAL;
for (total_len = 0; total_len < count; total_len += read_len) {
- read_len = min_t(size_t, count, 4);
- read_len -= off & 0x3;
+ read_len = aligned_access_size(off, count - total_len);
rc = fsi_slave_read(slave, off, buf + total_len, read_len);
if (rc)
@@ -595,8 +619,7 @@ static ssize_t fsi_slave_sysfs_raw_write(struct file *file,
return -EINVAL;
for (total_len = 0; total_len < count; total_len += write_len) {
- write_len = min_t(size_t, count, 4);
- write_len -= off & 0x3;
+ write_len = aligned_access_size(off, count - total_len);
rc = fsi_slave_write(slave, off, buf + total_len, write_len);
if (rc)
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index c8673a5..3f10f95 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -348,7 +348,8 @@ static int mpc8xxx_probe(struct platform_device *pdev)
* It's assumed that only a single type of gpio controller is available
* on the current machine, so overwriting global data is fine.
*/
- mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
+ if (devtype->irq_set_type)
+ mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
if (devtype->gpio_dir_out)
gc->direction_output = devtype->gpio_dir_out;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index ae3d8b2..113852c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -217,6 +217,14 @@ int gpiod_get_direction(struct gpio_desc *desc)
chip = gpiod_to_chip(desc);
offset = gpio_chip_hwgpio(desc);
+ /*
+ * Open drain emulation using input mode may incorrectly report
+ * input here, fix that up.
+ */
+ if (test_bit(FLAG_OPEN_DRAIN, &desc->flags) &&
+ test_bit(FLAG_IS_OUT, &desc->flags))
+ return 0;
+
if (!chip->get_direction)
return status;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c
index 8904e62..41d3142 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c
@@ -138,6 +138,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev)
}
dma_fence_put(fence);
+ fence = NULL;
r = amdgpu_bo_kmap(vram_obj, &vram_map);
if (r) {
@@ -183,6 +184,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev)
}
dma_fence_put(fence);
+ fence = NULL;
r = amdgpu_bo_kmap(gtt_obj[i], >t_map);
if (r) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 49fe508..f67c332 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -700,10 +700,8 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_
id->oa_base != job->oa_base ||
id->oa_size != job->oa_size);
bool vm_flush_needed = job->vm_needs_flush;
- bool pasid_mapping_needed = id->pasid != job->pasid ||
- !id->pasid_mapping ||
- !dma_fence_is_signaled(id->pasid_mapping);
struct dma_fence *fence = NULL;
+ bool pasid_mapping_needed = false;
unsigned patch_offset = 0;
int r;
@@ -713,6 +711,12 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_
pasid_mapping_needed = true;
}
+ mutex_lock(&id_mgr->lock);
+ if (id->pasid != job->pasid || !id->pasid_mapping ||
+ !dma_fence_is_signaled(id->pasid_mapping))
+ pasid_mapping_needed = true;
+ mutex_unlock(&id_mgr->lock);
+
gds_switch_needed &= !!ring->funcs->emit_gds_switch;
vm_flush_needed &= !!ring->funcs->emit_vm_flush &&
job->vm_pd_addr != AMDGPU_BO_INVALID_OFFSET;
@@ -752,9 +756,11 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_
}
if (pasid_mapping_needed) {
+ mutex_lock(&id_mgr->lock);
id->pasid = job->pasid;
dma_fence_put(id->pasid_mapping);
id->pasid_mapping = dma_fence_get(fence);
+ mutex_unlock(&id_mgr->lock);
}
dma_fence_put(fence);
diff --git a/drivers/gpu/drm/amd/amdgpu/df_v3_6.c b/drivers/gpu/drm/amd/amdgpu/df_v3_6.c
index d5ebe56..a1c9412 100644
--- a/drivers/gpu/drm/amd/amdgpu/df_v3_6.c
+++ b/drivers/gpu/drm/amd/amdgpu/df_v3_6.c
@@ -75,23 +75,29 @@ static void df_v3_6_update_medium_grain_clock_gating(struct amdgpu_device *adev,
{
u32 tmp;
- /* Put DF on broadcast mode */
- adev->df_funcs->enable_broadcast_mode(adev, true);
+ if (adev->cg_flags & AMD_CG_SUPPORT_DF_MGCG) {
+ /* Put DF on broadcast mode */
+ adev->df_funcs->enable_broadcast_mode(adev, true);
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_DF_MGCG)) {
- tmp = RREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater);
- tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK;
- tmp |= DF_V3_6_MGCG_ENABLE_15_CYCLE_DELAY;
- WREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater, tmp);
- } else {
- tmp = RREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater);
- tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK;
- tmp |= DF_V3_6_MGCG_DISABLE;
- WREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater, tmp);
+ if (enable) {
+ tmp = RREG32_SOC15(DF, 0,
+ mmDF_PIE_AON0_DfGlobalClkGater);
+ tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK;
+ tmp |= DF_V3_6_MGCG_ENABLE_15_CYCLE_DELAY;
+ WREG32_SOC15(DF, 0,
+ mmDF_PIE_AON0_DfGlobalClkGater, tmp);
+ } else {
+ tmp = RREG32_SOC15(DF, 0,
+ mmDF_PIE_AON0_DfGlobalClkGater);
+ tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK;
+ tmp |= DF_V3_6_MGCG_DISABLE;
+ WREG32_SOC15(DF, 0,
+ mmDF_PIE_AON0_DfGlobalClkGater, tmp);
+ }
+
+ /* Exit broadcast mode */
+ adev->df_funcs->enable_broadcast_mode(adev, false);
}
-
- /* Exit broadcast mode */
- adev->df_funcs->enable_broadcast_mode(adev, false);
}
static void df_v3_6_get_clockgating_state(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 5a9534a8..e1cb7fa 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -6405,7 +6405,23 @@ static void gfx_v8_0_ring_emit_fence_gfx(struct amdgpu_ring *ring, u64 addr,
bool write64bit = flags & AMDGPU_FENCE_FLAG_64BIT;
bool int_sel = flags & AMDGPU_FENCE_FLAG_INT;
- /* EVENT_WRITE_EOP - flush caches, send int */
+ /* Workaround for cache flush problems. First send a dummy EOP
+ * event down the pipe with seq one below.
+ */
+ amdgpu_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+ amdgpu_ring_write(ring, (EOP_TCL1_ACTION_EN |
+ EOP_TC_ACTION_EN |
+ EOP_TC_WB_ACTION_EN |
+ EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+ EVENT_INDEX(5)));
+ amdgpu_ring_write(ring, addr & 0xfffffffc);
+ amdgpu_ring_write(ring, (upper_32_bits(addr) & 0xffff) |
+ DATA_SEL(1) | INT_SEL(0));
+ amdgpu_ring_write(ring, lower_32_bits(seq - 1));
+ amdgpu_ring_write(ring, upper_32_bits(seq - 1));
+
+ /* Then send the real EOP event down the pipe:
+ * EVENT_WRITE_EOP - flush caches, send int */
amdgpu_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
amdgpu_ring_write(ring, (EOP_TCL1_ACTION_EN |
EOP_TC_ACTION_EN |
@@ -7154,7 +7170,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = {
5 + /* COND_EXEC */
7 + /* PIPELINE_SYNC */
VI_FLUSH_GPU_TLB_NUM_WREG * 5 + 9 + /* VM_FLUSH */
- 8 + /* FENCE for VM_FLUSH */
+ 12 + /* FENCE for VM_FLUSH */
20 + /* GDS switch */
4 + /* double SWITCH_BUFFER,
the first COND_EXEC jump to the place just
@@ -7166,7 +7182,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = {
31 + /* DE_META */
3 + /* CNTX_CTRL */
5 + /* HDP_INVL */
- 8 + 8 + /* FENCE x2 */
+ 12 + 12 + /* FENCE x2 */
2, /* SWITCH_BUFFER */
.emit_ib_size = 4, /* gfx_v8_0_ring_emit_ib_gfx */
.emit_ib = gfx_v8_0_ring_emit_ib_gfx,
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index 7824116..28794b1 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -2187,7 +2187,8 @@ static void gfx_v9_0_init_pg(struct amdgpu_device *adev)
* And it's needed by gfxoff feature.
*/
if (adev->gfx.rlc.is_rlc_v2_1) {
- gfx_v9_1_init_rlc_save_restore_list(adev);
+ if (adev->asic_type == CHIP_VEGA12)
+ gfx_v9_1_init_rlc_save_restore_list(adev);
gfx_v9_0_enable_save_restore_machine(adev);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.c b/drivers/gpu/drm/amd/amdgpu/si_ih.c
index 60dad63..e40a3fb 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_ih.c
@@ -62,7 +62,8 @@ static int si_ih_irq_init(struct amdgpu_device *adev)
u64 wptr_off;
si_ih_disable_interrupts(adev);
- WREG32(INTERRUPT_CNTL2, adev->irq.ih.gpu_addr >> 8);
+ /* set dummy read address to dummy page address */
+ WREG32(INTERRUPT_CNTL2, adev->dummy_page_addr >> 8);
interrupt_cntl = RREG32(INTERRUPT_CNTL);
interrupt_cntl &= ~IH_DUMMY_RD_OVERRIDE;
interrupt_cntl &= ~IH_REQ_NONSNOOP_EN;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
index c56ac47..bc47f6a 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
@@ -62,6 +62,11 @@ int kfd_interrupt_init(struct kfd_dev *kfd)
}
kfd->ih_wq = alloc_workqueue("KFD IH", WQ_HIGHPRI, 1);
+ if (unlikely(!kfd->ih_wq)) {
+ kfifo_free(&kfd->ih_fifo);
+ dev_err(kfd_chardev(), "Failed to allocate KFD IH workqueue\n");
+ return -ENOMEM;
+ }
spin_lock_init(&kfd->interrupt_lock);
INIT_WORK(&kfd->interrupt_work, interrupt_wq);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index 23a7ef9..2f42964 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -348,7 +348,7 @@ bool dc_link_is_dp_sink_present(struct dc_link *link)
if (GPIO_RESULT_OK != dal_ddc_open(
ddc, GPIO_MODE_INPUT, GPIO_DDC_CONFIG_TYPE_MODE_I2C)) {
- dal_gpio_destroy_ddc(&ddc);
+ dal_ddc_close(ddc);
return present;
}
@@ -1950,7 +1950,7 @@ static bool dp_active_dongle_validate_timing(
break;
}
- if (dongle_caps->dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER ||
+ if (dpcd_caps->dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER ||
dongle_caps->extendedCapValid == false)
return true;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
index 05840f5..122249d 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -2172,6 +2172,7 @@ static void get_active_converter_info(
uint8_t data, struct dc_link *link)
{
union dp_downstream_port_present ds_port = { .byte = data };
+ memset(&link->dpcd_caps.dongle_caps, 0, sizeof(link->dpcd_caps.dongle_caps));
/* decode converter info*/
if (!ds_port.fields.PORT_PRESENT) {
diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c
index f8433c9..cc820e9 100644
--- a/drivers/gpu/drm/bridge/analogix-anx78xx.c
+++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c
@@ -725,7 +725,9 @@ static int anx78xx_init_pdata(struct anx78xx *anx78xx)
/* 1.0V digital core power regulator */
pdata->dvdd10 = devm_regulator_get(dev, "dvdd10");
if (IS_ERR(pdata->dvdd10)) {
- DRM_ERROR("DVDD10 regulator not found\n");
+ if (PTR_ERR(pdata->dvdd10) != -EPROBE_DEFER)
+ DRM_ERROR("DVDD10 regulator not found\n");
+
return PTR_ERR(pdata->dvdd10);
}
@@ -1341,7 +1343,9 @@ static int anx78xx_i2c_probe(struct i2c_client *client,
err = anx78xx_init_pdata(anx78xx);
if (err) {
- DRM_ERROR("Failed to initialize pdata: %d\n", err);
+ if (err != -EPROBE_DEFER)
+ DRM_ERROR("Failed to initialize pdata: %d\n", err);
+
return err;
}
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 5971976..2a0a165 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -39,6 +39,7 @@
#include <media/cec-notifier.h>
+#define DDC_CI_ADDR 0x37
#define DDC_SEGMENT_ADDR 0x30
#define HDMI_EDID_LEN 512
@@ -320,6 +321,15 @@ static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap,
u8 addr = msgs[0].addr;
int i, ret = 0;
+ if (addr == DDC_CI_ADDR)
+ /*
+ * The internal I2C controller does not support the multi-byte
+ * read and write operations needed for DDC/CI.
+ * TOFIX: Blacklist the DDC/CI address until we filter out
+ * unsupported I2C operations.
+ */
+ return -EOPNOTSUPP;
+
dev_dbg(hdmi->dev, "xfer: num: %d, addr: %#x\n", num, addr);
for (i = 0; i < num; i++) {
@@ -1747,7 +1757,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
/* HDMI Initialization Step E - Configure audio */
hdmi_clk_regenerator_update_pixel_clock(hdmi);
- hdmi_enable_audio_clk(hdmi, true);
+ hdmi_enable_audio_clk(hdmi, hdmi->audio_enable);
}
/* not for DVI mode */
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 7794ad2..7632933 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -1639,8 +1639,11 @@ static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr,
if (ret != 1)
DRM_DEBUG_KMS("failed to send msg in q %d\n", ret);
- if (txmsg->seqno != -1)
+ if (txmsg->seqno != -1) {
+ WARN_ON((unsigned int)txmsg->seqno >
+ ARRAY_SIZE(txmsg->dst->tx_slots));
txmsg->dst->tx_slots[txmsg->seqno] = NULL;
+ }
}
static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr,
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index d1859bc..33a72a8 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -1572,7 +1572,7 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
unsigned int flags, pipe, high_pipe;
if (!dev->irq_enabled)
- return -EINVAL;
+ return -EOPNOTSUPP;
if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
return -EINVAL;
@@ -1813,7 +1813,7 @@ int drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
if (!dev->irq_enabled)
- return -EINVAL;
+ return -EOPNOTSUPP;
crtc = drm_crtc_find(dev, file_priv, get_seq->crtc_id);
if (!crtc)
@@ -1871,7 +1871,7 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
if (!dev->irq_enabled)
- return -EINVAL;
+ return -EOPNOTSUPP;
crtc = drm_crtc_find(dev, file_priv, queue_seq->crtc_id);
if (!crtc)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 7ba414b5..d71188b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -1292,6 +1292,7 @@ static int gsc_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ component_del(dev, &gsc_component_ops);
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_disable(dev);
diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
index 1b7fd6a..f73a02a 100644
--- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
+++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
@@ -139,6 +139,7 @@ static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit,
s32 freq_error, min_error = 100000;
memset(best_clock, 0, sizeof(*best_clock));
+ memset(&clock, 0, sizeof(clock));
for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
for (clock.n = limit->n.min; clock.n <= limit->n.max;
@@ -195,6 +196,7 @@ static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit,
int err = target;
memset(best_clock, 0, sizeof(*best_clock));
+ memset(&clock, 0, sizeof(clock));
for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 52a2146..5e6c78e 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -25,6 +25,7 @@
#include <linux/pm_opp.h>
#include <linux/devfreq.h>
#include <linux/devcoredump.h>
+#include <linux/sched/task.h>
/*
* Power Management:
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index dc7454e..b46e99f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -29,6 +29,7 @@
#include <nvif/notify.h>
+#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_dp_helper.h>
@@ -37,6 +38,60 @@
struct nvkm_i2c_port;
+#define nouveau_conn_atom(p) \
+ container_of((p), struct nouveau_conn_atom, state)
+
+struct nouveau_conn_atom {
+ struct drm_connector_state state;
+
+ struct {
+ /* The enum values specifically defined here match nv50/gf119
+ * hw values, and the code relies on this.
+ */
+ enum {
+ DITHERING_MODE_OFF = 0x00,
+ DITHERING_MODE_ON = 0x01,
+ DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON,
+ DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON,
+ DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON,
+ DITHERING_MODE_AUTO
+ } mode;
+ enum {
+ DITHERING_DEPTH_6BPC = 0x00,
+ DITHERING_DEPTH_8BPC = 0x02,
+ DITHERING_DEPTH_AUTO
+ } depth;
+ } dither;
+
+ struct {
+ int mode; /* DRM_MODE_SCALE_* */
+ struct {
+ enum {
+ UNDERSCAN_OFF,
+ UNDERSCAN_ON,
+ UNDERSCAN_AUTO,
+ } mode;
+ u32 hborder;
+ u32 vborder;
+ } underscan;
+ bool full;
+ } scaler;
+
+ struct {
+ int color_vibrance;
+ int vibrant_hue;
+ } procamp;
+
+ union {
+ struct {
+ bool dither:1;
+ bool scaler:1;
+ bool procamp:1;
+ };
+ u8 mask;
+ } set;
+};
+
struct nouveau_connector {
struct drm_connector base;
enum dcb_connector_type type;
@@ -111,61 +166,6 @@ extern int nouveau_ignorelid;
extern int nouveau_duallink;
extern int nouveau_hdmimhz;
-#include <drm/drm_crtc.h>
-#define nouveau_conn_atom(p) \
- container_of((p), struct nouveau_conn_atom, state)
-
-struct nouveau_conn_atom {
- struct drm_connector_state state;
-
- struct {
- /* The enum values specifically defined here match nv50/gf119
- * hw values, and the code relies on this.
- */
- enum {
- DITHERING_MODE_OFF = 0x00,
- DITHERING_MODE_ON = 0x01,
- DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON,
- DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON,
- DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON,
- DITHERING_MODE_AUTO
- } mode;
- enum {
- DITHERING_DEPTH_6BPC = 0x00,
- DITHERING_DEPTH_8BPC = 0x02,
- DITHERING_DEPTH_AUTO
- } depth;
- } dither;
-
- struct {
- int mode; /* DRM_MODE_SCALE_* */
- struct {
- enum {
- UNDERSCAN_OFF,
- UNDERSCAN_ON,
- UNDERSCAN_AUTO,
- } mode;
- u32 hborder;
- u32 vborder;
- } underscan;
- bool full;
- } scaler;
-
- struct {
- int color_vibrance;
- int vibrant_hue;
- } procamp;
-
- union {
- struct {
- bool dither:1;
- bool scaler:1;
- bool procamp:1;
- };
- u8 mask;
- } set;
-};
-
void nouveau_conn_attach_properties(struct drm_connector *);
void nouveau_conn_reset(struct drm_connector *);
struct drm_connector_state *
diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
index 9a2cb8a..aab6a70 100644
--- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
+++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
@@ -427,6 +427,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
return PTR_ERR(ts->dsi);
}
+ drm_panel_init(&ts->base);
ts->base.dev = dev;
ts->base.funcs = &rpi_touchscreen_funcs;
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index 74284e5..89fa178 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -380,6 +380,7 @@ static int st7789v_probe(struct spi_device *spi)
spi_set_drvdata(spi, ctx);
ctx->spi = spi;
+ drm_panel_init(&ctx->panel);
ctx->panel.dev = &spi->dev;
ctx->panel.funcs = &st7789v_drm_funcs;
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 416da53..8ad36f5 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -651,8 +651,6 @@ static void sun4i_hdmi_unbind(struct device *dev, struct device *master,
struct sun4i_hdmi *hdmi = dev_get_drvdata(dev);
cec_unregister_adapter(hdmi->cec_adap);
- drm_connector_cleanup(&hdmi->connector);
- drm_encoder_cleanup(&hdmi->encoder);
i2c_del_adapter(hdmi->i2c);
clk_disable_unprepare(hdmi->mod_clk);
clk_disable_unprepare(hdmi->bus_clk);
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index d7fe9f1..89cb70d 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -2922,6 +2922,11 @@ static int tegra_sor_parse_dt(struct tegra_sor *sor)
* earlier
*/
sor->pad = TEGRA_IO_PAD_HDMI_DP0 + sor->index;
+ } else {
+ if (sor->soc->supports_edp)
+ sor->index = 0;
+ else
+ sor->index = 1;
}
return 0;
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c
index 527a1cd..916b2355 100644
--- a/drivers/gpu/host1x/job.c
+++ b/drivers/gpu/host1x/job.c
@@ -447,7 +447,8 @@ static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g)
return err;
}
-static inline int copy_gathers(struct host1x_job *job, struct device *dev)
+static inline int copy_gathers(struct device *host, struct host1x_job *job,
+ struct device *dev)
{
struct host1x_firewall fw;
size_t size = 0;
@@ -470,12 +471,12 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev)
* Try a non-blocking allocation from a higher priority pools first,
* as awaiting for the allocation here is a major performance hit.
*/
- job->gather_copy_mapped = dma_alloc_wc(dev, size, &job->gather_copy,
+ job->gather_copy_mapped = dma_alloc_wc(host, size, &job->gather_copy,
GFP_NOWAIT);
/* the higher priority allocation failed, try the generic-blocking */
if (!job->gather_copy_mapped)
- job->gather_copy_mapped = dma_alloc_wc(dev, size,
+ job->gather_copy_mapped = dma_alloc_wc(host, size,
&job->gather_copy,
GFP_KERNEL);
if (!job->gather_copy_mapped)
@@ -523,7 +524,7 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
goto out;
if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) {
- err = copy_gathers(job, dev);
+ err = copy_gathers(host->dev, job, dev);
if (err)
goto out;
}
@@ -584,7 +585,7 @@ void host1x_job_unpin(struct host1x_job *job)
job->num_unpins = 0;
if (job->gather_copy_size)
- dma_free_wc(job->channel->dev, job->gather_copy_size,
+ dma_free_wc(host->dev, job->gather_copy_size,
job->gather_copy_mapped, job->gather_copy);
}
EXPORT_SYMBOL(host1x_job_unpin);
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index 266c0e1..30a730c 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -1042,7 +1042,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a620 = {
.features = ADRENO_64BIT | ADRENO_RPMH | ADRENO_GPMU |
ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT |
ADRENO_IFPC | ADRENO_PREEMPTION | ADRENO_ACD |
- ADRENO_APRIV,
+ ADRENO_APRIV | ADRENO_LM,
.gpudev = &adreno_a6xx_gpudev,
.gmem_size = SZ_512K,
.busy_mask = 0xfffffffe,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 58c93b4c3..b545b4d 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -339,6 +339,7 @@ void adreno_fault_detect_stop(struct adreno_device *adreno_dev)
/* Send an NMI to the GMU */
void adreno_gmu_send_nmi(struct adreno_device *adreno_dev)
{
+ u32 val;
/* Mask so there's no interrupt caused by NMI */
adreno_write_gmureg(adreno_dev,
ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF);
@@ -348,9 +349,10 @@ void adreno_gmu_send_nmi(struct adreno_device *adreno_dev)
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
adreno_write_gmureg(adreno_dev,
ADRENO_REG_GMU_NMI_CONTROL_STATUS, 0);
- adreno_write_gmureg(adreno_dev,
- ADRENO_REG_GMU_CM3_CFG,
- (1 << GMU_CM3_CFG_NONMASKINTR_SHIFT));
+
+ adreno_read_gmureg(adreno_dev, ADRENO_REG_GMU_CM3_CFG, &val);
+ val |= 1 << GMU_CM3_CFG_NONMASKINTR_SHIFT;
+ adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_CM3_CFG, val);
/* Make sure the NMI is invoked before we proceed*/
wmb();
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 63e48e6..d97a03f 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/firmware.h>
@@ -145,6 +145,18 @@ static void a6xx_init(struct adreno_device *adreno_dev)
/* LP DDR4 highest bank bit is different and needs to be overridden */
if (adreno_is_a650(adreno_dev) && of_fdt_get_ddrtype() == 0x7)
adreno_dev->highest_bank_bit = 15;
+ else if (adreno_is_a610(adreno_dev) && of_fdt_get_ddrtype() == 0x5) {
+ /*
+ * LPDDR3 has multiple different highest bank bit value
+ * based on different DDR density. Query this value from
+ * FDT, in case FDT returns error fallback to value in GPU
+ * DT node.
+ */
+ int hbb = of_fdt_get_ddrhbb(0, 0);
+
+ if (hbb > 0)
+ adreno_dev->highest_bank_bit = hbb;
+ }
a6xx_crashdump_init(adreno_dev);
@@ -1313,11 +1325,19 @@ static const char *a6xx_fault_block_uche(struct kgsl_device *device,
unsigned int uche_client_id = 0;
static char str[40];
- mutex_lock(&device->mutex);
+ /*
+ * Smmu driver takes a vote on CX gdsc before calling the kgsl pagefault
+ * handler. If there is contention for device mutex in this path and the
+ * dispatcher fault handler is holding this lock, trying to turn off CX
+ * gdsc will fail during the reset. So to avoid blocking here, try to
+ * lock device mutex and return if it fails.
+ */
+ if (!mutex_trylock(&device->mutex))
+ return "UCHE";
if (!kgsl_state_is_awake(device)) {
mutex_unlock(&device->mutex);
- return "UCHE: unknown";
+ return "UCHE";
}
kgsl_regread(device, A6XX_UCHE_CLIENT_PF, &uche_client_id);
@@ -1325,7 +1345,7 @@ static const char *a6xx_fault_block_uche(struct kgsl_device *device,
/* Ignore the value if the gpu is in IFPC */
if (uche_client_id == SCOOBYDOO)
- return "UCHE: unknown";
+ return "UCHE";
uche_client_id &= A6XX_UCHE_CLIENT_PF_CLIENT_ID_MASK;
snprintf(str, sizeof(str), "UCHE: %s",
diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c
index 0db1b58..b6a1b13 100644
--- a/drivers/gpu/msm/adreno_a6xx_gmu.c
+++ b/drivers/gpu/msm/adreno_a6xx_gmu.c
@@ -34,7 +34,7 @@ static const unsigned int a6xx_gmu_tcm_registers[] = {
static const unsigned int a6xx_gmu_registers[] = {
/* GMU CX */
- 0x1F400, 0x1F407, 0x1F410, 0x1F412, 0x1F500, 0x1F500, 0x1F507, 0x1F50A,
+ 0x1F400, 0x1F40B, 0x1F410, 0x1F412, 0x1F500, 0x1F500, 0x1F507, 0x1F50A,
0x1F800, 0x1F804, 0x1F807, 0x1F808, 0x1F80B, 0x1F80C, 0x1F80F, 0x1F81C,
0x1F824, 0x1F82A, 0x1F82D, 0x1F830, 0x1F840, 0x1F853, 0x1F887, 0x1F889,
0x1F8A0, 0x1F8A2, 0x1F8A4, 0x1F8AF, 0x1F8C0, 0x1F8C3, 0x1F8D0, 0x1F8D0,
@@ -352,12 +352,22 @@ static int a6xx_gmu_start(struct kgsl_device *device)
mask = 0xFFFFFFFF;
}
+ /**
+ * We may have asserted gbif halt as part of reset sequence which may
+ * not get cleared if the gdsc was not reset. So clear it before
+ * attempting GMU boot.
+ */
+ if (adreno_has_gbif(ADRENO_DEVICE(device)))
+ kgsl_regwrite(device, A6XX_GBIF_HALT, 0x0);
+
/* Set the log wptr index */
gmu_core_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_COL_CP_RESP,
gmu->log_wptr_retention);
/* Bring GMU out of reset */
gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 0);
+ /* Make sure the request completes before continuing */
+ wmb();
if (timed_poll_check(device,
A6XX_GMU_CM3_FW_INIT_RESULT,
val, GMU_START_TIMEOUT, mask)) {
@@ -1058,6 +1068,13 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device,
gmu_core_regwrite(device, A6XX_GMU_AHB_FENCE_RANGE_0,
GMU_FENCE_RANGE_MASK);
+ /*
+ * Make sure that CM3 state is at reset value. Snapshot is changing
+ * NMI bit and if we boot up GMU with NMI bit set.GMU will boot straight
+ * in to NMI handler without executing __main code
+ */
+ gmu_core_regwrite(device, A6XX_GMU_CM3_CFG, 0x4052);
+
/* Pass chipid to GMU FW, must happen before starting GMU */
/* Keep Core and Major bitfields unchanged */
diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c
index 8c44c4a..db850c2 100644
--- a/drivers/gpu/msm/adreno_a6xx_preempt.c
+++ b/drivers/gpu/msm/adreno_a6xx_preempt.c
@@ -760,7 +760,7 @@ void a6xx_preemption_context_destroy(struct kgsl_context *context)
struct kgsl_device *device = context->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- if (!adreno_is_preemption_enabled(adreno_dev))
+ if (!ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION))
return;
gpumem_free_entry(context->user_ctxt_record);
@@ -775,7 +775,7 @@ int a6xx_preemption_context_init(struct kgsl_context *context)
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
uint64_t flags = 0;
- if (!adreno_is_preemption_enabled(adreno_dev))
+ if (!ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION))
return 0;
if (context->flags & KGSL_CONTEXT_SECURE)
diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c
index cf82890..754662f 100644
--- a/drivers/gpu/msm/kgsl_hfi.c
+++ b/drivers/gpu/msm/kgsl_hfi.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/delay.h>
@@ -268,9 +268,9 @@ static int poll_adreno_gmu_reg(struct adreno_device *adreno_dev,
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
- u64 ao_pre_poll, ao_post_poll;
+ u64 ts1, ts2;
- ao_pre_poll = gmu_core_dev_read_ao_counter(device);
+ ts1 = gmu_core_dev_read_ao_counter(device);
while (time_is_after_jiffies(timeout)) {
adreno_read_gmureg(adreno_dev, offset_name, &val);
@@ -279,15 +279,16 @@ static int poll_adreno_gmu_reg(struct adreno_device *adreno_dev,
usleep_range(10, 100);
}
- ao_post_poll = gmu_core_dev_read_ao_counter(device);
+ ts2 = gmu_core_dev_read_ao_counter(device);
/* Check one last time */
adreno_read_gmureg(adreno_dev, offset_name, &val);
if ((val & mask) == expected_val)
return 0;
- dev_err(&gmu->pdev->dev, "kgsl hfi poll timeout: always on: %lld ms\n",
- div_u64((ao_post_poll - ao_pre_poll) * 52, USEC_PER_SEC));
+ dev_err(&gmu->pdev->dev,
+ "Timed out waiting for HFI response. Wait start=%llx end=%llx\n",
+ ts1, ts2);
return -ETIMEDOUT;
}
diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c
index d5a7f5e..5970692 100644
--- a/drivers/gpu/msm/kgsl_pool.c
+++ b/drivers/gpu/msm/kgsl_pool.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#include <asm/cacheflush.h>
@@ -100,7 +100,10 @@ _kgsl_pool_get_page(struct kgsl_page_pool *pool)
list_del(&p->lru);
}
spin_unlock(&pool->list_lock);
- mod_node_page_state(page_pgdat(p), NR_INDIRECTLY_RECLAIMABLE_BYTES,
+
+ if (p != NULL)
+ mod_node_page_state(page_pgdat(p),
+ NR_INDIRECTLY_RECLAIMABLE_BYTES,
-(PAGE_SIZE << pool->pool_order));
return p;
}
diff --git a/drivers/gpu/msm/kgsl_rgmu.c b/drivers/gpu/msm/kgsl_rgmu.c
index e3426e1e..ff89170 100644
--- a/drivers/gpu/msm/kgsl_rgmu.c
+++ b/drivers/gpu/msm/kgsl_rgmu.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk-provider.h>
@@ -404,6 +404,18 @@ static int rgmu_suspend(struct kgsl_device *device)
return 0;
}
+static int rgmu_init(struct kgsl_device *device)
+{
+ struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device);
+ int ret;
+
+ ret = ops->load_firmware(device);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
/* To be called to power on both GPU and RGMU */
static int rgmu_start(struct kgsl_device *device)
{
@@ -470,6 +482,7 @@ static bool rgmu_regulator_isenabled(struct kgsl_device *device)
struct gmu_core_ops rgmu_ops = {
.probe = rgmu_probe,
.remove = rgmu_stop,
+ .init = rgmu_init,
.start = rgmu_start,
.stop = rgmu_stop,
.dcvs_set = rgmu_dcvs_set,
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index b0c8fae..3a35971 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -780,6 +780,10 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
if (usage == 0xff0000c5 && parser->global.report_count == 256 &&
parser->global.report_size == 8)
parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
+
+ if (usage == 0xff0000c6 && parser->global.report_count == 1 &&
+ parser->global.report_size == 8)
+ parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
}
static void hid_scan_collection(struct hid_parser *parser, unsigned type)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index efd2861..4f41adc 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -563,6 +563,7 @@
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941 0x0941
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641 0x0641
+#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a 0x1f4a
#define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 034c883..504e891 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -978,6 +978,9 @@ static int hidpp20_batterylevel_get_battery_capacity(struct hidpp_device *hidpp,
ret = hidpp_send_fap_command_sync(hidpp, feature_index,
CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS,
NULL, 0, &response);
+ /* Ignore these intermittent errors */
+ if (ret == HIDPP_ERROR_RESOURCE_ERROR)
+ return -EIO;
if (ret > 0) {
hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
__func__, ret);
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 4865e67..e5aafda 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -96,6 +96,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
diff --git a/drivers/hid/hid-qvr.c b/drivers/hid/hid-qvr.c
index 6df6010..8ece1d7 100644
--- a/drivers/hid/hid-qvr.c
+++ b/drivers/hid/hid-qvr.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -46,7 +46,8 @@
#include "hid-qvr.h"
#include "hid-trace.h"
-#define WAIT_EVENT_INT_TOUT 20
+#define TIME_OUT_START_STOP_MS 500
+#define TIME_OUT_READ_WRITE_MS 20
#define QVR_START_IMU _IO('q', 1)
#define QVR_STOP_IMU _IO('q', 2)
@@ -63,6 +64,7 @@ struct qvr_buf_index {
uint8_t padding[60];
};
+// struct must be 64 bit aligned
struct qvr_sensor_t {
uint64_t gts;
uint64_t ats;
@@ -70,13 +72,19 @@ struct qvr_sensor_t {
s32 gx;
s32 gy;
s32 gz;
+ u32 gNumerator;
+ u32 gDenominator;
s32 ax;
s32 ay;
s32 az;
+ u32 aNumerator;
+ u32 aDenominator;
s32 mx;
s32 my;
s32 mz;
- uint8_t padding[4];
+ u32 mNumerator;
+ u32 mDenominator;
+ uint8_t padding[44];
};
struct qvr_calib_data {
@@ -105,7 +113,6 @@ struct qvr_external_sensor {
static DECLARE_WAIT_QUEUE_HEAD(wq);
static struct qvr_external_sensor qvr_external_sensor;
-static uint8_t DEBUG_ORIENTATION;
static int read_calibration_len(void)
{
@@ -128,7 +135,7 @@ static int read_calibration_len(void)
ret = wait_event_interruptible_timeout(wq,
sensor->calib_data_len != -1,
- msecs_to_jiffies(WAIT_EVENT_INT_TOUT));
+ msecs_to_jiffies(TIME_OUT_READ_WRITE_MS));
if (ret == 0) {
kfree(hid_buf);
return -ETIME;
@@ -173,7 +180,7 @@ static uint8_t *read_calibration_data(void)
HID_REQ_SET_REPORT);
ret = wait_event_interruptible_timeout(wq,
sensor->calib_data_recv == 1,
- msecs_to_jiffies(WAIT_EVENT_INT_TOUT));
+ msecs_to_jiffies(TIME_OUT_READ_WRITE_MS));
if (ret == 0) {
pr_err("%s:get calibration data timeout\n", __func__);
kfree(hid_buf);
@@ -221,7 +228,7 @@ static int control_imu_stream(bool status)
HID_FEATURE_REPORT,
HID_REQ_SET_REPORT);
ret = wait_event_interruptible_timeout(wq, sensor->ext_ack == 1,
- msecs_to_jiffies(WAIT_EVENT_INT_TOUT));
+ msecs_to_jiffies(TIME_OUT_START_STOP_MS));
if (!ret && status) {
pr_debug("qvr: falling back - start IMU stream failed\n");
hid_buf[0] = QVR_HID_REPORT_ID_CAL;
@@ -255,10 +262,6 @@ static int qvr_send_package_wrap(u8 *message, int msize, struct hid_device *hid)
memcpy((void *)&imuData, (void *)message,
sizeof(struct external_imu_format));
if (!sensor->ts_base) {
- if (imuData.gNumerator == 1 && imuData.aNumerator == 1)
- DEBUG_ORIENTATION = 1;
- else
- DEBUG_ORIENTATION = 0;
pr_debug("qvr msize = %d reportID=%d padding=%d\n"
"qvr version=%d numImu=%d nspip=%d pSize=%d\n"
"qvr imuID=%d sampleID=%d temp=%d\n",
@@ -285,9 +288,9 @@ static int qvr_send_package_wrap(u8 *message, int msize, struct hid_device *hid)
if (!sensor->ts_offset)
sensor->ts_offset = imuData.gts0;
index_buf = (struct qvr_buf_index *)((uintptr_t)sensor->vaddr +
- (sensor->vsize / 2) + (8 * sizeof(*sensor_buf)));
- sensor_buf = (struct qvr_sensor_t *)((uintptr_t)sensor->vaddr +
(sensor->vsize / 2));
+ sensor_buf = (struct qvr_sensor_t *)((uintptr_t)sensor->vaddr +
+ (sensor->vsize / 2) + sizeof(struct qvr_buf_index));
data = (struct qvr_sensor_t *)&(sensor_buf[buf_index]);
if (sensor->ts_offset > imuData.gts0)
@@ -302,27 +305,30 @@ static int qvr_send_package_wrap(u8 *message, int msize, struct hid_device *hid)
data->mts = data->ats;
data->gts = data->ats;
- if (DEBUG_ORIENTATION == 1) {
- data->ax = -imuData.ax0;
- data->ay = imuData.ay0;
- data->az = -imuData.az0;
- data->gx = -imuData.gx0;
- data->gy = imuData.gy0;
- data->gz = -imuData.gz0;
- data->mx = -imuData.my0;
- data->my = -imuData.mx0;
- data->mz = -imuData.mz0;
- } else {
- data->ax = -imuData.ay0;
- data->ay = -imuData.ax0;
- data->az = -imuData.az0;
- data->gx = -imuData.gy0;
- data->gy = -imuData.gx0;
- data->gz = -imuData.gz0;
- data->mx = -imuData.my0;
- data->my = -imuData.mx0;
- data->mz = -imuData.mz0;
- }
+ data->ax = imuData.ax0;
+ data->ay = imuData.ay0;
+ data->az = imuData.az0;
+ data->gx = imuData.gx0;
+ data->gy = imuData.gy0;
+ data->gz = imuData.gz0;
+ data->mx = imuData.my0;
+ data->my = imuData.mx0;
+ data->mz = imuData.mz0;
+ data->ax = imuData.ax0;
+ data->ay = imuData.ay0;
+ data->az = imuData.az0;
+ data->gx = imuData.gx0;
+ data->gy = imuData.gy0;
+ data->gz = imuData.gz0;
+ data->mx = imuData.my0;
+ data->my = imuData.mx0;
+ data->mz = imuData.mz0;
+ data->aNumerator = imuData.aNumerator;
+ data->aDenominator = imuData.aDenominator;
+ data->gNumerator = imuData.gNumerator;
+ data->gDenominator = imuData.gDenominator;
+ data->mNumerator = imuData.mNumerator;
+ data->mDenominator = imuData.mDenominator;
trace_qvr_recv_sensor("gyro", data->gts, data->gx, data->gy, data->gz);
trace_qvr_recv_sensor("accel", data->ats, data->ax, data->ay, data->az);
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index 9e33165..a5b6b2b 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -737,7 +737,8 @@ static void rmi_remove(struct hid_device *hdev)
{
struct rmi_data *hdata = hid_get_drvdata(hdev);
- if (hdata->device_flags & RMI_DEVICE) {
+ if ((hdata->device_flags & RMI_DEVICE)
+ && test_bit(RMI_STARTED, &hdata->flags)) {
clear_bit(RMI_STARTED, &hdata->flags);
cancel_work_sync(&hdata->reset_work);
rmi_unregister_transport_device(&hdata->xport);
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 2f940c1..0a39e44 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -51,6 +51,7 @@
#define I2C_HID_QUIRK_NO_RUNTIME_PM BIT(2)
#define I2C_HID_QUIRK_DELAY_AFTER_SLEEP BIT(3)
#define I2C_HID_QUIRK_BOGUS_IRQ BIT(4)
+#define I2C_HID_QUIRK_RESET_ON_RESUME BIT(5)
/* flags */
#define I2C_HID_STARTED 0
@@ -182,6 +183,8 @@ static const struct i2c_hid_quirks {
I2C_HID_QUIRK_NO_RUNTIME_PM },
{ USB_VENDOR_ID_ELAN, HID_ANY_ID,
I2C_HID_QUIRK_BOGUS_IRQ },
+ { USB_VENDOR_ID_ALPS_JP, HID_ANY_ID,
+ I2C_HID_QUIRK_RESET_ON_RESUME },
{ 0, 0 }
};
@@ -1290,8 +1293,15 @@ static int i2c_hid_resume(struct device *dev)
* solves "incomplete reports" on Raydium devices 2386:3118 and
* 2386:4B33 and fixes various SIS touchscreens no longer sending
* data after a suspend/resume.
+ *
+ * However some ALPS touchpads generate IRQ storm without reset, so
+ * let's still reset them here.
*/
- ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
+ if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME)
+ ret = i2c_hid_hwreset(client);
+ else
+ ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
+
if (ret)
return ret;
diff --git a/drivers/hwtracing/coresight/coresight-csr.c b/drivers/hwtracing/coresight/coresight-csr.c
index 775f363..6a19c6b 100644
--- a/drivers/hwtracing/coresight/coresight-csr.c
+++ b/drivers/hwtracing/coresight/coresight-csr.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2012-2013, 2015-2017, 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2015-2017, 2019-2020 The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
@@ -66,8 +66,11 @@ do { \
#define BLKSIZE_1024 2
#define BLKSIZE_2048 3
+#define FLUSHPERIOD_1 0x1
#define FLUSHPERIOD_2048 0x800
+#define PERFLSHEOT_BIT BIT(18)
+
struct csr_drvdata {
void __iomem *base;
phys_addr_t pbase;
@@ -79,6 +82,7 @@ struct csr_drvdata {
struct clk *clk;
spinlock_t spin_lock;
bool usb_bam_support;
+ bool perflsheot_set_support;
bool hwctrl_set_support;
bool set_byte_cntr_support;
bool timestamp_support;
@@ -153,6 +157,8 @@ void msm_qdss_csr_enable_flush(struct coresight_csr *csr)
usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
usbflshctrl |= 0x2;
+ if (drvdata->perflsheot_set_support)
+ usbflshctrl |= PERFLSHEOT_BIT;
csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
CSR_LOCK(drvdata);
@@ -205,6 +211,8 @@ void msm_qdss_csr_disable_flush(struct coresight_csr *csr)
usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
usbflshctrl &= ~0x2;
+ if (drvdata->perflsheot_set_support)
+ usbflshctrl &= ~PERFLSHEOT_BIT;
csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
CSR_LOCK(drvdata);
@@ -479,8 +487,16 @@ static int csr_probe(struct platform_device *pdev)
dev_dbg(dev, "aodbg_csr_support operation not supported\n");
else
dev_dbg(dev, "aodbg_csr_support operation supported\n");
+ drvdata->perflsheot_set_support = of_property_read_bool(
+ pdev->dev.of_node, "qcom,perflsheot-set-support");
+ if (!drvdata->perflsheot_set_support)
+ dev_dbg(dev, "perflsheot_set_support handled by other subsystem\n");
+ else
+ dev_dbg(dev, "perflsheot_set_support operation supported\n");
- if (drvdata->usb_bam_support)
+ if (drvdata->perflsheot_set_support)
+ drvdata->flushperiod = FLUSHPERIOD_1;
+ else if (drvdata->usb_bam_support)
drvdata->flushperiod = FLUSHPERIOD_2048;
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c
index 24ab3cb..e63a0c2 100644
--- a/drivers/hwtracing/intel_th/pci.c
+++ b/drivers/hwtracing/intel_th/pci.c
@@ -181,6 +181,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
.driver_data = (kernel_ulong_t)&intel_th_2x,
},
{
+ /* Comet Lake PCH-V */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa3a6),
+ .driver_data = (kernel_ulong_t)&intel_th_2x,
+ },
+ {
/* Ice Lake NNPI */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x45c5),
.driver_data = (kernel_ulong_t)&intel_th_2x,
@@ -205,6 +210,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4da6),
.driver_data = (kernel_ulong_t)&intel_th_2x,
},
+ {
+ /* Elkhart Lake */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4b26),
+ .driver_data = (kernel_ulong_t)&intel_th_2x,
+ },
{ 0 },
};
diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
index c64c667..4ab052d 100644
--- a/drivers/iio/adc/dln2-adc.c
+++ b/drivers/iio/adc/dln2-adc.c
@@ -527,6 +527,10 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
u16 conflict;
unsigned int trigger_chan;
+ ret = iio_triggered_buffer_postenable(indio_dev);
+ if (ret)
+ return ret;
+
mutex_lock(&dln2->mutex);
/* Enable ADC */
@@ -540,6 +544,7 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
(int)conflict);
ret = -EBUSY;
}
+ iio_triggered_buffer_predisable(indio_dev);
return ret;
}
@@ -553,6 +558,7 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
mutex_unlock(&dln2->mutex);
if (ret < 0) {
dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+ iio_triggered_buffer_predisable(indio_dev);
return ret;
}
} else {
@@ -560,12 +566,12 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
mutex_unlock(&dln2->mutex);
}
- return iio_triggered_buffer_postenable(indio_dev);
+ return 0;
}
static int dln2_adc_triggered_buffer_predisable(struct iio_dev *indio_dev)
{
- int ret;
+ int ret, ret2;
struct dln2_adc *dln2 = iio_priv(indio_dev);
mutex_lock(&dln2->mutex);
@@ -580,12 +586,14 @@ static int dln2_adc_triggered_buffer_predisable(struct iio_dev *indio_dev)
ret = dln2_adc_set_port_enabled(dln2, false, NULL);
mutex_unlock(&dln2->mutex);
- if (ret < 0) {
+ if (ret < 0)
dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
- return ret;
- }
- return iio_triggered_buffer_predisable(indio_dev);
+ ret2 = iio_triggered_buffer_predisable(indio_dev);
+ if (ret == 0)
+ ret = ret2;
+
+ return ret;
}
static const struct iio_buffer_setup_ops dln2_adc_buffer_setup_ops = {
diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c
index 311c1a8..0939eb0 100644
--- a/drivers/iio/adc/max1027.c
+++ b/drivers/iio/adc/max1027.c
@@ -460,6 +460,14 @@ static int max1027_probe(struct spi_device *spi)
goto fail_dev_register;
}
+ /* Internal reset */
+ st->reg = MAX1027_RST_REG;
+ ret = spi_write(st->spi, &st->reg, 1);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev, "Failed to reset the ADC\n");
+ return ret;
+ }
+
/* Disable averaging */
st->reg = MAX1027_AVG_REG;
ret = spi_write(st->spi, &st->reg, 1);
diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c
index 0884435..9f1a5ef 100644
--- a/drivers/iio/adc/max9611.c
+++ b/drivers/iio/adc/max9611.c
@@ -92,6 +92,12 @@
#define MAX9611_TEMP_SCALE_NUM 1000000
#define MAX9611_TEMP_SCALE_DIV 2083
+/*
+ * Conversion time is 2 ms (typically) at Ta=25 degreeC
+ * No maximum value is known, so play it safe.
+ */
+#define MAX9611_CONV_TIME_US_RANGE 3000, 3300
+
struct max9611_dev {
struct device *dev;
struct i2c_client *i2c_client;
@@ -239,11 +245,9 @@ static int max9611_read_single(struct max9611_dev *max9611,
return ret;
}
- /*
- * need a delay here to make register configuration
- * stabilize. 1 msec at least, from empirical testing.
- */
- usleep_range(1000, 2000);
+ /* need a delay here to make register configuration stabilize. */
+
+ usleep_range(MAX9611_CONV_TIME_US_RANGE);
ret = i2c_smbus_read_word_swapped(max9611->i2c_client, reg_addr);
if (ret < 0) {
@@ -510,7 +514,7 @@ static int max9611_init(struct max9611_dev *max9611)
MAX9611_REG_CTRL2, 0);
return ret;
}
- usleep_range(1000, 2000);
+ usleep_range(MAX9611_CONV_TIME_US_RANGE);
return 0;
}
diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c
index 49cdbf1..9be81ab 100644
--- a/drivers/iio/adc/qcom-vadc-common.c
+++ b/drivers/iio/adc/qcom-vadc-common.c
@@ -1142,7 +1142,8 @@ static int qcom_vadc7_scale_hw_calib_die_temp(
} else {
vtemp0 = adcmap7_die_temp[i-1].x;
voltage = voltage - vtemp0;
- temp = div64_s64(voltage, adcmap7_die_temp[i-1].y);
+ temp = div64_s64(voltage * DIE_TEMP_ADC7_SCALE_FACTOR,
+ adcmap7_die_temp[i-1].y);
temp += DIE_TEMP_ADC7_SCALE_1 + (DIE_TEMP_ADC7_SCALE_2 * (i-1));
*result_mdec = temp;
}
diff --git a/drivers/iio/adc/qcom-vadc-common.h b/drivers/iio/adc/qcom-vadc-common.h
index d3db4aba..e29ea9e 100644
--- a/drivers/iio/adc/qcom-vadc-common.h
+++ b/drivers/iio/adc/qcom-vadc-common.h
@@ -86,9 +86,10 @@
#define R_PU_100K 100000
#define RATIO_MAX_ADC7 0x4000
-#define DIE_TEMP_ADC7_SCALE_1 -60
-#define DIE_TEMP_ADC7_SCALE_2 20
-#define DIE_TEMP_ADC7_MAX 160
+#define DIE_TEMP_ADC7_SCALE_1 -60000
+#define DIE_TEMP_ADC7_SCALE_2 20000
+#define DIE_TEMP_ADC7_SCALE_FACTOR 1000
+#define DIE_TEMP_ADC7_MAX 160000
/**
* struct vadc_map_pt - Map the graph representation for ADC channel
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 80beb64..69f4cfa 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -59,8 +59,8 @@
help
Say yes here to build support for Analog Devices AD5300, AD5301, AD5310,
AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453,
- AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612,
- AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs
+ AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5600, AD5601, AD5602, AD5611,
+ AD5612, AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs
as well as Texas Instruments DAC081S101, DAC101S101, DAC121S101.
To compile this driver as a module, choose M here: the
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
index fd26a42..d3ce5de 100644
--- a/drivers/iio/dac/ad5446.c
+++ b/drivers/iio/dac/ad5446.c
@@ -328,6 +328,7 @@ enum ad5446_supported_spi_device_ids {
ID_AD5541A,
ID_AD5512A,
ID_AD5553,
+ ID_AD5600,
ID_AD5601,
ID_AD5611,
ID_AD5621,
@@ -382,6 +383,10 @@ static const struct ad5446_chip_info ad5446_spi_chip_info[] = {
.channel = AD5446_CHANNEL(14, 16, 0),
.write = ad5446_write,
},
+ [ID_AD5600] = {
+ .channel = AD5446_CHANNEL(16, 16, 0),
+ .write = ad5446_write,
+ },
[ID_AD5601] = {
.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
.write = ad5446_write,
@@ -449,6 +454,7 @@ static const struct spi_device_id ad5446_spi_ids[] = {
{"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
{"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
{"ad5553", ID_AD5553},
+ {"ad5600", ID_AD5600},
{"ad5601", ID_AD5601},
{"ad5611", ID_AD5611},
{"ad5621", ID_AD5621},
diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c
index a814828..5f5d54c 100644
--- a/drivers/iio/light/bh1750.c
+++ b/drivers/iio/light/bh1750.c
@@ -62,9 +62,9 @@ struct bh1750_chip_info {
u16 int_time_low_mask;
u16 int_time_high_mask;
-}
+};
-static const bh1750_chip_info_tbl[] = {
+static const struct bh1750_chip_info bh1750_chip_info_tbl[] = {
[BH1710] = { 140, 1022, 300, 400, 250000000, 2, 0x001F, 0x03E0 },
[BH1721] = { 140, 1020, 300, 400, 250000000, 2, 0x0010, 0x03E0 },
[BH1750] = { 31, 254, 69, 1740, 57500000, 1, 0x001F, 0x00E0 },
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 1f373ba..319bfef 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -4658,6 +4658,7 @@ static int __init cma_init(void)
err:
unregister_netdevice_notifier(&cma_nb);
ib_sa_unregister_client(&sa_client);
+ unregister_pernet_subsys(&cma_pernet_operations);
err_wq:
destroy_workqueue(cma_wq);
return ret;
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 0bbeaaa..9386bb5 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -3069,16 +3069,17 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
ibdev->ib_active = false;
flush_workqueue(wq);
- mlx4_ib_close_sriov(ibdev);
- mlx4_ib_mad_cleanup(ibdev);
- ib_unregister_device(&ibdev->ib_dev);
- mlx4_ib_diag_cleanup(ibdev);
if (ibdev->iboe.nb.notifier_call) {
if (unregister_netdevice_notifier(&ibdev->iboe.nb))
pr_warn("failure unregistering notifier\n");
ibdev->iboe.nb.notifier_call = NULL;
}
+ mlx4_ib_close_sriov(ibdev);
+ mlx4_ib_mad_cleanup(ibdev);
+ ib_unregister_device(&ibdev->ib_dev);
+ mlx4_ib_diag_cleanup(ibdev);
+
mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
ibdev->steer_qpn_count);
kfree(ibdev->ib_uc_qpns_bitmap);
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index f4ffdc5..df5be46 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -3286,10 +3286,6 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
}
INIT_LIST_HEAD(&handler->list);
- if (dst) {
- memcpy(&dest_arr[0], dst, sizeof(*dst));
- dest_num++;
- }
for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) {
err = parse_flow_attr(dev->mdev, spec->match_criteria,
@@ -3303,6 +3299,11 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
ib_flow += ((union ib_flow_spec *)ib_flow)->size;
}
+ if (dst && !(flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP)) {
+ memcpy(&dest_arr[0], dst, sizeof(*dst));
+ dest_num++;
+ }
+
if (!flow_is_multicast_only(flow_attr))
set_underlay_qp(dev, spec, underlay_qpn);
@@ -3340,10 +3341,8 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
}
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP) {
- if (!(flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT)) {
+ if (!dest_num)
rule_dst = NULL;
- dest_num = 0;
- }
} else {
if (is_egress)
flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW;
diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c
index 8cc3df2..9167a1c 100644
--- a/drivers/infiniband/hw/qedr/verbs.c
+++ b/drivers/infiniband/hw/qedr/verbs.c
@@ -1701,6 +1701,14 @@ static void qedr_cleanup_user(struct qedr_dev *dev, struct qedr_qp *qp)
if (qp->urq.umem)
ib_umem_release(qp->urq.umem);
qp->urq.umem = NULL;
+
+ if (rdma_protocol_roce(&dev->ibdev, 1)) {
+ qedr_free_pbl(dev, &qp->usq.pbl_info, qp->usq.pbl_tbl);
+ qedr_free_pbl(dev, &qp->urq.pbl_info, qp->urq.pbl_tbl);
+ } else {
+ kfree(qp->usq.pbl_tbl);
+ kfree(qp->urq.pbl_tbl);
+ }
}
static int qedr_create_user_qp(struct qedr_dev *dev,
@@ -2809,8 +2817,8 @@ int qedr_dereg_mr(struct ib_mr *ib_mr)
dev->ops->rdma_free_tid(dev->rdma_ctx, mr->hw_mr.itid);
- if ((mr->type != QEDR_MR_DMA) && (mr->type != QEDR_MR_FRMR))
- qedr_free_pbl(dev, &mr->info.pbl_info, mr->info.pbl_table);
+ if (mr->type != QEDR_MR_DMA)
+ free_mr_info(dev, &mr->info);
/* it could be user registered memory. */
if (mr->umem)
diff --git a/drivers/infiniband/sw/rxe/rxe_recv.c b/drivers/infiniband/sw/rxe/rxe_recv.c
index d30dbac..695a607 100644
--- a/drivers/infiniband/sw/rxe/rxe_recv.c
+++ b/drivers/infiniband/sw/rxe/rxe_recv.c
@@ -391,7 +391,7 @@ void rxe_rcv(struct sk_buff *skb)
calc_icrc = rxe_icrc_hdr(pkt, skb);
calc_icrc = rxe_crc32(rxe, calc_icrc, (u8 *)payload_addr(pkt),
- payload_size(pkt));
+ payload_size(pkt) + bth_pad(pkt));
calc_icrc = (__force u32)cpu_to_be32(~calc_icrc);
if (unlikely(calc_icrc != pack_icrc)) {
if (skb->protocol == htons(ETH_P_IPV6))
diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c
index f7dd8de..1c1eae0 100644
--- a/drivers/infiniband/sw/rxe/rxe_req.c
+++ b/drivers/infiniband/sw/rxe/rxe_req.c
@@ -500,6 +500,12 @@ static int fill_packet(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
if (err)
return err;
}
+ if (bth_pad(pkt)) {
+ u8 *pad = payload_addr(pkt) + paylen;
+
+ memset(pad, 0, bth_pad(pkt));
+ crc = rxe_crc32(rxe, crc, pad, bth_pad(pkt));
+ }
}
p = payload_addr(pkt) + paylen + bth_pad(pkt);
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index 681d8e0..9078cfd 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -737,6 +737,13 @@ static enum resp_states read_reply(struct rxe_qp *qp,
if (err)
pr_err("Failed copying memory\n");
+ if (bth_pad(&ack_pkt)) {
+ struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+ u8 *pad = payload_addr(&ack_pkt) + payload;
+
+ memset(pad, 0, bth_pad(&ack_pkt));
+ icrc = rxe_crc32(rxe, icrc, pad, bth_pad(&ack_pkt));
+ }
p = payload_addr(&ack_pkt) + payload + bth_pad(&ack_pkt);
*p = ~icrc;
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 3fecd87..b4e0ae0 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -646,6 +646,7 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
if (ib_conn->pi_support) {
u32 sig_caps = ib_conn->device->ib_device->attrs.sig_prot_cap;
+ shost->sg_prot_tablesize = shost->sg_tablesize;
scsi_host_set_prot(shost, iser_dif_prot_caps(sig_caps));
scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP |
SHOST_DIX_GUARD_CRC);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index a7ace07..e8f98de 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -3162,6 +3162,8 @@ static int __maybe_unused mxt_suspend(struct device *dev)
mutex_unlock(&input_dev->mutex);
+ disable_irq(data->irq);
+
return 0;
}
@@ -3174,6 +3176,8 @@ static int __maybe_unused mxt_resume(struct device *dev)
if (!input_dev)
return 0;
+ enable_irq(data->irq);
+
mutex_lock(&input_dev->mutex);
if (input_dev->users)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index a168ce5..d80c98f 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -2230,6 +2230,14 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
cfg->cbndx = ret;
+ if (!(smmu_domain->attributes & (1 << DOMAIN_ATTR_GEOMETRY))) {
+ /* Geometry is not set use the default geometry */
+ domain->geometry.aperture_start = 0;
+ domain->geometry.aperture_end = (1UL << ias) - 1;
+ if (domain->geometry.aperture_end >= SZ_1G * 4ULL)
+ domain->geometry.aperture_end = (SZ_1G * 4ULL) - 1;
+ }
+
if (arm_smmu_is_slave_side_secure(smmu_domain)) {
smmu_domain->pgtbl_cfg = (struct io_pgtable_cfg) {
.quirks = quirks,
@@ -2240,6 +2248,8 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
},
.tlb = smmu_domain->tlb_ops,
.iommu_dev = smmu->dev,
+ .iova_base = domain->geometry.aperture_start,
+ .iova_end = domain->geometry.aperture_end,
};
fmt = ARM_MSM_SECURE;
} else {
@@ -2250,6 +2260,8 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
.oas = oas,
.tlb = smmu_domain->tlb_ops,
.iommu_dev = smmu->dev,
+ .iova_base = domain->geometry.aperture_start,
+ .iova_end = domain->geometry.aperture_end,
};
}
@@ -2336,6 +2348,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
smmu_domain->smmu = NULL;
out_logger:
iommu_logger_unregister(smmu_domain->logger);
+ smmu_domain->logger = NULL;
out_unlock:
mutex_unlock(&smmu_domain->init_mutex);
return ret;
@@ -2927,6 +2940,8 @@ static int arm_smmu_setup_default_domain(struct device *dev,
const char *str;
int attr = 1;
u32 val;
+ const __be32 *ranges;
+ int naddr, nsize, len;
np = arm_iommu_get_of_node(dev);
if (!np)
@@ -3003,6 +3018,30 @@ static int arm_smmu_setup_default_domain(struct device *dev,
if (of_property_read_bool(np, "qcom,iommu-earlymap"))
__arm_smmu_domain_set_attr(domain,
DOMAIN_ATTR_EARLY_MAP, &attr);
+
+ ranges = of_get_property(np, "qcom,iommu-geometry", &len);
+ if (ranges) {
+ struct iommu_domain_geometry geometry;
+
+ len /= sizeof(u32);
+ naddr = of_n_addr_cells(np);
+ nsize = of_n_size_cells(np);
+ if (len < naddr + nsize) {
+ dev_err(dev, "Invalid length for qcom,iommu-geometry, expected %d cells\n",
+ naddr + nsize);
+ return -EINVAL;
+ }
+ if (naddr == 0 || nsize == 0) {
+ dev_err(dev, "Invalid #address-cells %d or #size-cells %d\n",
+ naddr, nsize);
+ return -EINVAL;
+ }
+
+ geometry.aperture_start = of_read_number(ranges, naddr);
+ geometry.aperture_end = of_read_number(ranges + naddr, nsize);
+ __arm_smmu_domain_set_attr(domain, DOMAIN_ATTR_GEOMETRY,
+ &geometry);
+ }
return 0;
}
@@ -4006,6 +4045,40 @@ static int __arm_smmu_domain_set_attr2(struct iommu_domain *domain,
ret = 0;
break;
}
+
+ case DOMAIN_ATTR_GEOMETRY: {
+ struct iommu_domain_geometry *geometry =
+ (struct iommu_domain_geometry *)data;
+
+ if (smmu_domain->smmu != NULL) {
+ dev_err(smmu_domain->smmu->dev,
+ "cannot set geometry attribute while attached\n");
+ ret = -EBUSY;
+ break;
+ }
+
+ if (geometry->aperture_start >= SZ_1G * 4ULL ||
+ geometry->aperture_end >= SZ_1G * 4ULL) {
+ pr_err("fastmap does not support IOVAs >= 4GB\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ if (geometry->aperture_start
+ < domain->geometry.aperture_start)
+ domain->geometry.aperture_start =
+ geometry->aperture_start;
+
+ if (geometry->aperture_end
+ > domain->geometry.aperture_end)
+ domain->geometry.aperture_end =
+ geometry->aperture_end;
+
+ smmu_domain->attributes |= 1 << DOMAIN_ATTR_GEOMETRY;
+ ret = 0;
+ break;
+ }
+
default:
ret = -ENODEV;
}
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index 53ff42a..8c3402d 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*/
#include <linux/dma-contiguous.h>
@@ -210,7 +210,11 @@ static dma_addr_t __fast_smmu_alloc_iova(struct dma_fast_smmu_mapping *mapping,
iommu_tlbiall(mapping->domain);
mapping->have_stale_tlbs = false;
- av8l_fast_clear_stale_ptes(mapping->pgtbl_ops, skip_sync);
+ av8l_fast_clear_stale_ptes(mapping->pgtbl_ops,
+ mapping->domain->geometry.aperture_start,
+ mapping->base,
+ mapping->base + mapping->size - 1,
+ skip_sync);
}
return (bit << FAST_PAGE_SHIFT) + mapping->base;
@@ -1075,7 +1079,7 @@ static const struct dma_map_ops fast_smmu_dma_ops = {
*
* Creates a mapping structure which holds information about used/unused IO
* address ranges, which is required to perform mapping with IOMMU aware
- * functions. The only VA range supported is [0, 4GB).
+ * functions. The only VA range supported is [0, 4GB].
*
* The client device need to be attached to the mapping with
* fast_smmu_attach_device function.
@@ -1219,6 +1223,9 @@ int fast_smmu_init_mapping(struct device *dev,
fast->dev = dev;
domain->iova_cookie = fast;
+ domain->geometry.aperture_start = mapping->base;
+ domain->geometry.aperture_end = mapping->base + size - 1;
+
if (iommu_domain_get_attr(domain, DOMAIN_ATTR_PGTBL_INFO,
&info)) {
dev_err(dev, "Couldn't get page table info\n");
diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c
index 1207037..07c8d38 100644
--- a/drivers/iommu/io-pgtable-fast.c
+++ b/drivers/iommu/io-pgtable-fast.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "io-pgtable-fast: " fmt
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/io-pgtable-fast.h>
+#include <linux/mm.h>
#include <asm/cacheflush.h>
#include <linux/vmalloc.h>
@@ -35,6 +36,10 @@ struct av8l_fast_io_pgtable {
av8l_fast_iopte *puds[4];
av8l_fast_iopte *pmds;
struct page **pages; /* page table memory */
+ int nr_pages;
+ dma_addr_t base;
+ dma_addr_t start;
+ dma_addr_t end;
};
/* Page table bits */
@@ -143,7 +148,7 @@ struct av8l_fast_io_pgtable {
#define PTE_SH_IDX(pte) (pte & AV8L_FAST_PTE_SH_MASK)
-#define iopte_pmd_offset(pmds, iova) (pmds + (iova >> 12))
+#define iopte_pmd_offset(pmds, base, iova) (pmds + ((iova - base) >> 12))
#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST_PROVE_TLB
@@ -172,13 +177,15 @@ static void __av8l_check_for_stale_tlb(av8l_fast_iopte *ptep)
}
}
-void av8l_fast_clear_stale_ptes(struct io_pgtable_ops *ops, bool skip_sync)
+void av8l_fast_clear_stale_ptes(struct io_pgtable_ops *ops, u64 base,
+ u64 start, u64 end, bool skip_sync)
{
int i;
struct av8l_fast_io_pgtable *data = iof_pgtable_ops_to_data(ops);
- av8l_fast_iopte *pmdp = data->pmds;
+ av8l_fast_iopte *pmdp = iopte_pmd_offset(pmds, base, start);
- for (i = 0; i < ((SZ_1G * 4UL) >> AV8L_FAST_PAGE_SHIFT); ++i) {
+ for (i = start >> AV8L_FAST_PAGE_SHIFT;
+ i <= (end >> AV8L_FAST_PAGE_SHIFT); ++i) {
if (!(*pmdp & AV8L_FAST_PTE_VALID)) {
*pmdp = 0;
if (!skip_sync)
@@ -233,7 +240,7 @@ static int av8l_fast_map(struct io_pgtable_ops *ops, unsigned long iova,
phys_addr_t paddr, size_t size, int prot)
{
struct av8l_fast_io_pgtable *data = iof_pgtable_ops_to_data(ops);
- av8l_fast_iopte *ptep = iopte_pmd_offset(data->pmds, iova);
+ av8l_fast_iopte *ptep = iopte_pmd_offset(data->pmds, data->base, iova);
unsigned long i, nptes = size >> AV8L_FAST_PAGE_SHIFT;
av8l_fast_iopte pte;
@@ -265,7 +272,7 @@ __av8l_fast_unmap(struct io_pgtable_ops *ops, unsigned long iova,
? AV8L_FAST_PTE_UNMAPPED_NEED_TLBI
: 0;
- ptep = iopte_pmd_offset(data->pmds, iova);
+ ptep = iopte_pmd_offset(data->pmds, data->base, iova);
nptes = size >> AV8L_FAST_PAGE_SHIFT;
memset(ptep, val, sizeof(*ptep) * nptes);
@@ -363,7 +370,7 @@ static bool av8l_fast_iova_coherent(struct io_pgtable_ops *ops,
unsigned long iova)
{
struct av8l_fast_io_pgtable *data = iof_pgtable_ops_to_data(ops);
- av8l_fast_iopte *ptep = iopte_pmd_offset(data->pmds, iova);
+ av8l_fast_iopte *ptep = iopte_pmd_offset(data->pmds, data->base, iova);
return ((PTE_MAIR_IDX(*ptep) == AV8L_FAST_MAIR_ATTR_IDX_CACHE) &&
((PTE_SH_IDX(*ptep) == AV8L_FAST_PTE_SH_OS) ||
@@ -397,7 +404,7 @@ av8l_fast_alloc_pgtable_data(struct io_pgtable_cfg *cfg)
}
/*
- * We need 1 page for the pgd, 4 pages for puds (1GB VA per pud page) and
+ * We need max 1 page for the pgd, 4 pages for puds (1GB VA per pud page) and
* 2048 pages for pmds (each pud page contains 512 table entries, each
* pointing to a pmd).
*/
@@ -406,12 +413,38 @@ av8l_fast_alloc_pgtable_data(struct io_pgtable_cfg *cfg)
#define NUM_PMD_PAGES 2048
#define NUM_PGTBL_PAGES (NUM_PGD_PAGES + NUM_PUD_PAGES + NUM_PMD_PAGES)
+/* undefine arch specific definitions which depends on page table format */
+#undef pud_index
+#undef pud_mask
+#undef pud_next
+#undef pmd_index
+#undef pmd_mask
+#undef pmd_next
+
+#define pud_index(addr) (((addr) >> 30) & 0x3)
+#define pud_mask(addr) ((addr) & ~((1UL << 30) - 1))
+#define pud_next(addr, end) \
+({ unsigned long __boundary = pud_mask(addr + (1UL << 30));\
+ (__boundary - 1 < (end) - 1) ? __boundary : (end); \
+})
+
+#define pmd_index(addr) (((addr) >> 21) & 0x1ff)
+#define pmd_mask(addr) ((addr) & ~((1UL << 21) - 1))
+#define pmd_next(addr, end) \
+({ unsigned long __boundary = pmd_mask(addr + (1UL << 21));\
+ (__boundary - 1 < (end) - 1) ? __boundary : (end); \
+})
+
static int
av8l_fast_prepopulate_pgtables(struct av8l_fast_io_pgtable *data,
struct io_pgtable_cfg *cfg, void *cookie)
{
int i, j, pg = 0;
struct page **pages, *page;
+ dma_addr_t base = cfg->iova_base;
+ dma_addr_t end = cfg->iova_end;
+ dma_addr_t pud, pmd;
+ int pmd_pg_index;
pages = kmalloc(sizeof(*pages) * NUM_PGTBL_PAGES, __GFP_NOWARN |
__GFP_NORETRY);
@@ -429,10 +462,11 @@ av8l_fast_prepopulate_pgtables(struct av8l_fast_io_pgtable *data,
data->pgd = page_address(page);
/*
- * We need 2048 entries at level 2 to map 4GB of VA space. A page
- * can hold 512 entries, so we need 4 pages.
+ * We need max 2048 entries at level 2 to map 4GB of VA space. A page
+ * can hold 512 entries, so we need max 4 pages.
*/
- for (i = 0; i < 4; ++i) {
+ for (i = pud_index(base), pud = base; pud < end;
+ ++i, pud = pud_next(pud, end)) {
av8l_fast_iopte pte, *ptep;
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
@@ -447,12 +481,15 @@ av8l_fast_prepopulate_pgtables(struct av8l_fast_io_pgtable *data,
dmac_clean_range(data->pgd, data->pgd + 4);
/*
- * We have 4 puds, each of which can point to 512 pmds, so we'll
- * have 2048 pmds, each of which can hold 512 ptes, for a grand
+ * We have max 4 puds, each of which can point to 512 pmds, so we'll
+ * have max 2048 pmds, each of which can hold 512 ptes, for a grand
* total of 2048*512=1048576 PTEs.
*/
- for (i = 0; i < 4; ++i) {
- for (j = 0; j < 512; ++j) {
+ pmd_pg_index = pg;
+ for (i = pud_index(base), pud = base; pud < end;
+ ++i, pud = pud_next(pud, end)) {
+ for (j = pmd_index(pud), pmd = pud; pmd < pud_next(pud, end);
+ ++j, pmd = pmd_next(pmd, end)) {
av8l_fast_iopte pte, *pudp;
void *addr;
@@ -471,21 +508,21 @@ av8l_fast_prepopulate_pgtables(struct av8l_fast_io_pgtable *data,
dmac_clean_range(data->puds[i], data->puds[i] + 512);
}
- if (WARN_ON(pg != NUM_PGTBL_PAGES))
- goto err_free_pages;
-
/*
* We map the pmds into a virtually contiguous space so that we
* don't have to traverse the first two levels of the page tables
* to find the appropriate pud. Instead, it will be a simple
* offset from the virtual base of the pmds.
*/
- data->pmds = vmap(&pages[NUM_PGD_PAGES + NUM_PUD_PAGES], NUM_PMD_PAGES,
+ data->pmds = vmap(&pages[pmd_pg_index], pg - pmd_pg_index,
VM_IOREMAP, PAGE_KERNEL);
if (!data->pmds)
goto err_free_pages;
data->pages = pages;
+ data->nr_pages = pg;
+ data->base = base;
+ data->end = end;
return 0;
err_free_pages:
@@ -591,7 +628,7 @@ static void av8l_fast_free_pgtable(struct io_pgtable *iop)
struct av8l_fast_io_pgtable *data = iof_pgtable_to_data(iop);
vunmap(data->pmds);
- for (i = 0; i < NUM_PGTBL_PAGES; ++i)
+ for (i = 0; i < data->nr_pages; ++i)
__free_page(data->pages[i]);
kvfree(data->pages);
kfree(data);
@@ -663,6 +700,7 @@ static int __init av8l_fast_positive_testing(void)
struct av8l_fast_io_pgtable *data;
av8l_fast_iopte *pmds;
u64 max = SZ_1G * 4ULL - 1;
+ u64 base = 0;
cfg = (struct io_pgtable_cfg) {
.quirks = 0,
@@ -670,6 +708,8 @@ static int __init av8l_fast_positive_testing(void)
.ias = 32,
.oas = 32,
.pgsize_bitmap = SZ_4K,
+ .iova_base = base,
+ .iova_end = max,
};
cfg_cookie = &cfg;
@@ -682,81 +722,81 @@ static int __init av8l_fast_positive_testing(void)
pmds = data->pmds;
/* map the entire 4GB VA space with 4K map calls */
- for (iova = 0; iova < max; iova += SZ_4K) {
+ for (iova = base; iova < max; iova += SZ_4K) {
if (WARN_ON(ops->map(ops, iova, iova, SZ_4K, IOMMU_READ))) {
failed++;
continue;
}
}
- if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, 0, 0,
- max)))
+ if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, base,
+ base, max - base)))
failed++;
/* unmap it all */
- for (iova = 0; iova < max; iova += SZ_4K) {
+ for (iova = base; iova < max; iova += SZ_4K) {
if (WARN_ON(ops->unmap(ops, iova, SZ_4K) != SZ_4K))
failed++;
}
/* sweep up TLB proving PTEs */
- av8l_fast_clear_stale_ptes(ops, false);
+ av8l_fast_clear_stale_ptes(pmds, base, base, max, false);
/* map the entire 4GB VA space with 8K map calls */
- for (iova = 0; iova < max; iova += SZ_8K) {
+ for (iova = base; iova < max; iova += SZ_8K) {
if (WARN_ON(ops->map(ops, iova, iova, SZ_8K, IOMMU_READ))) {
failed++;
continue;
}
}
- if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, 0, 0,
- max)))
+ if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, base,
+ base, max - base)))
failed++;
/* unmap it all with 8K unmap calls */
- for (iova = 0; iova < max; iova += SZ_8K) {
+ for (iova = base; iova < max; iova += SZ_8K) {
if (WARN_ON(ops->unmap(ops, iova, SZ_8K) != SZ_8K))
failed++;
}
/* sweep up TLB proving PTEs */
- av8l_fast_clear_stale_ptes(ops, false);
+ av8l_fast_clear_stale_ptes(pmds, base, base, max, false);
/* map the entire 4GB VA space with 16K map calls */
- for (iova = 0; iova < max; iova += SZ_16K) {
+ for (iova = base; iova < max; iova += SZ_16K) {
if (WARN_ON(ops->map(ops, iova, iova, SZ_16K, IOMMU_READ))) {
failed++;
continue;
}
}
- if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, 0, 0,
- max)))
+ if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, base,
+ base, max - base)))
failed++;
/* unmap it all */
- for (iova = 0; iova < max; iova += SZ_16K) {
+ for (iova = base; iova < max; iova += SZ_16K) {
if (WARN_ON(ops->unmap(ops, iova, SZ_16K) != SZ_16K))
failed++;
}
/* sweep up TLB proving PTEs */
- av8l_fast_clear_stale_ptes(ops, false);
+ av8l_fast_clear_stale_ptes(pmds, base, base, max, false);
/* map the entire 4GB VA space with 64K map calls */
- for (iova = 0; iova < max; iova += SZ_64K) {
+ for (iova = base; iova < max; iova += SZ_64K) {
if (WARN_ON(ops->map(ops, iova, iova, SZ_64K, IOMMU_READ))) {
failed++;
continue;
}
}
- if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, 0, 0,
- max)))
+ if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, base,
+ base, max - base)))
failed++;
/* unmap it all at once */
- if (WARN_ON(ops->unmap(ops, 0, max) != max))
+ if (WARN_ON(ops->unmap(ops, base, max - base) != (max - base)))
failed++;
free_io_pgtable_ops(ops);
diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h
index 7f8c864..e32e494 100644
--- a/drivers/iommu/io-pgtable.h
+++ b/drivers/iommu/io-pgtable.h
@@ -114,6 +114,8 @@ struct io_pgtable_cfg {
unsigned int oas;
const struct iommu_gather_ops *tlb;
struct device *iommu_dev;
+ dma_addr_t iova_base;
+ dma_addr_t iova_end;
/* Low-level data specific to the table format */
union {
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index c90712a..b0533d1 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -171,21 +171,25 @@ static void iommu_debug_destroy_phoney_sg_table(struct device *dev,
struct iommu_debug_attr {
unsigned long dma_type;
int vmid;
+ struct iommu_domain_geometry geometry;
};
static struct iommu_debug_attr std_attr = {
.dma_type = 0,
.vmid = 0,
+ .geometry = {0, 0, 0},
};
static struct iommu_debug_attr fastmap_attr = {
.dma_type = DOMAIN_ATTR_FAST,
.vmid = 0,
+ .geometry = {0, (dma_addr_t)(SZ_1G * 4ULL - 1), 0},
};
static struct iommu_debug_attr secure_attr = {
.dma_type = 0,
.vmid = VMID_CP_PIXEL,
+ .geometry = {0, 0, 0},
};
static int iommu_debug_set_attrs(struct iommu_debug_device *ddev,
@@ -204,6 +208,10 @@ static int iommu_debug_set_attrs(struct iommu_debug_device *ddev,
iommu_domain_set_attr(domain,
DOMAIN_ATTR_SECURE_VMID, &attrs->vmid);
+ if (attrs->geometry.aperture_end || attrs->geometry.aperture_start)
+ iommu_domain_set_attr(domain,
+ DOMAIN_ATTR_GEOMETRY, &attrs->geometry);
+
return 0;
}
diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index a27debb..19259ae 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -318,7 +318,7 @@ static DEFINE_MUTEX(iova_cache_mutex);
struct iova *alloc_iova_mem(void)
{
- return kmem_cache_alloc(iova_cache, GFP_ATOMIC);
+ return kmem_cache_zalloc(iova_cache, GFP_ATOMIC);
}
EXPORT_SYMBOL(alloc_iova_mem);
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index ad3e2b9..140b287 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -977,13 +977,13 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
if (!dma_dev)
return NULL;
- rk_domain = devm_kzalloc(dma_dev, sizeof(*rk_domain), GFP_KERNEL);
+ rk_domain = kzalloc(sizeof(*rk_domain), GFP_KERNEL);
if (!rk_domain)
return NULL;
if (type == IOMMU_DOMAIN_DMA &&
iommu_get_dma_cookie(&rk_domain->domain))
- return NULL;
+ goto err_free_domain;
/*
* rk32xx iommus use a 2 level pagetable.
@@ -1018,6 +1018,8 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
err_put_cookie:
if (type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(&rk_domain->domain);
+err_free_domain:
+ kfree(rk_domain);
return NULL;
}
@@ -1046,6 +1048,7 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
if (domain->type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(&rk_domain->domain);
+ kfree(rk_domain);
}
static int rk_iommu_add_device(struct device *dev)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 121d3cb..fa0ecb5 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -164,9 +164,9 @@ static bool smmu_dma_addr_valid(struct tegra_smmu *smmu, dma_addr_t addr)
return (addr & smmu->pfn_mask) == addr;
}
-static dma_addr_t smmu_pde_to_dma(u32 pde)
+static dma_addr_t smmu_pde_to_dma(struct tegra_smmu *smmu, u32 pde)
{
- return pde << 12;
+ return (dma_addr_t)(pde & smmu->pfn_mask) << 12;
}
static void smmu_flush_ptc_all(struct tegra_smmu *smmu)
@@ -551,6 +551,7 @@ static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as *as, unsigned long iova,
dma_addr_t *dmap)
{
unsigned int pd_index = iova_pd_index(iova);
+ struct tegra_smmu *smmu = as->smmu;
struct page *pt_page;
u32 *pd;
@@ -559,7 +560,7 @@ static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as *as, unsigned long iova,
return NULL;
pd = page_address(as->pd);
- *dmap = smmu_pde_to_dma(pd[pd_index]);
+ *dmap = smmu_pde_to_dma(smmu, pd[pd_index]);
return tegra_smmu_pte_offset(pt_page, iova);
}
@@ -601,7 +602,7 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
} else {
u32 *pd = page_address(as->pd);
- *dmap = smmu_pde_to_dma(pd[pde]);
+ *dmap = smmu_pde_to_dma(smmu, pd[pde]);
}
return tegra_smmu_pte_offset(as->pts[pde], iova);
@@ -626,7 +627,7 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
if (--as->count[pde] == 0) {
struct tegra_smmu *smmu = as->smmu;
u32 *pd = page_address(as->pd);
- dma_addr_t pte_dma = smmu_pde_to_dma(pd[pde]);
+ dma_addr_t pte_dma = smmu_pde_to_dma(smmu, pd[pde]);
tegra_smmu_set_pde(as, iova, 0);
diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c
index 0f6e30e..f53dfc5 100644
--- a/drivers/irqchip/irq-bcm7038-l1.c
+++ b/drivers/irqchip/irq-bcm7038-l1.c
@@ -284,6 +284,10 @@ static int __init bcm7038_l1_init_one(struct device_node *dn,
pr_err("failed to map parent interrupt %d\n", parent_irq);
return -EINVAL;
}
+
+ if (of_property_read_bool(dn, "brcm,irq-can-wake"))
+ enable_irq_wake(parent_irq);
+
irq_set_chained_handler_and_data(parent_irq, bcm7038_l1_irq_handle,
intc);
diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 2ff0898..be6923ab 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -117,6 +117,14 @@ static int __init ingenic_intc_of_init(struct device_node *node,
goto out_unmap_irq;
}
+ domain = irq_domain_add_legacy(node, num_chips * 32,
+ JZ4740_IRQ_BASE, 0,
+ &irq_domain_simple_ops, NULL);
+ if (!domain) {
+ err = -ENOMEM;
+ goto out_unmap_base;
+ }
+
for (i = 0; i < num_chips; i++) {
/* Mask all irqs */
writel(0xffffffff, intc->base + (i * CHIP_SIZE) +
@@ -143,14 +151,11 @@ static int __init ingenic_intc_of_init(struct device_node *node,
IRQ_NOPROBE | IRQ_LEVEL);
}
- domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0,
- &irq_domain_simple_ops, NULL);
- if (!domain)
- pr_warn("unable to register IRQ domain\n");
-
setup_irq(parent_irq, &intc_cascade_action);
return 0;
+out_unmap_base:
+ iounmap(intc->base);
out_unmap_irq:
irq_dispose_mapping(parent_irq);
out_free:
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 44e132b..0dce3bf 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -208,6 +208,21 @@
This option enables support for the Soekris net4801 and net4826 error
LED.
+config LEDS_QTI_FLASH
+ tristate "Support for QTI Flash LEDs"
+ depends on LEDS_CLASS_FLASH
+ depends on MFD_SPMI_PMIC
+ select LEDS_TRIGGERS
+ help
+ This driver supports flash LED peripheral that is present on
+ some Qualcomm Technologies, Inc. PMICs (e.g. PM8350C). It can
+ configure the flash LED target current for several independent
+ channels. It also supports various over current and over
+ temperature mitigation features.
+
+ To compile this driver as a module, choose M here: the
+ module will be called leds-qti-flash.
+
config LEDS_FSG
tristate "LED Support for the Freecom FSG-3"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 6a8b49a..5afeec6 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -22,6 +22,7 @@
obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
+obj-$(CONFIG_LEDS_QTI_FLASH) += leds-qti-flash.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c
index 4f413a7..d79a66a 100644
--- a/drivers/leds/leds-lm3692x.c
+++ b/drivers/leds/leds-lm3692x.c
@@ -337,9 +337,18 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
return ret;
}
- led->regulator = devm_regulator_get(&led->client->dev, "vled");
- if (IS_ERR(led->regulator))
+ led->regulator = devm_regulator_get_optional(&led->client->dev, "vled");
+ if (IS_ERR(led->regulator)) {
+ ret = PTR_ERR(led->regulator);
+ if (ret != -ENODEV) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&led->client->dev,
+ "Failed to get vled regulator: %d\n",
+ ret);
+ return ret;
+ }
led->regulator = NULL;
+ }
child = device_get_next_child_node(&led->client->dev, child);
if (!child) {
diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c
new file mode 100644
index 0000000..ee855c4
--- /dev/null
+++ b/drivers/leds/leds-qti-flash.c
@@ -0,0 +1,1250 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
+ */
+#define pr_fmt(fmt) "qti-flash: %s: " fmt, __func__
+
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/led-class-flash.h>
+#include <linux/leds-qti-flash.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "leds.h"
+
+#define FLASH_LED_STATUS1 0x06
+
+#define FLASH_LED_STATUS2 0x07
+#define FLASH_LED_VPH_PWR_LOW BIT(0)
+
+#define FLASH_INT_RT_STS 0x10
+#define FLASH_LED_FAULT_RT_STS BIT(0)
+#define FLASH_LED_ALL_RAMP_DN_DONE_RT_STS BIT(3)
+#define FLASH_LED_ALL_RAMP_UP_DONE_RT_STS BIT(4)
+
+#define FLASH_LED_SAFETY_TIMER(id) (0x3E + id)
+#define FLASH_LED_SAFETY_TIMER_EN_MASK BIT(7)
+#define FLASH_LED_SAFETY_TIMER_EN BIT(7)
+#define SAFETY_TIMER_MAX_TIMEOUT_MS 1280
+#define SAFETY_TIMER_MIN_TIMEOUT_MS 10
+#define SAFETY_TIMER_STEP_SIZE 10
+
+/* Default timer duration is 200ms */
+#define SAFETY_TIMER_DEFAULT_DURATION 0x13
+
+#define FLASH_LED_ITARGET(id) (0x42 + id)
+#define FLASH_LED_ITARGET_MASK GENMASK(6, 0)
+
+#define FLASH_ENABLE_CONTROL 0x46
+#define FLASH_MODULE_ENABLE BIT(7)
+#define FLASH_MODULE_DISABLE 0x0
+
+#define FLASH_LED_IRESOLUTION 0x49
+#define FLASH_LED_IRESOLUTION_MASK(id) BIT(id)
+
+#define FLASH_LED_STROBE_CTRL(id) (0x4A + id)
+#define FLASH_LED_STROBE_CFG_MASK GENMASK(6, 4)
+#define FLASH_LED_STROBE_CFG_SHIFT 4
+#define FLASH_LED_HW_SW_STROBE_SEL BIT(2)
+#define FLASH_LED_STROBE_SEL_SHIFT 2
+
+#define FLASH_EN_LED_CTRL 0x4E
+#define FLASH_LED_ENABLE(id) BIT(id)
+#define FLASH_LED_DISABLE 0
+
+#define MAX_IRES_LEVELS 2
+#define IRES_12P5_MAX_CURR_MA 1500
+#define IRES_5P0_MAX_CURR_MA 640
+#define TORCH_MAX_CURR_MA 500
+#define IRES_12P5_UA 12500
+#define IRES_5P0_UA 5000
+#define IRES_DEFAULT_UA IRES_12P5_UA
+#define MAX_FLASH_CURRENT_MA 1000
+
+enum flash_led_type {
+ FLASH_LED_TYPE_UNKNOWN,
+ FLASH_LED_TYPE_FLASH,
+ FLASH_LED_TYPE_TORCH,
+};
+
+enum strobe_type {
+ SW_STROBE = 0,
+ HW_STROBE,
+};
+
+/* Configurations for each individual flash or torch device */
+struct flash_node_data {
+ struct qti_flash_led *led;
+ struct led_classdev_flash fdev;
+ u32 ires_ua;
+ u32 default_ires_ua;
+ u32 current_ma;
+ u32 max_current;
+ u8 duration;
+ u8 id;
+ u8 updated_ires_idx;
+ u8 ires_idx;
+ u8 strobe_config;
+ u8 strobe_sel;
+ enum flash_led_type type;
+ bool configured;
+ bool enabled;
+};
+
+struct flash_switch_data {
+ struct qti_flash_led *led;
+ struct led_classdev cdev;
+ u32 led_mask;
+ bool enabled;
+ bool symmetry_en;
+};
+
+/**
+ * struct qti_flash_led: Main Flash LED data structure
+ * @pdev : Pointer for platform device
+ * @regmap : Pointer for regmap structure
+ * @fnode : Pointer for array of child LED devices
+ * @snode : Pointer for array of child switch devices
+ * @lock : Spinlock to be used for critical section
+ * @num_fnodes : Number of flash/torch nodes defined in device tree
+ * @num_snodes : Number of switch nodes defined in device tree
+ * @hw_strobe_gpio : Pointer for array of GPIOs for HW strobing
+ * @all_ramp_up_done_irq : IRQ number for all ramp up interrupt
+ * @all_ramp_down_done_irq : IRQ number for all ramp down interrupt
+ * @led_fault_irq : IRQ number for LED fault interrupt
+ * @base : Base address of the flash LED module
+ * @max_channels : Maximum number of channels supported by flash module
+ * @ref_count : Reference count used to enable/disable flash LED
+ */
+struct qti_flash_led {
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ struct flash_node_data *fnode;
+ struct flash_switch_data *snode;
+ spinlock_t lock;
+ u32 num_fnodes;
+ u32 num_snodes;
+ int *hw_strobe_gpio;
+ int all_ramp_up_done_irq;
+ int all_ramp_down_done_irq;
+ int led_fault_irq;
+ int max_current;
+ u16 base;
+ u8 max_channels;
+ u8 ref_count;
+};
+
+static const u32 flash_led_max_ires_values[MAX_IRES_LEVELS] = {
+ IRES_5P0_MAX_CURR_MA, IRES_12P5_MAX_CURR_MA
+};
+
+static int timeout_to_code(u32 timeout)
+{
+ if (timeout < SAFETY_TIMER_MIN_TIMEOUT_MS ||
+ timeout > SAFETY_TIMER_MAX_TIMEOUT_MS)
+ return -EINVAL;
+
+ return DIV_ROUND_CLOSEST(timeout, SAFETY_TIMER_STEP_SIZE) - 1;
+}
+
+static int get_ires_idx(u32 ires_ua)
+{
+ if (ires_ua == IRES_5P0_UA)
+ return 0;
+ else if (ires_ua == IRES_12P5_UA)
+ return 1;
+ else
+ return -EINVAL;
+}
+
+static int current_to_code(u32 target_curr_ma, u32 ires_ua)
+{
+ if (!ires_ua || !target_curr_ma ||
+ (target_curr_ma < DIV_ROUND_CLOSEST(ires_ua, 1000)))
+ return 0;
+
+ return DIV_ROUND_CLOSEST(target_curr_ma * 1000, ires_ua) - 1;
+}
+
+static int qti_flash_led_read(struct qti_flash_led *led, u16 offset,
+ u8 *data, u8 len)
+{
+ int rc;
+ u32 val;
+
+ rc = regmap_bulk_read(led->regmap, (led->base + offset), &val, len);
+ if (rc < 0) {
+ pr_err("Failed to read from 0x%04X rc = %d\n",
+ (led->base + offset), rc);
+ } else {
+ pr_debug("Read 0x%02X from addr 0x%04X\n", val,
+ (led->base + offset));
+ *data = (u8)val;
+ }
+
+ return rc;
+}
+
+static int qti_flash_led_write(struct qti_flash_led *led, u16 offset,
+ u8 *data, u8 len)
+{
+ int rc;
+
+ rc = regmap_bulk_write(led->regmap, (led->base + offset), data,
+ len);
+ if (rc < 0)
+ pr_err("Failed to write to 0x%04X rc = %d\n",
+ (led->base + offset), rc);
+ else
+ pr_debug("Wrote 0x%02X to addr 0x%04X\n", data,
+ (led->base + offset));
+
+ return rc;
+}
+
+static int qti_flash_led_masked_write(struct qti_flash_led *led,
+ u16 offset, u8 mask, u8 data)
+{
+ int rc;
+
+ rc = regmap_update_bits(led->regmap, (led->base + offset),
+ mask, data);
+ if (rc < 0)
+ pr_err("Failed to update bits from 0x%04X, rc = %d\n",
+ (led->base + offset), rc);
+ else
+ pr_debug("Wrote 0x%02X to addr 0x%04X\n", data,
+ (led->base + offset));
+
+ return rc;
+}
+
+static int qti_flash_led_module_control(struct qti_flash_led *led,
+ bool enable)
+{
+ int rc = 0;
+ u8 val;
+
+ if (enable) {
+ if (!led->ref_count) {
+ val = FLASH_MODULE_ENABLE;
+ rc = qti_flash_led_write(led, FLASH_ENABLE_CONTROL,
+ &val, 1);
+ if (rc < 0)
+ return rc;
+ }
+
+ led->ref_count++;
+ } else {
+ if (led->ref_count)
+ led->ref_count--;
+
+ if (!led->ref_count) {
+ val = FLASH_MODULE_DISABLE;
+ rc = qti_flash_led_write(led, FLASH_ENABLE_CONTROL,
+ &val, 1);
+ if (rc < 0)
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+static int qti_flash_led_strobe(struct qti_flash_led *led,
+ u8 mask, u8 value)
+{
+ int rc;
+ bool enable = mask & value;
+
+ spin_lock(&led->lock);
+
+ if (enable) {
+ rc = qti_flash_led_module_control(led, enable);
+ if (rc < 0)
+ goto error;
+
+ rc = qti_flash_led_masked_write(led, FLASH_EN_LED_CTRL,
+ mask, value);
+ if (rc < 0)
+ goto error;
+ } else {
+ rc = qti_flash_led_masked_write(led, FLASH_EN_LED_CTRL,
+ mask, value);
+ if (rc < 0)
+ goto error;
+
+ rc = qti_flash_led_module_control(led, enable);
+ if (rc < 0)
+ goto error;
+ }
+
+error:
+ spin_unlock(&led->lock);
+
+ return rc;
+}
+
+static int qti_flash_led_enable(struct flash_node_data *fnode)
+{
+ struct qti_flash_led *led = fnode->led;
+ int rc;
+ u8 val, addr_offset;
+
+ addr_offset = fnode->id;
+
+ spin_lock(&led->lock);
+ val = (fnode->updated_ires_idx ? 0 : 1) << fnode->id;
+ rc = qti_flash_led_masked_write(led, FLASH_LED_IRESOLUTION,
+ FLASH_LED_IRESOLUTION_MASK(fnode->id), val);
+ if (rc < 0)
+ goto out;
+
+ rc = qti_flash_led_masked_write(led,
+ FLASH_LED_ITARGET(addr_offset), FLASH_LED_ITARGET_MASK,
+ current_to_code(fnode->current_ma, fnode->ires_ua));
+ if (rc < 0)
+ goto out;
+
+ /*
+ * For dynamic brightness control of Torch LEDs,
+ * just configure the target current.
+ */
+ if (fnode->type == FLASH_LED_TYPE_TORCH && fnode->enabled) {
+ spin_unlock(&led->lock);
+ return 0;
+ }
+
+ if (fnode->type == FLASH_LED_TYPE_FLASH && fnode->duration) {
+ val = fnode->duration | FLASH_LED_SAFETY_TIMER_EN;
+ rc = qti_flash_led_write(led,
+ FLASH_LED_SAFETY_TIMER(addr_offset), &val, 1);
+ if (rc < 0)
+ goto out;
+ } else {
+ rc = qti_flash_led_masked_write(led,
+ FLASH_LED_SAFETY_TIMER(addr_offset),
+ FLASH_LED_SAFETY_TIMER_EN_MASK, 0);
+ if (rc < 0)
+ goto out;
+ }
+
+ fnode->configured = true;
+
+ if ((fnode->strobe_sel == HW_STROBE) &&
+ gpio_is_valid(led->hw_strobe_gpio[fnode->id]))
+ gpio_set_value(led->hw_strobe_gpio[fnode->id], 1);
+
+out:
+ spin_unlock(&led->lock);
+ return rc;
+}
+
+static int qti_flash_led_disable(struct flash_node_data *fnode)
+{
+ struct qti_flash_led *led = fnode->led;
+ int rc;
+
+ spin_lock(&led->lock);
+ if ((fnode->strobe_sel == HW_STROBE) &&
+ gpio_is_valid(led->hw_strobe_gpio[fnode->id]))
+ gpio_set_value(led->hw_strobe_gpio[fnode->id], 0);
+
+ rc = qti_flash_led_masked_write(led,
+ FLASH_LED_ITARGET(fnode->id), FLASH_LED_ITARGET_MASK, 0);
+ if (rc < 0)
+ goto out;
+
+ rc = qti_flash_led_masked_write(led,
+ FLASH_LED_SAFETY_TIMER(fnode->id),
+ FLASH_LED_SAFETY_TIMER_EN_MASK, 0);
+ if (rc < 0)
+ goto out;
+
+ fnode->current_ma = 0;
+
+out:
+ spin_unlock(&led->lock);
+ return rc;
+}
+
+static enum led_brightness qti_flash_led_brightness_get(
+ struct led_classdev *led_cdev)
+{
+ return led_cdev->brightness;
+}
+
+static void qti_flash_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct qti_flash_led *led = NULL;
+ struct flash_node_data *fnode = NULL;
+ struct led_classdev_flash *fdev = NULL;
+ int rc;
+ u32 current_ma = brightness;
+ u32 min_current_ma;
+
+ fdev = container_of(led_cdev, struct led_classdev_flash, led_cdev);
+ fnode = container_of(fdev, struct flash_node_data, fdev);
+ led = fnode->led;
+
+ if (brightness <= 0) {
+ rc = qti_flash_led_disable(fnode);
+ if (rc < 0)
+ pr_err("Failed to set brightness %d to LED\n",
+ brightness);
+ return;
+ }
+
+ min_current_ma = DIV_ROUND_CLOSEST(fnode->ires_ua, 1000);
+ if (current_ma < min_current_ma)
+ current_ma = min_current_ma;
+
+ fnode->updated_ires_idx = fnode->ires_idx;
+ fnode->ires_ua = fnode->default_ires_ua;
+
+ current_ma = min(current_ma, fnode->max_current);
+ if (current_ma > flash_led_max_ires_values[fnode->ires_idx]) {
+ if (current_ma > IRES_5P0_MAX_CURR_MA)
+ fnode->ires_ua = IRES_12P5_UA;
+ else
+ fnode->ires_ua = IRES_5P0_UA;
+ fnode->ires_idx = get_ires_idx(fnode->ires_ua);
+ }
+
+ fnode->current_ma = current_ma;
+ led_cdev->brightness = current_ma;
+
+ rc = qti_flash_led_enable(fnode);
+ if (rc < 0)
+ pr_err("Failed to set brightness %d to LED\n", brightness);
+}
+
+static int qti_flash_led_symmetry_config(
+ struct flash_switch_data *snode)
+{
+ struct qti_flash_led *led = snode->led;
+ int i, total_curr_ma = 0, symmetric_leds = 0, per_led_curr_ma;
+ enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN;
+
+ /* Determine which LED type has triggered switch ON */
+ for (i = 0; i < led->num_fnodes; i++) {
+ if ((snode->led_mask & BIT(led->fnode[i].id)) &&
+ (led->fnode[i].configured))
+ type = led->fnode[i].type;
+ }
+
+ if (type == FLASH_LED_TYPE_UNKNOWN) {
+ pr_err("Error in symmetry configuration for switch device\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if ((snode->led_mask & BIT(led->fnode[i].id)) &&
+ (led->fnode[i].type == type)) {
+ total_curr_ma += led->fnode[i].current_ma;
+ symmetric_leds++;
+ }
+ }
+
+ if (symmetric_leds > 0 && total_curr_ma > 0) {
+ per_led_curr_ma = total_curr_ma / symmetric_leds;
+ } else {
+ pr_err("Incorrect configuration, symmetric_leds: %d total_curr_ma: %d\n",
+ symmetric_leds, total_curr_ma);
+ return -EINVAL;
+ }
+
+ if (per_led_curr_ma == 0) {
+ pr_warn("per_led_curr_ma cannot be 0\n");
+ return 0;
+ }
+
+ pr_debug("symmetric_leds: %d total: %d per_led_curr_ma: %d\n",
+ symmetric_leds, total_curr_ma, per_led_curr_ma);
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (snode->led_mask & BIT(led->fnode[i].id) &&
+ led->fnode[i].type == type) {
+ qti_flash_led_brightness_set(
+ &led->fnode[i].fdev.led_cdev, per_led_curr_ma);
+ }
+ }
+
+ return 0;
+}
+
+static int qti_flash_switch_enable(struct flash_switch_data *snode)
+{
+ struct qti_flash_led *led = snode->led;
+ int rc = 0, i;
+ u8 led_en = 0;
+
+ /* If symmetry enabled switch, then turn ON all its LEDs */
+ if (snode->symmetry_en) {
+ rc = qti_flash_led_symmetry_config(snode);
+ if (rc < 0) {
+ pr_err("Failed to configure switch symmetrically, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ /*
+ * Do not turn ON flash/torch device if
+ * i. the device is not under this switch or
+ * ii. brightness is not configured for device under this switch
+ */
+ if (!(snode->led_mask & BIT(led->fnode[i].id)) ||
+ !led->fnode[i].configured)
+ continue;
+
+ led_en |= (1 << led->fnode[i].id);
+ }
+
+ return qti_flash_led_strobe(led, snode->led_mask, led_en);
+}
+
+static int qti_flash_switch_disable(struct flash_switch_data *snode)
+{
+ struct qti_flash_led *led = snode->led;
+ int rc = 0, i;
+ u8 led_dis = 0;
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ /*
+ * Do not turn OFF flash/torch device if
+ * i. the device is not under this switch or
+ * ii. brightness is not configured for device under this switch
+ */
+ if (!(snode->led_mask & BIT(led->fnode[i].id)) ||
+ !led->fnode[i].configured)
+ continue;
+
+ rc = qti_flash_led_disable(&led->fnode[i]);
+ if (rc < 0) {
+ pr_err("Failed to disable LED%d\n",
+ &led->fnode[i].id);
+ break;
+ }
+
+ led_dis |= (1 << led->fnode[i].id);
+ led->fnode[i].configured = false;
+ }
+
+ return qti_flash_led_strobe(led, led_dis, ~led_dis);
+}
+
+static void qti_flash_led_switch_brightness_set(
+ struct led_classdev *led_cdev, enum led_brightness value)
+{
+ struct flash_switch_data *snode = NULL;
+ int rc = 0;
+ bool state = value > 0;
+
+ snode = container_of(led_cdev, struct flash_switch_data, cdev);
+
+ if (snode->enabled == state) {
+ pr_debug("Switch is already %s!\n",
+ state ? "enabled" : "disabled");
+ return;
+ }
+
+ if (state)
+ rc = qti_flash_switch_enable(snode);
+ else
+ rc = qti_flash_switch_disable(snode);
+
+ if (rc < 0)
+ pr_err("Failed to %s switch, rc=%d\n",
+ state ? "enable" : "disable", rc);
+ else
+ snode->enabled = state;
+}
+
+static ssize_t qti_flash_led_max_current_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct flash_switch_data *snode;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ snode = container_of(led_cdev, struct flash_switch_data, cdev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", snode->led->max_current);
+}
+
+int qti_flash_led_prepare(struct led_trigger *trig, int options,
+ int *max_current)
+{
+ struct led_classdev *led_cdev;
+ struct flash_switch_data *snode;
+
+ if (!trig) {
+ pr_err("Invalid led_trigger\n");
+ return -EINVAL;
+ }
+
+ led_cdev = trigger_to_lcdev(trig);
+ if (!led_cdev) {
+ pr_err("Invalid led_cdev in trigger %s\n", trig->name);
+ return -ENODEV;
+ }
+
+ snode = container_of(led_cdev, struct flash_switch_data, cdev);
+
+ if (options & QUERY_MAX_AVAIL_CURRENT) {
+ *max_current = snode->led->max_current;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(qti_flash_led_prepare);
+
+static struct device_attribute qti_flash_led_attrs[] = {
+ __ATTR(max_current, 0664, qti_flash_led_max_current_show, NULL),
+};
+
+static int qti_flash_brightness_set_blocking(
+ struct led_classdev *led_cdev, enum led_brightness value)
+{
+ qti_flash_led_brightness_set(led_cdev, value);
+
+ return 0;
+}
+
+static int qti_flash_brightness_set(
+ struct led_classdev_flash *fdev, u32 brightness)
+{
+ qti_flash_led_brightness_set(&fdev->led_cdev, brightness);
+
+ return 0;
+}
+
+static int qti_flash_brightness_get(
+ struct led_classdev_flash *fdev, u32 *brightness)
+{
+ *brightness = qti_flash_led_brightness_get(&fdev->led_cdev);
+
+ return 0;
+}
+
+static int qti_flash_strobe_set(struct led_classdev_flash *fdev,
+ bool state)
+{
+ struct flash_node_data *fnode;
+ int rc;
+ u8 mask, value;
+
+ fnode = container_of(fdev, struct flash_node_data, fdev);
+
+ if (fnode->enabled == state)
+ return 0;
+
+ mask = FLASH_LED_ENABLE(fnode->id);
+ value = state ? FLASH_LED_ENABLE(fnode->id) : 0;
+
+ rc = qti_flash_led_strobe(fnode->led, mask, value);
+ if (!rc) {
+ fnode->enabled = state;
+ if (!state)
+ fnode->configured = false;
+ }
+
+ return rc;
+}
+
+static int qti_flash_strobe_get(struct led_classdev_flash *fdev,
+ bool *state)
+{
+ struct flash_node_data *fnode = container_of(fdev,
+ struct flash_node_data, fdev);
+
+ *state = fnode->enabled;
+
+ return 0;
+}
+
+static int qti_flash_timeout_set(struct led_classdev_flash *fdev,
+ u32 timeout)
+{
+ struct qti_flash_led *led;
+ struct flash_node_data *fnode;
+ int rc = 0;
+ u8 val;
+
+ if (timeout < SAFETY_TIMER_MIN_TIMEOUT_MS ||
+ timeout > SAFETY_TIMER_MAX_TIMEOUT_MS)
+ return -EINVAL;
+
+ fnode = container_of(fdev, struct flash_node_data, fdev);
+ led = fnode->led;
+
+ rc = timeout_to_code(timeout);
+ if (rc < 0)
+ return rc;
+ fnode->duration = rc;
+ val = fnode->duration | FLASH_LED_SAFETY_TIMER_EN;
+ rc = qti_flash_led_write(led,
+ FLASH_LED_SAFETY_TIMER(fnode->id), &val, 1);
+
+ return rc;
+}
+
+static const struct led_flash_ops flash_ops = {
+ .flash_brightness_set = qti_flash_brightness_set,
+ .flash_brightness_get = qti_flash_brightness_get,
+ .strobe_set = qti_flash_strobe_set,
+ .strobe_get = qti_flash_strobe_get,
+ .timeout_set = qti_flash_timeout_set,
+};
+
+static int qti_flash_led_setup(struct qti_flash_led *led)
+{
+ int rc = 0, i, addr_offset;
+ u8 val, mask;
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ addr_offset = led->fnode[i].id;
+ rc = qti_flash_led_masked_write(led,
+ FLASH_LED_SAFETY_TIMER(addr_offset),
+ FLASH_LED_SAFETY_TIMER_EN_MASK, 0);
+ if (rc < 0)
+ return rc;
+
+ val = (led->fnode[i].strobe_config <<
+ FLASH_LED_STROBE_CFG_SHIFT) |
+ (led->fnode[i].strobe_sel <<
+ FLASH_LED_STROBE_SEL_SHIFT);
+ mask = FLASH_LED_STROBE_CFG_MASK | FLASH_LED_HW_SW_STROBE_SEL;
+ rc = qti_flash_led_masked_write(led,
+ FLASH_LED_STROBE_CTRL(addr_offset), mask, val);
+ if (rc < 0)
+ return rc;
+ }
+
+ led->max_current = MAX_FLASH_CURRENT_MA;
+
+ return rc;
+}
+
+static irqreturn_t qti_flash_led_irq_handler(int irq, void *_led)
+{
+ struct qti_flash_led *led = _led;
+ int rc;
+ u8 irq_status, led_status1, led_status2;
+
+ rc = qti_flash_led_read(led, FLASH_INT_RT_STS, &irq_status, 1);
+ if (rc < 0)
+ goto exit;
+
+ if (irq == led->led_fault_irq) {
+ if (irq_status & FLASH_LED_FAULT_RT_STS)
+ pr_debug("Led fault open/short/vreg_not_ready detected\n");
+ } else if (irq == led->all_ramp_down_done_irq) {
+ if (irq_status & FLASH_LED_ALL_RAMP_DN_DONE_RT_STS)
+ pr_debug("All LED channels ramp down done detected\n");
+ } else if (irq == led->all_ramp_up_done_irq) {
+ if (irq_status & FLASH_LED_ALL_RAMP_UP_DONE_RT_STS)
+ pr_debug("All LED channels ramp up done detected\n");
+ }
+
+ rc = qti_flash_led_read(led, FLASH_LED_STATUS1, &led_status1, 1);
+ if (rc < 0)
+ goto exit;
+
+ if (led_status1)
+ pr_debug("LED channel open/short fault detected\n");
+
+ rc = qti_flash_led_read(led, FLASH_LED_STATUS2, &led_status2, 1);
+ if (rc < 0)
+ goto exit;
+
+ if (led_status2 & FLASH_LED_VPH_PWR_LOW)
+ pr_debug("LED vph_droop fault detected!\n");
+
+ pr_debug("LED irq handled, irq_status=%02x led_status1=%02x led_status2=%02x\n",
+ irq_status, led_status1, led_status2);
+
+exit:
+ return IRQ_HANDLED;
+}
+
+static int qti_flash_led_register_interrupts(struct qti_flash_led *led)
+{
+ int rc;
+
+ rc = devm_request_threaded_irq(&led->pdev->dev,
+ led->all_ramp_up_done_irq, NULL, qti_flash_led_irq_handler,
+ IRQF_ONESHOT, "flash_all_ramp_up", led);
+ if (rc < 0) {
+ pr_err("Failed to request all_ramp_up_done(%d) IRQ(err:%d)\n",
+ led->all_ramp_up_done_irq, rc);
+ return rc;
+ }
+
+ rc = devm_request_threaded_irq(&led->pdev->dev,
+ led->all_ramp_down_done_irq, NULL, qti_flash_led_irq_handler,
+ IRQF_ONESHOT, "flash_all_ramp_down", led);
+ if (rc < 0) {
+ pr_err("Failed to request all_ramp_down_done(%d) IRQ(err:%d)\n",
+ led->all_ramp_down_done_irq,
+ rc);
+ return rc;
+ }
+
+ rc = devm_request_threaded_irq(&led->pdev->dev,
+ led->led_fault_irq, NULL, qti_flash_led_irq_handler,
+ IRQF_ONESHOT, "flash_fault", led);
+ if (rc < 0) {
+ pr_err("Failed to request led_fault(%d) IRQ(err:%d)\n",
+ led->led_fault_irq, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int register_switch_device(struct qti_flash_led *led,
+ struct flash_switch_data *snode, struct device_node *node)
+{
+ int rc, i;
+
+ rc = of_property_read_string(node, "qcom,led-name",
+ &snode->cdev.name);
+ if (rc < 0) {
+ pr_err("Failed to read switch node name, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_string(node, "qcom,default-led-trigger",
+ &snode->cdev.default_trigger);
+ if (rc < 0) {
+ pr_err("Failed to read trigger name, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,led-mask", &snode->led_mask);
+ if (rc < 0) {
+ pr_err("Failed to read led mask rc=%d\n", rc);
+ return rc;
+ }
+ if ((snode->led_mask > ((1 << led->max_channels) - 1))) {
+ pr_err("Error, Invalid value for led-mask mask=0x%x\n",
+ snode->led_mask);
+ return -EINVAL;
+ }
+
+ snode->symmetry_en = of_property_read_bool(node, "qcom,symmetry-en");
+
+ snode->led = led;
+ snode->cdev.brightness_set = qti_flash_led_switch_brightness_set;
+ snode->cdev.brightness_get = qti_flash_led_brightness_get;
+
+ rc = devm_led_classdev_register(&led->pdev->dev, &snode->cdev);
+ if (rc < 0) {
+ pr_err("Failed to register led switch device:%s\n",
+ snode->cdev.name);
+ return rc;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(qti_flash_led_attrs); i++) {
+ rc = sysfs_create_file(&snode->cdev.dev->kobj,
+ &qti_flash_led_attrs[i].attr);
+ if (rc < 0) {
+ pr_err("Failed to create sysfs attrs, rc=%d\n", rc);
+ goto sysfs_fail;
+ }
+ }
+
+ return 0;
+
+sysfs_fail:
+ while (i >= 0)
+ sysfs_remove_file(&snode->cdev.dev->kobj,
+ &qti_flash_led_attrs[i--].attr);
+ return rc;
+}
+
+static int register_flash_device(struct qti_flash_led *led,
+ struct flash_node_data *fnode, struct device_node *node)
+{
+ struct led_flash_setting *setting;
+ const char *temp_string;
+ int rc;
+ u32 val, default_curr_ma;
+
+ rc = of_property_read_string(node, "qcom,led-name",
+ &fnode->fdev.led_cdev.name);
+ if (rc < 0) {
+ pr_err("Failed to read flash LED names\n");
+ return rc;
+ }
+
+ rc = of_property_read_string(node, "label", &temp_string);
+ if (rc < 0) {
+ pr_err("Failed to read flash LED label\n");
+ return rc;
+ }
+
+ if (!strcmp(temp_string, "flash")) {
+ fnode->type = FLASH_LED_TYPE_FLASH;
+ } else if (!strcmp(temp_string, "torch")) {
+ fnode->type = FLASH_LED_TYPE_TORCH;
+ } else {
+ pr_err("Incorrect flash LED type %s\n", temp_string);
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,id", &val);
+ if (rc < 0) {
+ pr_err("Failed to read flash LED ID\n");
+ return rc;
+ }
+ fnode->id = (u8)val;
+
+ rc = of_property_read_string(node, "qcom,default-led-trigger",
+ &fnode->fdev.led_cdev.default_trigger);
+ if (rc < 0) {
+ pr_err("Failed to read trigger name\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,ires-ua", &val);
+ if (rc < 0) {
+ pr_err("Failed to read current resolution, rc=%d\n", rc);
+ return rc;
+ } else if (!rc) {
+ rc = get_ires_idx(val);
+ if (rc < 0) {
+ pr_err("Incorrect ires-ua configured, ires-ua=%u\n",
+ val);
+ return rc;
+ }
+ fnode->default_ires_ua = fnode->ires_ua = val;
+ fnode->updated_ires_idx = fnode->ires_idx = rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,max-current-ma", &val);
+ if (rc < 0) {
+ pr_err("Failed to read max current, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (fnode->type == FLASH_LED_TYPE_FLASH &&
+ (val > IRES_12P5_MAX_CURR_MA)) {
+ pr_err("Incorrect max-current-ma for flash %u\n",
+ val);
+ return -EINVAL;
+ }
+
+ if (fnode->type == FLASH_LED_TYPE_TORCH &&
+ (val > TORCH_MAX_CURR_MA)) {
+ pr_err("Incorrect max-current-ma for torch %u\n",
+ val);
+ return -EINVAL;
+ }
+
+ fnode->max_current = val;
+ fnode->fdev.led_cdev.max_brightness = val;
+
+ fnode->duration = SAFETY_TIMER_DEFAULT_DURATION;
+ rc = of_property_read_u32(node, "qcom,duration-ms", &val);
+ if (!rc) {
+ rc = timeout_to_code(val);
+ if (rc < 0) {
+ pr_err("Incorrect timeout configured %u\n", val);
+ return rc;
+ }
+ fnode->duration = rc;
+ }
+
+ fnode->strobe_sel = SW_STROBE;
+ rc = of_property_read_u32(node, "qcom,strobe-sel", &val);
+ if (!rc)
+ fnode->strobe_sel = (u8)val;
+
+ if (fnode->strobe_sel == HW_STROBE) {
+ rc = of_property_read_u32(node, "qcom,strobe-config", &val);
+ if (!rc) {
+ fnode->strobe_config = (u8)val;
+ } else {
+ pr_err("Failed to read qcom,strobe-config property\n");
+ return rc;
+ }
+
+ }
+
+ fnode->led = led;
+ fnode->fdev.led_cdev.brightness_set = qti_flash_led_brightness_set;
+ fnode->fdev.led_cdev.brightness_get = qti_flash_led_brightness_get;
+ fnode->enabled = false;
+ fnode->configured = false;
+ fnode->fdev.ops = &flash_ops;
+
+ if (fnode->type == FLASH_LED_TYPE_FLASH) {
+ fnode->fdev.led_cdev.flags = LED_DEV_CAP_FLASH;
+ fnode->fdev.led_cdev.brightness_set_blocking =
+ qti_flash_brightness_set_blocking;
+ }
+
+ default_curr_ma = DIV_ROUND_CLOSEST(fnode->ires_ua, 1000);
+ setting = &fnode->fdev.brightness;
+ setting->min = 0;
+ setting->max = fnode->max_current;
+ setting->step = 1;
+ setting->val = default_curr_ma;
+
+ setting = &fnode->fdev.timeout;
+ setting->min = SAFETY_TIMER_MIN_TIMEOUT_MS;
+ setting->max = SAFETY_TIMER_MAX_TIMEOUT_MS;
+ setting->step = 1;
+ setting->val = SAFETY_TIMER_DEFAULT_DURATION;
+
+ rc = led_classdev_flash_register(&led->pdev->dev, &fnode->fdev);
+ if (rc < 0) {
+ pr_err("Failed to register flash led device:%s\n",
+ fnode->fdev.led_cdev.name);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int qti_flash_led_register_device(struct qti_flash_led *led,
+ struct device_node *node)
+{
+ struct device_node *temp;
+ char buffer[20];
+ const char *label;
+ int rc, i = 0, j = 0;
+ u32 val;
+
+ rc = of_property_read_u32(node, "reg", &val);
+ if (rc < 0) {
+ pr_err("Failed to find reg in node %s, rc = %d\n",
+ node->full_name, rc);
+ return rc;
+ }
+ led->base = val;
+
+ led->hw_strobe_gpio = devm_kcalloc(&led->pdev->dev,
+ led->max_channels, sizeof(u32), GFP_KERNEL);
+ if (!led->hw_strobe_gpio)
+ return -ENOMEM;
+
+ for (i = 0; i < led->max_channels; i++) {
+
+ led->hw_strobe_gpio[i] = -EINVAL;
+
+ rc = of_get_named_gpio(node, "hw-strobe-gpios", i);
+ if (rc < 0) {
+ pr_debug("Failed to get hw strobe gpio, rc = %d\n", rc);
+ continue;
+ }
+
+ if (!gpio_is_valid(rc)) {
+ pr_err("Error, Invalid gpio specified\n");
+ return -EINVAL;
+ }
+ led->hw_strobe_gpio[i] = rc;
+
+ scnprintf(buffer, sizeof(buffer), "hw_strobe_gpio%d", i);
+ rc = devm_gpio_request_one(&led->pdev->dev,
+ led->hw_strobe_gpio[i], GPIOF_DIR_OUT,
+ buffer);
+ if (rc < 0) {
+ pr_err("Failed to acquire gpio rc = %d\n", rc);
+ return rc;
+ }
+
+ gpio_direction_output(led->hw_strobe_gpio[i], 0);
+
+ }
+
+ led->all_ramp_up_done_irq = of_irq_get_byname(node,
+ "all-ramp-up-done-irq");
+ if (led->all_ramp_up_done_irq < 0)
+ pr_debug("all-ramp-up-done-irq not used\n");
+
+ led->all_ramp_down_done_irq = of_irq_get_byname(node,
+ "all-ramp-down-done-irq");
+ if (led->all_ramp_down_done_irq < 0)
+ pr_debug("all-ramp-down-done-irq not used\n");
+
+ led->led_fault_irq = of_irq_get_byname(node,
+ "led-fault-irq");
+ if (led->led_fault_irq < 0)
+ pr_debug("led-fault-irq not used\n");
+
+ for_each_available_child_of_node(node, temp) {
+ rc = of_property_read_string(temp, "label", &label);
+ if (rc < 0) {
+ pr_err("Failed to parse label, rc=%d\n", rc);
+ of_node_put(temp);
+ return rc;
+ }
+
+ if (!strcmp("flash", label) || !strcmp("torch", label)) {
+ led->num_fnodes++;
+ } else if (!strcmp("switch", label)) {
+ led->num_snodes++;
+ } else {
+ pr_err("Invalid label for led node label=%s\n",
+ label);
+ of_node_put(temp);
+ return -EINVAL;
+ }
+ }
+
+ if (!led->num_fnodes) {
+ pr_err("No flash/torch devices defined\n");
+ return -ECHILD;
+ }
+
+ if (!led->num_snodes) {
+ pr_err("No switch devices defined\n");
+ return -ECHILD;
+ }
+
+ led->fnode = devm_kcalloc(&led->pdev->dev, led->num_fnodes,
+ sizeof(*led->fnode), GFP_KERNEL);
+ led->snode = devm_kcalloc(&led->pdev->dev, led->num_snodes,
+ sizeof(*led->snode), GFP_KERNEL);
+ if ((!led->fnode) || (!led->snode))
+ return -ENOMEM;
+
+ i = 0;
+ for_each_available_child_of_node(node, temp) {
+ rc = of_property_read_string(temp, "label", &label);
+ if (rc < 0) {
+ pr_err("Failed to parse label, rc=%d\n", rc);
+ of_node_put(temp);
+ return rc;
+ }
+
+ if (!strcmp("flash", label) || !strcmp("torch", label)) {
+ rc = register_flash_device(led, &led->fnode[i], temp);
+ if (rc < 0) {
+ pr_err("Failed to register flash device %s rc=%d\n",
+ led->fnode[i].fdev.led_cdev.name, rc);
+ of_node_put(temp);
+ goto unreg_led;
+ }
+ led->fnode[i++].fdev.led_cdev.dev->of_node = temp;
+ } else {
+ rc = register_switch_device(led, &led->snode[j], temp);
+ if (rc < 0) {
+ pr_err("Failed to register switch device %s rc=%d\n",
+ led->snode[j].cdev.name, rc);
+ i--;
+ of_node_put(temp);
+ goto unreg_led;
+ }
+ led->snode[j++].cdev.dev->of_node = temp;
+ }
+ }
+
+ return 0;
+
+unreg_led:
+ while (i >= 0)
+ led_classdev_flash_unregister(&led->fnode[i--].fdev);
+
+ return rc;
+}
+
+static int qti_flash_led_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct qti_flash_led *led;
+ int rc;
+
+ led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!led->regmap) {
+ pr_err("Failed to get parent's regmap\n");
+ return -EINVAL;
+ }
+
+ led->max_channels = (u8)of_device_get_match_data(&pdev->dev);
+ if (!led->max_channels) {
+ pr_err("Failed to get max supported led channels\n");
+ return -EINVAL;
+ }
+
+ led->pdev = pdev;
+ spin_lock_init(&led->lock);
+
+ rc = qti_flash_led_register_device(led, node);
+ if (rc < 0) {
+ pr_err("Failed to parse and register LED devices rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qti_flash_led_setup(led);
+ if (rc < 0) {
+ pr_err("Failed to initialize flash LED, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qti_flash_led_register_interrupts(led);
+ if (rc < 0) {
+ pr_err("Failed to register LED interrupts rc=%d\n", rc);
+ return rc;
+ }
+
+ dev_set_drvdata(&pdev->dev, led);
+
+ return 0;
+}
+
+static int qti_flash_led_remove(struct platform_device *pdev)
+{
+ struct qti_flash_led *led = dev_get_drvdata(&pdev->dev);
+ int i, j;
+
+ for (i = 0; (i < led->num_snodes); i++) {
+ for (j = 0; j < ARRAY_SIZE(qti_flash_led_attrs); j++)
+ sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
+ &qti_flash_led_attrs[j].attr);
+
+ led_classdev_unregister(&led->snode[i].cdev);
+ }
+
+ for (i = 0; (i < led->num_fnodes); i++)
+ led_classdev_flash_unregister(&led->fnode[i].fdev);
+
+ return 0;
+}
+
+const static struct of_device_id qti_flash_led_match_table[] = {
+ { .compatible = "qcom,pm8350c-flash-led", .data = (void *)4, },
+ { .compatible = "qcom,pm2250-flash-led", .data = (void *)1, },
+ { },
+};
+
+static struct platform_driver qti_flash_led_driver = {
+ .driver = {
+ .name = "leds-qti-flash",
+ .of_match_table = qti_flash_led_match_table,
+ },
+ .probe = qti_flash_led_probe,
+ .remove = qti_flash_led_remove,
+};
+
+module_platform_driver(qti_flash_led_driver);
+
+MODULE_DESCRIPTION("QTI Flash LED driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index 363d35d..2f47023 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -214,8 +214,10 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
struct imx_mu_con_priv *cp = chan->con_priv;
- if (cp->type == IMX_MU_TYPE_TXDB)
+ if (cp->type == IMX_MU_TYPE_TXDB) {
tasklet_kill(&cp->txdb_tasklet);
+ return;
+ }
imx_mu_xcr_rmw(priv, 0,
IMX_MU_xCR_TIEn(cp->idx) | IMX_MU_xCR_RIEn(cp->idx));
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index 9c3beb1..46794ca 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -377,7 +377,10 @@ static int bch_allocator_thread(void *arg)
if (!fifo_full(&ca->free_inc))
goto retry_invalidate;
- bch_prio_write(ca);
+ if (bch_prio_write(ca, false) < 0) {
+ ca->invalidate_needs_gc = 1;
+ wake_up_gc(ca->set);
+ }
}
}
out:
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 83f0b91..4677b18 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -959,7 +959,7 @@ bool bch_cached_dev_error(struct cached_dev *dc);
__printf(2, 3)
bool bch_cache_set_error(struct cache_set *c, const char *fmt, ...);
-void bch_prio_write(struct cache *ca);
+int bch_prio_write(struct cache *ca, bool wait);
void bch_write_bdev_super(struct cached_dev *dc, struct closure *parent);
extern struct workqueue_struct *bcache_wq;
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 45f6846..bb40bd6 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -713,6 +713,8 @@ static unsigned long bch_mca_scan(struct shrinker *shrink,
* IO can always make forward progress:
*/
nr /= c->btree_pages;
+ if (nr == 0)
+ nr = 1;
nr = min_t(unsigned long, nr, mca_can_free(c));
i = 0;
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 14d381c..c45d9ad 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -525,12 +525,29 @@ static void prio_io(struct cache *ca, uint64_t bucket, int op,
closure_sync(cl);
}
-void bch_prio_write(struct cache *ca)
+int bch_prio_write(struct cache *ca, bool wait)
{
int i;
struct bucket *b;
struct closure cl;
+ pr_debug("free_prio=%zu, free_none=%zu, free_inc=%zu",
+ fifo_used(&ca->free[RESERVE_PRIO]),
+ fifo_used(&ca->free[RESERVE_NONE]),
+ fifo_used(&ca->free_inc));
+
+ /*
+ * Pre-check if there are enough free buckets. In the non-blocking
+ * scenario it's better to fail early rather than starting to allocate
+ * buckets and do a cleanup later in case of failure.
+ */
+ if (!wait) {
+ size_t avail = fifo_used(&ca->free[RESERVE_PRIO]) +
+ fifo_used(&ca->free[RESERVE_NONE]);
+ if (prio_buckets(ca) > avail)
+ return -ENOMEM;
+ }
+
closure_init_stack(&cl);
lockdep_assert_held(&ca->set->bucket_lock);
@@ -540,9 +557,6 @@ void bch_prio_write(struct cache *ca)
atomic_long_add(ca->sb.bucket_size * prio_buckets(ca),
&ca->meta_sectors_written);
- //pr_debug("free %zu, free_inc %zu, unused %zu", fifo_used(&ca->free),
- // fifo_used(&ca->free_inc), fifo_used(&ca->unused));
-
for (i = prio_buckets(ca) - 1; i >= 0; --i) {
long bucket;
struct prio_set *p = ca->disk_buckets;
@@ -560,7 +574,7 @@ void bch_prio_write(struct cache *ca)
p->magic = pset_magic(&ca->sb);
p->csum = bch_crc64(&p->magic, bucket_bytes(ca) - 8);
- bucket = bch_bucket_alloc(ca, RESERVE_PRIO, true);
+ bucket = bch_bucket_alloc(ca, RESERVE_PRIO, wait);
BUG_ON(bucket == -1);
mutex_unlock(&ca->set->bucket_lock);
@@ -589,6 +603,7 @@ void bch_prio_write(struct cache *ca)
ca->prio_last_buckets[i] = ca->prio_buckets[i];
}
+ return 0;
}
static void prio_read(struct cache *ca, uint64_t bucket)
@@ -747,20 +762,28 @@ static inline int idx_to_first_minor(int idx)
static void bcache_device_free(struct bcache_device *d)
{
+ struct gendisk *disk = d->disk;
+
lockdep_assert_held(&bch_register_lock);
- pr_info("%s stopped", d->disk->disk_name);
+ if (disk)
+ pr_info("%s stopped", disk->disk_name);
+ else
+ pr_err("bcache device (NULL gendisk) stopped");
if (d->c)
bcache_device_detach(d);
- if (d->disk && d->disk->flags & GENHD_FL_UP)
- del_gendisk(d->disk);
- if (d->disk && d->disk->queue)
- blk_cleanup_queue(d->disk->queue);
- if (d->disk) {
+
+ if (disk) {
+ if (disk->flags & GENHD_FL_UP)
+ del_gendisk(disk);
+
+ if (disk->queue)
+ blk_cleanup_queue(disk->queue);
+
ida_simple_remove(&bcache_device_idx,
- first_minor_to_idx(d->disk->first_minor));
- put_disk(d->disk);
+ first_minor_to_idx(disk->first_minor));
+ put_disk(disk);
}
bioset_exit(&d->bio_split);
@@ -1876,7 +1899,7 @@ static int run_cache_set(struct cache_set *c)
mutex_lock(&c->bucket_lock);
for_each_cache(ca, c, i)
- bch_prio_write(ca);
+ bch_prio_write(ca, true);
mutex_unlock(&c->bucket_lock);
err = "cannot allocate new UUID bucket";
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 2fc8c11..fd86071 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -2132,6 +2132,7 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
memcpy(page_address(store.sb_page),
page_address(bitmap->storage.sb_page),
sizeof(bitmap_super_t));
+ spin_lock_irq(&bitmap->counts.lock);
md_bitmap_file_unmap(&bitmap->storage);
bitmap->storage = store;
@@ -2147,7 +2148,6 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
blocks = min(old_counts.chunks << old_counts.chunkshift,
chunks << chunkshift);
- spin_lock_irq(&bitmap->counts.lock);
/* For cluster raid, need to pre-allocate bitmap */
if (mddev_is_clustered(bitmap->mddev)) {
unsigned long page;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 6800dcd..abcb4c3 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2756,7 +2756,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
write_targets++;
}
}
- if (bio->bi_end_io) {
+ if (rdev && bio->bi_end_io) {
atomic_inc(&rdev->nr_pending);
bio->bi_iter.bi_sector = sector_nr + rdev->data_offset;
bio_set_dev(bio, rdev->bdev);
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index dd6f3e6..ba7e976 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -365,7 +365,8 @@ static void cec_data_cancel(struct cec_data *data, u8 tx_status)
} else {
list_del_init(&data->list);
if (!(data->msg.tx_status & CEC_TX_STATUS_OK))
- data->adap->transmit_queue_sz--;
+ if (!WARN_ON(!data->adap->transmit_queue_sz))
+ data->adap->transmit_queue_sz--;
}
if (data->msg.tx_status & CEC_TX_STATUS_OK) {
@@ -417,6 +418,14 @@ static void cec_flush(struct cec_adapter *adap)
* need to do anything special in that case.
*/
}
+ /*
+ * If something went wrong and this counter isn't what it should
+ * be, then this will reset it back to 0. Warn if it is not 0,
+ * since it indicates a bug, either in this framework or in a
+ * CEC driver.
+ */
+ if (WARN_ON(adap->transmit_queue_sz))
+ adap->transmit_queue_sz = 0;
}
/*
@@ -441,7 +450,7 @@ int cec_thread_func(void *_adap)
bool timeout = false;
u8 attempts;
- if (adap->transmitting) {
+ if (adap->transmit_in_progress) {
int err;
/*
@@ -476,7 +485,7 @@ int cec_thread_func(void *_adap)
goto unlock;
}
- if (adap->transmitting && timeout) {
+ if (adap->transmit_in_progress && timeout) {
/*
* If we timeout, then log that. Normally this does
* not happen and it is an indication of a faulty CEC
@@ -485,14 +494,18 @@ int cec_thread_func(void *_adap)
* so much traffic on the bus that the adapter was
* unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s).
*/
- pr_warn("cec-%s: message %*ph timed out\n", adap->name,
- adap->transmitting->msg.len,
- adap->transmitting->msg.msg);
+ if (adap->transmitting) {
+ pr_warn("cec-%s: message %*ph timed out\n", adap->name,
+ adap->transmitting->msg.len,
+ adap->transmitting->msg.msg);
+ /* Just give up on this. */
+ cec_data_cancel(adap->transmitting,
+ CEC_TX_STATUS_TIMEOUT);
+ } else {
+ pr_warn("cec-%s: transmit timed out\n", adap->name);
+ }
adap->transmit_in_progress = false;
adap->tx_timeouts++;
- /* Just give up on this. */
- cec_data_cancel(adap->transmitting,
- CEC_TX_STATUS_TIMEOUT);
goto unlock;
}
@@ -507,7 +520,8 @@ int cec_thread_func(void *_adap)
data = list_first_entry(&adap->transmit_queue,
struct cec_data, list);
list_del_init(&data->list);
- adap->transmit_queue_sz--;
+ if (!WARN_ON(!data->adap->transmit_queue_sz))
+ adap->transmit_queue_sz--;
/* Make this the current transmitting message */
adap->transmitting = data;
@@ -1038,11 +1052,11 @@ void cec_received_msg_ts(struct cec_adapter *adap,
valid_la = false;
else if (!cec_msg_is_broadcast(msg) && !(dir_fl & DIRECTED))
valid_la = false;
- else if (cec_msg_is_broadcast(msg) && !(dir_fl & BCAST1_4))
+ else if (cec_msg_is_broadcast(msg) && !(dir_fl & BCAST))
valid_la = false;
else if (cec_msg_is_broadcast(msg) &&
- adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0 &&
- !(dir_fl & BCAST2_0))
+ adap->log_addrs.cec_version < CEC_OP_CEC_VERSION_2_0 &&
+ !(dir_fl & BCAST1_4))
valid_la = false;
}
if (valid_la && min_len) {
diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c
index e6a8b56..4b6be3b 100644
--- a/drivers/media/i2c/ov2659.c
+++ b/drivers/media/i2c/ov2659.c
@@ -419,10 +419,14 @@ static struct sensor_register ov2659_720p[] = {
{ REG_TIMING_YINC, 0x11 },
{ REG_TIMING_VERT_FORMAT, 0x80 },
{ REG_TIMING_HORIZ_FORMAT, 0x00 },
+ { 0x370a, 0x12 },
{ 0x3a03, 0xe8 },
{ 0x3a09, 0x6f },
{ 0x3a0b, 0x5d },
{ 0x3a15, 0x9a },
+ { REG_VFIFO_READ_START_H, 0x00 },
+ { REG_VFIFO_READ_START_L, 0x80 },
+ { REG_ISP_CTRL02, 0x00 },
{ REG_NULL, 0x00 },
};
@@ -1203,11 +1207,15 @@ static int ov2659_s_stream(struct v4l2_subdev *sd, int on)
goto unlock;
}
- ov2659_set_pixel_clock(ov2659);
- ov2659_set_frame_size(ov2659);
- ov2659_set_format(ov2659);
- ov2659_set_streaming(ov2659, 1);
- ov2659->streaming = on;
+ ret = ov2659_set_pixel_clock(ov2659);
+ if (!ret)
+ ret = ov2659_set_frame_size(ov2659);
+ if (!ret)
+ ret = ov2659_set_format(ov2659);
+ if (!ret) {
+ ov2659_set_streaming(ov2659, 1);
+ ov2659->streaming = on;
+ }
unlock:
mutex_unlock(&ov2659->lock);
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index edded86..c5aadd8 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -469,38 +469,39 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
- struct v4l2_rect rect = sel->r;
int ret;
if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- v4l_bound_align_image(&rect.width, 2, W_CIF, 1,
- &rect.height, 2, H_CIF, 1, 0);
- v4l_bound_align_image(&rect.left, DEF_HSTRT << 1,
- (DEF_HSTRT << 1) + W_CIF - (__s32)rect.width, 1,
- &rect.top, DEF_VSTRT << 1,
- (DEF_VSTRT << 1) + H_CIF - (__s32)rect.height, 1,
- 0);
+ v4l_bound_align_image(&sel->r.width, 2, W_CIF, 1,
+ &sel->r.height, 2, H_CIF, 1, 0);
+ v4l_bound_align_image(&sel->r.left, DEF_HSTRT << 1,
+ (DEF_HSTRT << 1) + W_CIF - (__s32)sel->r.width, 1,
+ &sel->r.top, DEF_VSTRT << 1,
+ (DEF_VSTRT << 1) + H_CIF - (__s32)sel->r.height,
+ 1, 0);
- ret = ov6650_reg_write(client, REG_HSTRT, rect.left >> 1);
+ ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1);
if (!ret) {
- priv->rect.left = rect.left;
+ priv->rect.width += priv->rect.left - sel->r.left;
+ priv->rect.left = sel->r.left;
ret = ov6650_reg_write(client, REG_HSTOP,
- (rect.left + rect.width) >> 1);
+ (sel->r.left + sel->r.width) >> 1);
}
if (!ret) {
- priv->rect.width = rect.width;
- ret = ov6650_reg_write(client, REG_VSTRT, rect.top >> 1);
+ priv->rect.width = sel->r.width;
+ ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1);
}
if (!ret) {
- priv->rect.top = rect.top;
+ priv->rect.height += priv->rect.top - sel->r.top;
+ priv->rect.top = sel->r.top;
ret = ov6650_reg_write(client, REG_VSTOP,
- (rect.top + rect.height) >> 1);
+ (sel->r.top + sel->r.height) >> 1);
}
if (!ret)
- priv->rect.height = rect.height;
+ priv->rect.height = sel->r.height;
return ret;
}
@@ -614,7 +615,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
return -EINVAL;
}
- priv->code = code;
if (code == MEDIA_BUS_FMT_Y8_1X8 ||
code == MEDIA_BUS_FMT_SBGGR8_1X8) {
@@ -640,7 +640,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
dev_dbg(&client->dev, "max resolution: CIF\n");
coma_mask |= COMA_QCIF;
}
- priv->half_scale = half_scale;
clkrc = CLKRC_12MHz;
mclk = 12000000;
@@ -658,8 +657,13 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
if (!ret)
ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
- if (!ret)
+ if (!ret) {
+ priv->half_scale = half_scale;
+
ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
+ }
+ if (!ret)
+ priv->code = code;
if (!ret) {
mf->colorspace = priv->colorspace;
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 1236683..4731e1c 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -3108,19 +3108,23 @@ static int smiapp_probe(struct i2c_client *client,
if (rval < 0)
goto out_media_entity_cleanup;
- rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd);
- if (rval < 0)
- goto out_media_entity_cleanup;
-
pm_runtime_set_active(&client->dev);
pm_runtime_get_noresume(&client->dev);
pm_runtime_enable(&client->dev);
+
+ rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd);
+ if (rval < 0)
+ goto out_disable_runtime_pm;
+
pm_runtime_set_autosuspend_delay(&client->dev, 1000);
pm_runtime_use_autosuspend(&client->dev);
pm_runtime_put_autosuspend(&client->dev);
return 0;
+out_disable_runtime_pm:
+ pm_runtime_disable(&client->dev);
+
out_media_entity_cleanup:
media_entity_cleanup(&sensor->src->sd.entity);
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index 7b113ba..248fb3b 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1312,7 +1312,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
core = cx88_core_get(dev->pci);
if (!core) {
err = -EINVAL;
- goto fail_free;
+ goto fail_disable;
}
dev->core = core;
@@ -1358,7 +1358,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
cc->step, cc->default_value);
if (!vc) {
err = core->audio_hdl.error;
- goto fail_core;
+ goto fail_irq;
}
vc->priv = (void *)cc;
}
@@ -1372,7 +1372,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
cc->step, cc->default_value);
if (!vc) {
err = core->video_hdl.error;
- goto fail_core;
+ goto fail_irq;
}
vc->priv = (void *)cc;
if (vc->id == V4L2_CID_CHROMA_AGC)
@@ -1535,11 +1535,14 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
fail_unreg:
cx8800_unregister_video(dev);
- free_irq(pci_dev->irq, dev);
mutex_unlock(&core->lock);
+fail_irq:
+ free_irq(pci_dev->irq, dev);
fail_core:
core->v4ldev = NULL;
cx88_core_put(core, dev->pci);
+fail_disable:
+ pci_disable_device(pci_dev);
fail_free:
kfree(dev);
return err;
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
index b05738a..809320d 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -1848,6 +1848,10 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id)
if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD))
return -ENODATA;
+ /* if trying to set the same std then nothing to do */
+ if (vpfe_standards[vpfe->std_index].std_id == std_id)
+ return 0;
+
/* If streaming is started, return error */
if (vb2_is_busy(&vpfe->buffer_queue)) {
vpfe_err(vpfe, "%s device busy\n", __func__);
diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c
index 4b8866f..beb17951 100644
--- a/drivers/media/platform/msm/npu/npu_dev.c
+++ b/drivers/media/platform/msm/npu/npu_dev.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
/* -------------------------------------------------------------------------
@@ -1738,13 +1738,70 @@ int npu_set_bw(struct npu_device *npu_dev, int new_ib, int new_ab)
return ret;
}
+#define NPU_FMAX_THRESHOLD 1000000
+static int npu_adjust_max_power_level(struct npu_device *npu_dev)
+{
+ struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;
+ uint32_t fmax_reg_value, fmax, fmax_pwrlvl;
+ struct npu_pwrlevel *level;
+ int i, j;
+
+ if (!npu_dev->qfprom_io.base)
+ return 0;
+
+ /* search for cal clock index */
+ for (j = 0; j < npu_dev->core_clk_num; j++) {
+ if (!strcmp(npu_dev->core_clks[j].clk_name,
+ "cal_hm0_clk"))
+ break;
+ }
+
+ if (j == npu_dev->core_clk_num) {
+ NPU_WARN("can't find clock cal_hm0_clk\n");
+ return 0;
+ }
+
+ /* Read FMAX info if available */
+ fmax_reg_value = (npu_qfprom_reg_read(npu_dev,
+ QFPROM_FMAX_REG_OFFSET) & QFPROM_FMAX_BITS_MASK) >>
+ QFPROM_FMAX_BITS_SHIFT;
+ NPU_DBG("fmax_reg_value %x\n", fmax_reg_value);
+
+ if (fmax_reg_value == 0)
+ return 0;
+
+ /* calculate fmax and truncate to MHz */
+ fmax = fmax_reg_value * 19200000 / 2;
+
+ /* search for the nearest power level */
+ for (i = 0; i < pwr->num_pwrlevels; i++) {
+ level = &pwr->pwrlevels[i];
+
+ if (level->clk_freq[j] >= fmax ||
+ ((fmax - level->clk_freq[j]) < NPU_FMAX_THRESHOLD)) {
+ fmax_pwrlvl = level->pwr_level;
+ break;
+ }
+ }
+
+ if (i == pwr->num_pwrlevels)
+ return 0;
+
+ if (fmax_pwrlvl < pwr->max_pwrlevel) {
+ pwr->max_pwrlevel = fmax_pwrlvl;
+ NPU_INFO("Adjust max_pwrlevel to %d[%x]\n", fmax_pwrlvl,
+ fmax_reg_value);
+ }
+
+ return 0;
+}
+
static int npu_of_parse_pwrlevels(struct npu_device *npu_dev,
struct device_node *node)
{
struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;
struct device_node *child;
uint32_t init_level_index = 0, init_power_level;
- uint32_t fmax, fmax_pwrlvl;
pwr->num_pwrlevels = 0;
pwr->min_pwrlevel = NPU_PWRLEVEL_TURBO_L1;
@@ -1805,28 +1862,7 @@ static int npu_of_parse_pwrlevels(struct npu_device *npu_dev,
}
}
- /* Read FMAX info if available */
- if (npu_dev->qfprom_io.base) {
- fmax = (npu_qfprom_reg_read(npu_dev,
- QFPROM_FMAX_REG_OFFSET) & QFPROM_FMAX_BITS_MASK) >>
- QFPROM_FMAX_BITS_SHIFT;
- NPU_DBG("fmax %x\n", fmax);
-
- switch (fmax) {
- case 0x34:
- fmax_pwrlvl = NPU_PWRLEVEL_SVS_L1;
- break;
- case 0x48:
- fmax_pwrlvl = NPU_PWRLEVEL_NOM;
- break;
- default:
- fmax_pwrlvl = pwr->max_pwrlevel;
- break;
- }
-
- if (fmax_pwrlvl < pwr->max_pwrlevel)
- pwr->max_pwrlevel = fmax_pwrlvl;
- }
+ npu_adjust_max_power_level(npu_dev);
of_property_read_u32(node, "initial-pwrlevel", &init_level_index);
NPU_DBG("initial-pwrlevel %d\n", init_level_index);
@@ -1860,6 +1896,8 @@ static int npu_pwrctrl_init(struct npu_device *npu_dev)
struct platform_device *p2dev;
struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;
+ pwr->devbw_num = 0;
+
/* Power levels */
node = of_find_node_by_name(pdev->dev.of_node, "qcom,npu-pwrlevels");
@@ -1873,15 +1911,17 @@ static int npu_pwrctrl_init(struct npu_device *npu_dev)
return ret;
/* Parse Bandwidth Monitor */
- pwr->devbw_num = of_property_count_strings(pdev->dev.of_node,
+ ret = of_property_count_strings(pdev->dev.of_node,
"qcom,npubw-dev-names");
- if (pwr->devbw_num <= 0) {
+ if (ret <= 0) {
NPU_INFO("npubw-dev-names are not defined\n");
return 0;
- } else if (pwr->devbw_num > NPU_MAX_BW_DEVS) {
- NPU_ERR("number of devbw %d exceeds limit\n", pwr->devbw_num);
+ } else if (ret > NPU_MAX_BW_DEVS) {
+ NPU_ERR("number of devbw %d exceeds limit\n", ret);
return -EINVAL;
}
+ pwr->devbw_num = ret;
+ ret = 0;
for (i = 0; i < pwr->devbw_num; i++) {
node = of_parse_phandle(pdev->dev.of_node,
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 5b8350e..6006986 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -430,10 +430,11 @@ static const struct venus_resources msm8916_res = {
};
static const struct freq_tbl msm8996_freq_table[] = {
- { 1944000, 490000000 }, /* 4k UHD @ 60 */
- { 972000, 320000000 }, /* 4k UHD @ 30 */
- { 489600, 150000000 }, /* 1080p @ 60 */
- { 244800, 75000000 }, /* 1080p @ 30 */
+ { 1944000, 520000000 }, /* 4k UHD @ 60 (decode only) */
+ { 972000, 520000000 }, /* 4k UHD @ 30 */
+ { 489600, 346666667 }, /* 1080p @ 60 */
+ { 244800, 150000000 }, /* 1080p @ 30 */
+ { 108000, 75000000 }, /* 720p @ 30 */
};
static const struct reg_val msm8996_reg_preset[] = {
diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c
index 1240855..fbcc67c 100644
--- a/drivers/media/platform/qcom/venus/hfi_venus.c
+++ b/drivers/media/platform/qcom/venus/hfi_venus.c
@@ -1484,6 +1484,7 @@ static int venus_suspend_3xx(struct venus_core *core)
{
struct venus_hfi_device *hdev = to_hfi_priv(core);
struct device *dev = core->dev;
+ u32 ctrl_status;
bool val;
int ret;
@@ -1499,6 +1500,10 @@ static int venus_suspend_3xx(struct venus_core *core)
return -EINVAL;
}
+ ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
+ if (ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)
+ goto power_off;
+
/*
* Power collapse sequence for Venus 3xx and 4xx versions:
* 1. Check for ARM9 and video core to be idle by checking WFI bit
@@ -1523,6 +1528,7 @@ static int venus_suspend_3xx(struct venus_core *core)
if (ret)
return ret;
+power_off:
mutex_lock(&hdev->lock);
ret = venus_power_off(hdev);
diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
index 81413ab..b677d01 100644
--- a/drivers/media/platform/rcar_drif.c
+++ b/drivers/media/platform/rcar_drif.c
@@ -912,6 +912,7 @@ static int rcar_drif_g_fmt_sdr_cap(struct file *file, void *priv,
{
struct rcar_drif_sdr *sdr = video_drvdata(file);
+ memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
f->fmt.sdr.pixelformat = sdr->fmt->pixelformat;
f->fmt.sdr.buffersize = sdr->fmt->buffersize;
diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h
index 7e61150..f29074c 100644
--- a/drivers/media/platform/ti-vpe/vpdma.h
+++ b/drivers/media/platform/ti-vpe/vpdma.h
@@ -60,6 +60,7 @@ struct vpdma_data_format {
* line stride of source and dest
* buffers should be 16 byte aligned
*/
+#define VPDMA_MAX_STRIDE 65520 /* Max line stride 16 byte aligned */
#define VPDMA_DTD_DESC_SIZE 32 /* 8 words */
#define VPDMA_CFD_CTD_DESC_SIZE 16 /* 4 words */
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index d70871d0..a285b9d 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -352,20 +352,25 @@ enum {
};
/* find our format description corresponding to the passed v4l2_format */
-static struct vpe_fmt *find_format(struct v4l2_format *f)
+static struct vpe_fmt *__find_format(u32 fourcc)
{
struct vpe_fmt *fmt;
unsigned int k;
for (k = 0; k < ARRAY_SIZE(vpe_formats); k++) {
fmt = &vpe_formats[k];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
+ if (fmt->fourcc == fourcc)
return fmt;
}
return NULL;
}
+static struct vpe_fmt *find_format(struct v4l2_format *f)
+{
+ return __find_format(f->fmt.pix.pixelformat);
+}
+
/*
* there is one vpe_dev structure in the driver, it is shared by
* all instances.
@@ -1027,11 +1032,14 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
dma_addr_t dma_addr;
u32 flags = 0;
u32 offset = 0;
+ u32 stride;
if (port == VPE_PORT_MV_OUT) {
vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
dma_addr = ctx->mv_buf_dma[mv_buf_selector];
q_data = &ctx->q_data[Q_DATA_SRC];
+ stride = ALIGN((q_data->width * vpdma_fmt->depth) >> 3,
+ VPDMA_STRIDE_ALIGN);
} else {
/* to incorporate interleaved formats */
int plane = fmt->coplanar ? p_data->vb_part : 0;
@@ -1058,6 +1066,7 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
}
/* Apply the offset */
dma_addr += offset;
+ stride = q_data->bytesperline[VPE_LUMA];
}
if (q_data->flags & Q_DATA_FRAME_1D)
@@ -1069,7 +1078,7 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
MAX_W, MAX_H);
vpdma_add_out_dtd(&ctx->desc_list, q_data->width,
- q_data->bytesperline[VPE_LUMA], &q_data->c_rect,
+ stride, &q_data->c_rect,
vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1,
MAX_OUT_HEIGHT_REG1, p_data->channel, flags);
}
@@ -1088,10 +1097,13 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
dma_addr_t dma_addr;
u32 flags = 0;
u32 offset = 0;
+ u32 stride;
if (port == VPE_PORT_MV_IN) {
vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
dma_addr = ctx->mv_buf_dma[mv_buf_selector];
+ stride = ALIGN((q_data->width * vpdma_fmt->depth) >> 3,
+ VPDMA_STRIDE_ALIGN);
} else {
/* to incorporate interleaved formats */
int plane = fmt->coplanar ? p_data->vb_part : 0;
@@ -1118,6 +1130,7 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
}
/* Apply the offset */
dma_addr += offset;
+ stride = q_data->bytesperline[VPE_LUMA];
if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) {
/*
@@ -1153,10 +1166,10 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12)
frame_height /= 2;
- vpdma_add_in_dtd(&ctx->desc_list, q_data->width,
- q_data->bytesperline[VPE_LUMA], &q_data->c_rect,
- vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width,
- frame_height, 0, 0);
+ vpdma_add_in_dtd(&ctx->desc_list, q_data->width, stride,
+ &q_data->c_rect, vpdma_fmt, dma_addr,
+ p_data->channel, field, flags, frame_width,
+ frame_height, 0, 0);
}
/*
@@ -1405,9 +1418,6 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
/* the previous dst mv buffer becomes the next src mv buffer */
ctx->src_mv_buf_selector = !ctx->src_mv_buf_selector;
- if (ctx->aborting)
- goto finished;
-
s_vb = ctx->src_vbs[0];
d_vb = ctx->dst_vb;
@@ -1418,6 +1428,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
d_vb->timecode = s_vb->timecode;
d_vb->sequence = ctx->sequence;
+ s_vb->sequence = ctx->sequence;
d_q_data = &ctx->q_data[Q_DATA_DST];
if (d_q_data->flags & Q_IS_INTERLACED) {
@@ -1471,6 +1482,9 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
ctx->src_vbs[0] = NULL;
ctx->dst_vb = NULL;
+ if (ctx->aborting)
+ goto finished;
+
ctx->bufs_completed++;
if (ctx->bufs_completed < ctx->bufs_per_job && job_ready(ctx)) {
device_run(ctx);
@@ -1583,9 +1597,9 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
unsigned int stride = 0;
if (!fmt || !(fmt->types & type)) {
- vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n",
+ vpe_dbg(ctx->dev, "Fourcc format (0x%08x) invalid.\n",
pix->pixelformat);
- return -EINVAL;
+ fmt = __find_format(V4L2_PIX_FMT_YUYV);
}
if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE
@@ -1632,7 +1646,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
&pix->height, MIN_H, MAX_H, H_ALIGN,
S_ALIGN);
- if (!pix->num_planes)
+ if (!pix->num_planes || pix->num_planes > 2)
pix->num_planes = fmt->coplanar ? 2 : 1;
else if (pix->num_planes > 1 && !fmt->coplanar)
pix->num_planes = 1;
@@ -1671,6 +1685,10 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
if (stride > plane_fmt->bytesperline)
plane_fmt->bytesperline = stride;
+ plane_fmt->bytesperline = clamp_t(u32, plane_fmt->bytesperline,
+ stride,
+ VPDMA_MAX_STRIDE);
+
plane_fmt->bytesperline = ALIGN(plane_fmt->bytesperline,
VPDMA_STRIDE_ALIGN);
@@ -2291,7 +2309,7 @@ static int vpe_open(struct file *file)
v4l2_ctrl_handler_setup(hdl);
s_q_data = &ctx->q_data[Q_DATA_SRC];
- s_q_data->fmt = &vpe_formats[2];
+ s_q_data->fmt = __find_format(V4L2_PIX_FMT_YUYV);
s_q_data->width = 1920;
s_q_data->height = 1080;
s_q_data->nplanes = 1;
@@ -2369,6 +2387,12 @@ static int vpe_release(struct file *file)
mutex_lock(&dev->dev_mutex);
free_mv_buffers(ctx);
+
+ vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf);
+ vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb);
+ vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h);
+ vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v);
+
vpdma_free_desc_list(&ctx->desc_list);
vpdma_free_desc_buf(&ctx->mmr_adb);
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index e3b3ecd..ae7540b 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -485,6 +485,8 @@ static int si470x_i2c_remove(struct i2c_client *client)
video_unregister_device(&radio->videodev);
kfree(radio);
+ v4l2_ctrl_handler_free(&radio->hdl);
+ v4l2_device_unregister(&radio->v4l2_dev);
return 0;
}
diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c
index ac4fddf..427cda4 100644
--- a/drivers/media/usb/b2c2/flexcop-usb.c
+++ b/drivers/media/usb/b2c2/flexcop-usb.c
@@ -294,7 +294,7 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
mutex_unlock(&fc_usb->data_mutex);
- return 0;
+ return ret;
}
/* actual bus specific access functions,
@@ -503,7 +503,13 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
static int flexcop_usb_init(struct flexcop_usb *fc_usb)
{
/* use the alternate setting with the larges buffer */
- usb_set_interface(fc_usb->udev,0,1);
+ int ret = usb_set_interface(fc_usb->udev, 0, 1);
+
+ if (ret) {
+ err("set interface failed.");
+ return ret;
+ }
+
switch (fc_usb->udev->speed) {
case USB_SPEED_LOW:
err("cannot handle USB speed because it is too slow.");
diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c
index 16e946e..2587197 100644
--- a/drivers/media/usb/dvb-usb/af9005.c
+++ b/drivers/media/usb/dvb-usb/af9005.c
@@ -985,8 +985,9 @@ static int af9005_identify_state(struct usb_device *udev,
else if (reply == 0x02)
*cold = 0;
else
- return -EIO;
- deb_info("Identify state cold = %d\n", *cold);
+ ret = -EIO;
+ if (!ret)
+ deb_info("Identify state cold = %d\n", *cold);
err:
kfree(buf);
diff --git a/drivers/media/usb/pulse8-cec/pulse8-cec.c b/drivers/media/usb/pulse8-cec/pulse8-cec.c
index 6e3bdd7..f589932 100644
--- a/drivers/media/usb/pulse8-cec/pulse8-cec.c
+++ b/drivers/media/usb/pulse8-cec/pulse8-cec.c
@@ -121,6 +121,7 @@ struct pulse8 {
unsigned int vers;
struct completion cmd_done;
struct work_struct work;
+ u8 work_result;
struct delayed_work ping_eeprom_work;
struct cec_msg rx_msg;
u8 data[DATA_SIZE];
@@ -142,8 +143,10 @@ static void pulse8_irq_work_handler(struct work_struct *work)
{
struct pulse8 *pulse8 =
container_of(work, struct pulse8, work);
+ u8 result = pulse8->work_result;
- switch (pulse8->data[0] & 0x3f) {
+ pulse8->work_result = 0;
+ switch (result & 0x3f) {
case MSGCODE_FRAME_DATA:
cec_received_msg(pulse8->adap, &pulse8->rx_msg);
break;
@@ -177,12 +180,12 @@ static irqreturn_t pulse8_interrupt(struct serio *serio, unsigned char data,
pulse8->escape = false;
} else if (data == MSGEND) {
struct cec_msg *msg = &pulse8->rx_msg;
+ u8 msgcode = pulse8->buf[0];
if (debug)
dev_info(pulse8->dev, "received: %*ph\n",
pulse8->idx, pulse8->buf);
- pulse8->data[0] = pulse8->buf[0];
- switch (pulse8->buf[0] & 0x3f) {
+ switch (msgcode & 0x3f) {
case MSGCODE_FRAME_START:
msg->len = 1;
msg->msg[0] = pulse8->buf[1];
@@ -191,14 +194,20 @@ static irqreturn_t pulse8_interrupt(struct serio *serio, unsigned char data,
if (msg->len == CEC_MAX_MSG_SIZE)
break;
msg->msg[msg->len++] = pulse8->buf[1];
- if (pulse8->buf[0] & MSGCODE_FRAME_EOM)
+ if (msgcode & MSGCODE_FRAME_EOM) {
+ WARN_ON(pulse8->work_result);
+ pulse8->work_result = msgcode;
schedule_work(&pulse8->work);
+ break;
+ }
break;
case MSGCODE_TRANSMIT_SUCCEEDED:
case MSGCODE_TRANSMIT_FAILED_LINE:
case MSGCODE_TRANSMIT_FAILED_ACK:
case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
+ WARN_ON(pulse8->work_result);
+ pulse8->work_result = msgcode;
schedule_work(&pulse8->work);
break;
case MSGCODE_HIGH_ERROR:
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index e53a80b..04d3341 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -916,8 +916,12 @@ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
pvr2_v4l2_dev_disassociate_parent(vp->dev_video);
pvr2_v4l2_dev_disassociate_parent(vp->dev_radio);
if (!list_empty(&vp->dev_video->devbase.fh_list) ||
- !list_empty(&vp->dev_radio->devbase.fh_list))
+ (vp->dev_radio &&
+ !list_empty(&vp->dev_radio->devbase.fh_list))) {
+ pvr2_trace(PVR2_TRACE_STRUCT,
+ "pvr2_v4l2 internal_check exit-empty id=%p", vp);
return;
+ }
pvr2_v4l2_destroy_no_lock(vp);
}
@@ -953,7 +957,8 @@ static int pvr2_v4l2_release(struct file *file)
kfree(fhp);
if (vp->channel.mc_head->disconnect_flag &&
list_empty(&vp->dev_video->devbase.fh_list) &&
- list_empty(&vp->dev_radio->devbase.fh_list)) {
+ (!vp->dev_radio ||
+ list_empty(&vp->dev_radio->devbase.fh_list))) {
pvr2_v4l2_destroy_no_lock(vp);
}
return 0;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 96cf69a..b7bf43b 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1505,10 +1505,26 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
return ret;
}
+static void v4l_pix_format_touch(struct v4l2_pix_format *p)
+{
+ /*
+ * The v4l2_pix_format structure contains fields that make no sense for
+ * touch. Set them to default values in this case.
+ */
+
+ p->field = V4L2_FIELD_NONE;
+ p->colorspace = V4L2_COLORSPACE_RAW;
+ p->flags = 0;
+ p->ycbcr_enc = 0;
+ p->quantization = 0;
+ p->xfer_func = 0;
+}
+
static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
struct v4l2_format *p = arg;
+ struct video_device *vfd = video_devdata(file);
int ret = check_fmt(file, p->type);
if (ret)
@@ -1546,6 +1562,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg);
/* just in case the driver zeroed it again */
p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ if (vfd->vfl_type == VFL_TYPE_TOUCH)
+ v4l_pix_format_touch(&p->fmt.pix);
return ret;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg);
@@ -1581,21 +1599,6 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
return -EINVAL;
}
-static void v4l_pix_format_touch(struct v4l2_pix_format *p)
-{
- /*
- * The v4l2_pix_format structure contains fields that make no sense for
- * touch. Set them to default values in this case.
- */
-
- p->field = V4L2_FIELD_NONE;
- p->colorspace = V4L2_COLORSPACE_RAW;
- p->flags = 0;
- p->ycbcr_enc = 0;
- p->quantization = 0;
- p->xfer_func = 0;
-}
-
static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index f2b5ac5..986061f 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -596,6 +596,14 @@
The output of the driver is CIRs (Channel Impulse Response) which
must be processed in user space in order to get meaningful results.
+config QTI_XR_SMRTVWR_MISC
+ tristate "QTI XR Reference device Misc driver support"
+ help
+ This driver supports the misc chips in XR Reference devices
+ such as NDI controller chip, Power up Sensor rails etc. Note: This
+ driver initializes gpios, enables/disables LDOs that are part of
+ XR standalone reference device.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 11270e4..4968aeb 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -72,4 +72,5 @@
obj-$(CONFIG_OKL4_GUEST) += okl4-panic.o
obj-$(CONFIG_OKL4_LINK_SHBUF) += okl4-link-shbuf.o
obj-$(CONFIG_WIGIG_SENSING_SPI) += wigig_sensing.o
+obj-$(CONFIG_QTI_XR_SMRTVWR_MISC) += qxr-stdalonevwr.o
diff --git a/drivers/misc/qxr-stdalonevwr.c b/drivers/misc/qxr-stdalonevwr.c
new file mode 100644
index 0000000..c3fd763
--- /dev/null
+++ b/drivers/misc/qxr-stdalonevwr.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+struct qxr_stdalonevwr {
+ struct platform_device *pdev;
+ struct regulator *reg_imu;
+ int ndi_5v_en;
+ bool initDone;
+};
+
+static struct qxr_stdalonevwr *pdata;
+
+static int qxr_stdalonevwr_allocate_res(void)
+{
+ int rc = -EINVAL;
+ bool gpioEnabled = false;
+
+ if (pdata->initDone) {
+ pr_debug("%s init is done already\n", __func__);
+ return 0;
+ }
+ /* Invensense 3.3 PowerRail */
+ pdata->reg_imu = devm_regulator_get(&pdata->pdev->dev, "pm8150a_l11");
+ if (!IS_ERR(pdata->reg_imu)) {
+ regulator_set_load(pdata->reg_imu, 600000);
+ rc = regulator_enable(pdata->reg_imu);
+ if (rc < 0) {
+ pr_err("%s IMU rail pm8150a_l11 failed\n", __func__);
+ devm_regulator_put(pdata->reg_imu);
+ }
+ }
+
+ if (gpio_is_valid(pdata->ndi_5v_en)) {
+ rc = gpio_request(pdata->ndi_5v_en, "ndi_5v_en");
+ if (!rc) {
+ rc = gpio_direction_output(pdata->ndi_5v_en, 0);
+ if (!rc) {
+ gpio_set_value(pdata->ndi_5v_en, 1);
+ gpioEnabled = true;
+ msleep(20);
+ }
+ }
+ }
+ if (!gpioEnabled) {
+ pr_err("%s NDI_5V_EN gpio failed to allocate\n", __func__);
+ gpio_free(pdata->ndi_5v_en);
+ }
+ pdata->initDone = true;
+ pr_debug("%s rc:%d\n", __func__, rc);
+ return rc;
+}
+
+static void qxr_stdalonevwr_free_res(void)
+{
+ if (pdata->initDone) {
+ if (pdata->reg_imu) {
+ regulator_disable(pdata->reg_imu);
+ devm_regulator_put(pdata->reg_imu);
+ }
+ gpio_free(pdata->ndi_5v_en);
+ pdata->initDone = false;
+ }
+ pr_debug("%s initDone:%d\n", __func__, pdata->initDone);
+}
+
+static int qxr_stdalonevwr_probe(struct platform_device *pdev)
+{
+ pdata = devm_kzalloc(&pdev->dev, sizeof(struct qxr_stdalonevwr),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->pdev = pdev;
+ pdata->ndi_5v_en = 1237;
+ pdata->initDone = false;
+ qxr_stdalonevwr_allocate_res();
+ pr_info("%s done\n", __func__);
+ return 0;
+}
+
+static int qxr_stdalonevrw_pm_suspend(struct device *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+ if (pdata)
+ qxr_stdalonevwr_free_res();
+ return 0;
+}
+
+static int qxr_stdalonevrw_pm_resume(struct device *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+ if (pdata)
+ qxr_stdalonevwr_allocate_res();
+ return 0;
+}
+
+static int qxr_stdalonevrw_pm_freeze(struct device *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+ return qxr_stdalonevrw_pm_suspend(dev);
+};
+
+static int qxr_stdalonevrw_pm_restore(struct device *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+ return qxr_stdalonevrw_pm_resume(dev);
+};
+
+static int qxr_stdalonevrw_pm_poweroff(struct device *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+ return qxr_stdalonevrw_pm_suspend(dev);
+};
+
+static int qxr_stdalonevrw_pm_thaw(struct device *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+ return qxr_stdalonevrw_pm_resume(dev);
+};
+
+static const struct dev_pm_ops qxr_stdalonevwr_dev_pm_ops = {
+ .suspend = qxr_stdalonevrw_pm_suspend,
+ .resume = qxr_stdalonevrw_pm_resume,
+ .freeze = qxr_stdalonevrw_pm_freeze,
+ .restore = qxr_stdalonevrw_pm_restore,
+ .thaw = qxr_stdalonevrw_pm_thaw,
+ .poweroff = qxr_stdalonevrw_pm_poweroff,
+};
+
+static const struct of_device_id qxr_stdalonevwr_match_table[] = {
+ { .compatible = "qcom,xr-stdalonevwr-misc", },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, qxr_stdalonevwr_match_table);
+
+static struct platform_driver qxr_stdalonevwr_driver = {
+ .driver = {
+ .name = "qxr-stdalonevwr",
+ .of_match_table = qxr_stdalonevwr_match_table,
+ .pm = &qxr_stdalonevwr_dev_pm_ops,
+ },
+ .probe = qxr_stdalonevwr_probe,
+};
+
+module_platform_driver(qxr_stdalonevwr_driver);
+
+MODULE_DESCRIPTION("QTI XR STANDALONE MISC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/wigig_sensing.c b/drivers/misc/wigig_sensing.c
index 7db1f3b..b8d4d6f 100644
--- a/drivers/misc/wigig_sensing.c
+++ b/drivers/misc/wigig_sensing.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2019, The Linux foundation. All rights reserved.
+ * Copyright (c) 2019-2020, The Linux foundation. All rights reserved.
*/
#include <linux/cdev.h>
#include <linux/circ_buf.h>
@@ -15,6 +15,7 @@
#include <linux/ioctl.h>
#include <linux/kernel.h>
#include <linux/kfifo.h>
+#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -44,6 +45,35 @@
#define circ_space_to_end(circ, size) \
((CIRC_SPACE_TO_END((circ)->head, (circ)->tail, size)) & ~3)
+#ifdef CONFIG_DEBUG_FS
+#define SPI_STATS_MEAS_INIT(ctx, idx, name_str) \
+ do { \
+ strlcpy((ctx)->spi_stats[idx].name, name_str, \
+ SPI_STATS_MAX_NAME_LEN); \
+ atomic64_set(&(ctx)->spi_stats[idx].min, U64_MAX); \
+ } while (0)
+
+#define SPI_STATS_MEAS_START(ctx, idx) (ctx)->spi_stats[idx].start = ktime_get()
+
+#define SPI_STATS_MEAS_STOP(ctx, idx) \
+ do { \
+ struct spi_stats *ss = &(ctx)->spi_stats[idx]; \
+ u64 min = atomic64_read(&ss->min); \
+ u64 max = atomic64_read(&ss->max); \
+ \
+ ss->delta = ktime_sub(ktime_get(), ss->start); \
+ atomic64_set(&ss->min, (ktime_to_us(ss->delta) != 0) ? \
+ min_t(u64, min, ss->delta) : min); \
+ atomic64_set(&ss->max, max_t(u64, max, ss->delta)); \
+ atomic64_add(ss->delta, &ss->acc); \
+ atomic_inc(&ss->num_meas); \
+ } while (0)
+#else /* CONFIG_DEBUG_FS */
+#define SPI_STATS_MEAS_INIT(ctx, idx, name_str)
+#define SPI_STATS_MEAS_START(ctx, idx)
+#define SPI_STATS_MEAS_STOP(ctx, idx)
+#endif /* CONFIG_DEBUG_FS */
+
struct wigig_sensing_platform_data {
struct gpio_desc *dri_gpio;
};
@@ -809,17 +839,16 @@ static long wigig_sensing_ioctl(struct file *file, unsigned int cmd,
case WIGIG_SENSING_IOCTL_CHANGE_MODE:
{
struct wigig_sensing_change_mode req;
-
pr_info("Received WIGIG_SENSING_IOCTL_CHANGE_MODE command\n");
if (copy_from_user(&req, (void *)arg, sizeof(req)))
return -EFAULT;
+ SPI_STATS_MEAS_START(ctx, SPI_STATS_MEAS_CHANGE_MODE);
rc = wigig_sensing_ioc_change_mode(ctx, &req);
-
if (copy_to_user((void *)arg, &req, sizeof(req)))
return -EFAULT;
-
+ SPI_STATS_MEAS_STOP(ctx, SPI_STATS_MEAS_CHANGE_MODE);
break;
}
case WIGIG_SENSING_IOCTL_CLEAR_DATA:
@@ -1122,11 +1151,13 @@ static int wigig_sensing_chip_data_ready(struct wigig_sensing_ctx *ctx,
/* Read fill_level again */
pr_debug("Reading RGF_USER_SPI_SPI_MBOX_FILL_STATUS register\n");
+ SPI_STATS_MEAS_START(ctx, SPI_STATS_MEAS_MBOX_FILL_STATUS);
mutex_lock(&ctx->spi_lock);
rc = spis_read_reg(ctx->spi_dev,
RGF_USER_SPI_SPI_MBOX_FILL_STATUS,
&spi_status.v);
mutex_unlock(&ctx->spi_lock);
+ SPI_STATS_MEAS_STOP(ctx, SPI_STATS_MEAS_MBOX_FILL_STATUS);
if (rc) {
pr_err("Fail to read RGF_USER_SPI_SPI_MBOX_FILL_STATUS, err %d\n",
rc);
@@ -1263,10 +1294,12 @@ static irqreturn_t wigig_sensing_dri_isr_thread(int irq, void *cookie)
}
pr_debug("Reading SANITY register\n");
+ SPI_STATS_MEAS_START(ctx, SPI_STATS_MEAS_SANITY);
mutex_lock(&ctx->spi_lock);
rc = spis_read_reg(ctx->spi_dev, SPIS_SANITY_REG_ADDR,
&sanity_reg);
mutex_unlock(&ctx->spi_lock);
+ SPI_STATS_MEAS_STOP(ctx, SPI_STATS_MEAS_SANITY);
if (rc || sanity_reg != SPIS_SANITY_REG_VAL) {
pr_err("Fail to read SANITY, expected 0x%X found 0x%X err %d\n",
SPIS_SANITY_REG_VAL, sanity_reg, (int)rc);
@@ -1285,11 +1318,12 @@ static irqreturn_t wigig_sensing_dri_isr_thread(int irq, void *cookie)
}
pr_debug("Reading RGF_USER_SPI_SPI_MBOX_FILL_STATUS register\n");
+ SPI_STATS_MEAS_START(ctx, SPI_STATS_MEAS_MBOX_FILL_STATUS);
mutex_lock(&ctx->spi_lock);
rc = spis_read_reg(ctx->spi_dev, RGF_USER_SPI_SPI_MBOX_FILL_STATUS,
&spi_status.v);
mutex_unlock(&ctx->spi_lock);
-
+ SPI_STATS_MEAS_STOP(ctx, SPI_STATS_MEAS_MBOX_FILL_STATUS);
if (rc) {
pr_err("Fail to read RGF_USER_SPI_SPI_MBOX_FILL_STATUS, err %d\n",
rc);
@@ -1335,12 +1369,14 @@ static irqreturn_t wigig_sensing_dri_isr_thread(int irq, void *cookie)
spi_status.v &= ~INT_FW_READY;
}
if (spi_status.b.int_data_ready) {
+ SPI_STATS_MEAS_START(ctx, SPI_STATS_MEAS_DATA_READY);
pr_debug("DATA READY INTERRUPT\n");
if (!ctx->stm.change_mode_in_progress)
wigig_sensing_chip_data_ready(
ctx, spi_status.b.fill_level, ctx->stm.burst_size);
else
pr_debug("Change mode in progress, aborting data processing\n");
+ SPI_STATS_MEAS_STOP(ctx, SPI_STATS_MEAS_DATA_READY);
spi_status.v &= ~INT_DATA_READY;
}
@@ -1378,19 +1414,125 @@ static irqreturn_t wigig_sensing_dri_isr_thread(int irq, void *cookie)
deassert_and_bail_out:
/* Notify FW we are done with interrupt handling */
if (!dont_deassert || additional_inb_command.b.mode != 0) {
+ SPI_STATS_MEAS_START(ctx, SPI_STATS_MEAS_DEASSERT);
rc = wigig_sensing_deassert_dri(ctx, additional_inb_command);
if (rc)
pr_err("wigig_sensing_deassert_dri() failed, rc=%d\n",
rc);
+ SPI_STATS_MEAS_STOP(ctx, SPI_STATS_MEAS_DEASSERT);
}
bail_out:
mutex_unlock(&ctx->dri_lock);
+ SPI_STATS_MEAS_STOP(ctx, SPI_STATS_MEAS_DRI_PROC);
+
return IRQ_HANDLED;
}
+static int wigig_sensing_debugfs_spi_stats_show(struct seq_file *s, void *data)
+{
+ struct wigig_sensing_ctx *ctx = s->private;
+ int i;
+
+ if (ctx == NULL)
+ return -ENODEV;
+
+ seq_printf(s, "|%18s|%10s|%10s|%15s|%10s|%10s|\n",
+ "Name", "Min [uS]", "Max [uS]", "Acc [uS]", "#", "Avg [uS]");
+ for (i = 0; i < SPI_STATS_MEAS_MAX; i++) {
+ struct spi_stats *ss = &ctx->spi_stats[i];
+ u64 min = atomic64_read(&ss->min);
+ u64 max = atomic64_read(&ss->max);
+ u64 acc = atomic64_read(&ss->acc);
+ u64 num_meas = atomic_read(&ss->num_meas);
+
+ seq_printf(s, "|%18s|%10lu|%10lu|%15llu|%10lu|%10lu|\n",
+ ss->name,
+ ktime_to_us(min),
+ ktime_to_us(max),
+ ktime_to_us(acc),
+ num_meas,
+ ktime_to_us((num_meas != 0) ? acc / num_meas : 0));
+ }
+
+ return 0;
+}
+
+static int wigig_sensing_seq_spi_stats_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, wigig_sensing_debugfs_spi_stats_show,
+ inode->i_private);
+}
+
+static const struct file_operations debugfs_spi_stats_fops = {
+ .open = wigig_sensing_seq_spi_stats_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek,
+};
+
+static int wigig_sensing_debugfs_spi_stats_init_open(struct seq_file *s,
+ void *data)
+{
+ struct wigig_sensing_ctx *ctx = s->private;
+ int i;
+
+ if (ctx == NULL)
+ return -ENODEV;
+
+ for (i = 0; i < SPI_STATS_MEAS_MAX; i++) {
+ struct spi_stats *ss = &ctx->spi_stats[i];
+
+ atomic64_set(&ss->min, U64_MAX);
+ atomic64_set(&ss->max, 0);
+ atomic64_set(&ss->acc, 0);
+ atomic_set(&ss->num_meas, 0);
+ ss->start = 0;
+ ss->delta = 0;
+ }
+
+ return 0;
+}
+
+static int wigig_sensing_seq_spi_stats_init_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, wigig_sensing_debugfs_spi_stats_init_open,
+ inode->i_private);
+}
+
+static const struct file_operations debugfs_spi_stats_init_fops = {
+ .open = wigig_sensing_seq_spi_stats_init_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek,
+};
+
+static int wigig_sensing_debugfs_init(struct wigig_sensing_ctx *ctx)
+{
+ SPI_STATS_MEAS_INIT(ctx, SPI_STATS_MEAS_SANITY, "Sanity");
+ SPI_STATS_MEAS_INIT(ctx, SPI_STATS_MEAS_DEASSERT, "Deassert DRI");
+ SPI_STATS_MEAS_INIT(ctx, SPI_STATS_MEAS_DRI_PROC, "DRI proc");
+ SPI_STATS_MEAS_INIT(ctx, SPI_STATS_MEAS_MBOX_FILL_STATUS,
+ "MBOX FILL STATUS");
+ SPI_STATS_MEAS_INIT(ctx, SPI_STATS_MEAS_CHANGE_MODE, "CHANGE MODE");
+ SPI_STATS_MEAS_INIT(ctx, SPI_STATS_MEAS_DATA_READY, "Data Ready");
+
+ ctx->debugfs_dent = debugfs_create_dir("wigig_sensing", NULL);
+ debugfs_create_file("spi_stats", 0644, ctx->debugfs_dent, ctx,
+ &debugfs_spi_stats_fops);
+ debugfs_create_file("spi_stats_init", 0644, ctx->debugfs_dent, ctx,
+ &debugfs_spi_stats_init_fops);
+
+ return 0;
+}
+
static irqreturn_t wigig_sensing_dri_isr_hard(int irq, void *cookie)
{
+ SPI_STATS_MEAS_START((struct wigig_sensing_ctx *)cookie,
+ SPI_STATS_MEAS_DRI_PROC);
+
return IRQ_WAKE_THREAD;
}
@@ -1475,6 +1617,9 @@ static int wigig_sensing_probe(struct spi_device *spi)
goto fail_gpiod_get;
}
+ /* Initialize debugfs */
+ wigig_sensing_debugfs_init(ctx);
+
return 0;
fail_gpiod_get:
@@ -1502,6 +1647,7 @@ static int wigig_sensing_remove(struct spi_device *spi)
/* Make sure that FW is in STOP mode */
wigig_sensing_ioc_change_mode(ctx, &req);
+ debugfs_remove_recursive(ctx->debugfs_dent);
device_destroy(ctx->class, ctx->wigig_sensing_dev);
unregister_chrdev_region(ctx->wigig_sensing_dev, 1);
class_destroy(ctx->class);
diff --git a/drivers/misc/wigig_sensing.h b/drivers/misc/wigig_sensing.h
index da55cee..4c449bc 100644
--- a/drivers/misc/wigig_sensing.h
+++ b/drivers/misc/wigig_sensing.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2019, The Linux foundation. All rights reserved.
+ * Copyright (c) 2019-2020, The Linux foundation. All rights reserved.
*/
#ifndef __WIGIG_SENSING_H__
@@ -8,6 +8,7 @@
#include <linux/cdev.h>
#include <linux/circ_buf.h>
#include <linux/kfifo.h>
+#include <linux/ktime.h>
#include <linux/slab.h>
#include <uapi/misc/wigig_sensing_uapi.h>
@@ -162,12 +163,34 @@ struct wigig_sensing_stm {
enum wigig_sensing_mode mode_request;
};
+enum spi_stats_meas {
+ SPI_STATS_MEAS_MIN,
+ SPI_STATS_MEAS_SANITY = SPI_STATS_MEAS_MIN,
+ SPI_STATS_MEAS_DEASSERT,
+ SPI_STATS_MEAS_DRI_PROC,
+ SPI_STATS_MEAS_MBOX_FILL_STATUS,
+ SPI_STATS_MEAS_CHANGE_MODE,
+ SPI_STATS_MEAS_DATA_READY,
+ SPI_STATS_MEAS_MAX,
+};
+
+#define SPI_STATS_MAX_NAME_LEN (20)
+struct spi_stats {
+ char name[SPI_STATS_MAX_NAME_LEN];
+ atomic64_t min;
+ atomic64_t max;
+ atomic64_t acc;
+ atomic_t num_meas;
+ ktime_t start, delta;
+};
+
struct wigig_sensing_ctx {
dev_t wigig_sensing_dev;
struct cdev cdev;
struct class *class;
struct device *dev;
struct spi_device *spi_dev;
+ struct dentry *debugfs_dent;
/* Locks */
struct mutex ioctl_lock;
@@ -201,6 +224,9 @@ struct wigig_sensing_ctx {
bool event_pending;
DECLARE_KFIFO(events_fifo, enum wigig_sensing_event, 8);
u32 dropped_bursts;
+
+ /* Statistics */
+ struct spi_stats spi_stats[SPI_STATS_MEAS_MAX];
};
#endif /* __WIGIG_SENSING_H__ */
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index de6dac1..f8d35fd 100644
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -108,7 +108,7 @@ static enum blk_eh_timer_return mmc_cqe_timed_out(struct request *req)
case MMC_ISSUE_DCMD:
if (host->cqe_ops->cqe_timeout(host, mrq, &recovery_needed)) {
if (recovery_needed)
- __mmc_cqe_recovery_notifier(mq);
+ mmc_cqe_recovery_notifier(mrq);
return BLK_EH_RESET_TIMER;
}
/* No timeout (XXX: huh? comment doesn't make much sense) */
@@ -130,12 +130,13 @@ static enum blk_eh_timer_return mmc_mq_timed_out(struct request *req,
spin_lock_irqsave(q->queue_lock, flags);
- if (mq->recovery_needed || !mq->use_cqe)
+ if (mq->recovery_needed || !mq->use_cqe) {
ret = BLK_EH_RESET_TIMER;
- else
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ } else {
+ spin_unlock_irqrestore(q->queue_lock, flags);
ret = mmc_cqe_timed_out(req);
-
- spin_unlock_irqrestore(q->queue_lock, flags);
+ }
return ret;
}
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 673f6a9..9ecf86b 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -228,6 +228,7 @@
#define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */
#define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */
+#define MSDC_PATCH_BIT1_CMDTA (0x7 << 3) /* RW */
#define MSDC_PATCH_BIT1_STOP_DLY (0xf << 8) /* RW */
#define MSDC_PATCH_BIT2_CFGRESP (0x1 << 15) /* RW */
@@ -1673,6 +1674,7 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode)
/* select EMMC50 PAD CMD tune */
sdr_set_bits(host->base + PAD_CMD_TUNE, BIT(0));
+ sdr_set_field(host->base + MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_CMDTA, 2);
if (mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
mmc->ios.timing == MMC_TIMING_UHS_SDR104)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4a222ea..3918e4a 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -145,8 +145,8 @@
#define CORE_DDR_CAL_EN (1 << 0)
#define CORE_FLL_CYCLE_CNT (1 << 18)
#define CORE_DLL_CLOCK_DISABLE (1 << 21)
+#define DDR_CONFIG_POR_VAL 0x80040873
-#define DDR_CONFIG_POR_VAL 0x80040873
#define DLL_USR_CTL_POR_VAL 0x10800
#define ENABLE_DLL_LOCK_STATUS (1 << 26)
#define FINE_TUNE_MODE_EN (1 << 27)
@@ -1980,6 +1980,42 @@ static int sdhci_msm_dt_parse_hsr_info(struct device *dev,
return ret;
}
+static int sdhci_msm_parse_regulator_info(struct device *dev,
+ struct sdhci_msm_pltfm_data *pdata)
+{
+ int ret = 0;
+
+ pdata->vreg_data = devm_kzalloc(dev, sizeof(struct
+ sdhci_msm_slot_reg_data),
+ GFP_KERNEL);
+ if (!pdata->vreg_data) {
+ dev_err(dev, "failed to allocate memory for vreg data\n");
+ goto out;
+ }
+
+ if (sdhci_msm_dt_parse_vreg_info(dev, &pdata->vreg_data->vdd_data,
+ "vdd")) {
+ dev_err(dev, "failed parsing vdd data\n");
+ goto out;
+ }
+ if (sdhci_msm_dt_parse_vreg_info(dev,
+ &pdata->vreg_data->vdd_io_data,
+ "vdd-io")) {
+ dev_err(dev, "failed parsing vdd-io data\n");
+ goto out;
+ }
+
+ if (sdhci_msm_dt_parse_vreg_info(dev,
+ &pdata->vreg_data->vdd_io_bias_data,
+ "vdd-io-bias")) {
+ dev_err(dev, "No vdd-io-bias regulator data\n");
+ }
+
+ return ret;
+out:
+ return -EINVAL;
+}
+
/* Parse platform data */
static
struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
@@ -2080,25 +2116,8 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
MMC_SCALING_LOWER_DDR52_MODE;
}
- pdata->vreg_data = devm_kzalloc(dev, sizeof(struct
- sdhci_msm_slot_reg_data),
- GFP_KERNEL);
- if (!pdata->vreg_data) {
- dev_err(dev, "failed to allocate memory for vreg data\n");
+ if (sdhci_msm_parse_regulator_info(dev, pdata))
goto out;
- }
-
- if (sdhci_msm_dt_parse_vreg_info(dev, &pdata->vreg_data->vdd_data,
- "vdd")) {
- dev_err(dev, "failed parsing vdd data\n");
- goto out;
- }
- if (sdhci_msm_dt_parse_vreg_info(dev,
- &pdata->vreg_data->vdd_io_data,
- "vdd-io")) {
- dev_err(dev, "failed parsing vdd-io data\n");
- goto out;
- }
if (sdhci_msm_dt_parse_gpio_info(dev, pdata)) {
dev_err(dev, "failed parsing gpio data\n");
@@ -2652,7 +2671,7 @@ static int sdhci_msm_setup_vreg(struct sdhci_msm_pltfm_data *pdata,
{
int ret = 0, i;
struct sdhci_msm_slot_reg_data *curr_slot;
- struct sdhci_msm_reg_data *vreg_table[2];
+ struct sdhci_msm_reg_data *vreg_table[3];
curr_slot = pdata->vreg_data;
if (!curr_slot) {
@@ -2663,6 +2682,7 @@ static int sdhci_msm_setup_vreg(struct sdhci_msm_pltfm_data *pdata,
vreg_table[0] = curr_slot->vdd_data;
vreg_table[1] = curr_slot->vdd_io_data;
+ vreg_table[2] = curr_slot->vdd_io_bias_data;
for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
if (vreg_table[i]) {
@@ -2685,7 +2705,8 @@ static int sdhci_msm_vreg_init(struct device *dev,
{
int ret = 0;
struct sdhci_msm_slot_reg_data *curr_slot;
- struct sdhci_msm_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
+ struct sdhci_msm_reg_data *curr_vdd_reg, *curr_vdd_io_reg,
+ *curr_vdd_io_bias_reg;
curr_slot = pdata->vreg_data;
if (!curr_slot)
@@ -2693,10 +2714,11 @@ static int sdhci_msm_vreg_init(struct device *dev,
curr_vdd_reg = curr_slot->vdd_data;
curr_vdd_io_reg = curr_slot->vdd_io_data;
+ curr_vdd_io_bias_reg = curr_slot->vdd_io_bias_data;
if (!is_init)
/* Deregister all regulators from regulator framework */
- goto vdd_io_reg_deinit;
+ goto vdd_io_bias_reg_deinit;
/*
* Get the regulator handle from voltage regulator framework
@@ -2712,11 +2734,19 @@ static int sdhci_msm_vreg_init(struct device *dev,
if (ret)
goto vdd_reg_deinit;
}
+ if (curr_vdd_io_bias_reg) {
+ ret = sdhci_msm_vreg_init_reg(dev, curr_vdd_io_bias_reg);
+ if (ret)
+ goto vdd_io_reg_deinit;
+ }
if (ret)
dev_err(dev, "vreg reset failed (%d)\n", ret);
goto out;
+vdd_io_bias_reg_deinit:
+ if (curr_vdd_io_bias_reg)
+ sdhci_msm_vreg_deinit_reg(curr_vdd_io_bias_reg);
vdd_io_reg_deinit:
if (curr_vdd_io_reg)
sdhci_msm_vreg_deinit_reg(curr_vdd_io_reg);
@@ -2890,6 +2920,8 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
int ret = 0;
int pwr_state = 0, io_level = 0;
unsigned long flags;
+ struct sdhci_msm_reg_data *vreg_io_bias =
+ msm_host->pdata->vreg_data->vdd_io_bias_data;
irq_status = sdhci_msm_readb_relaxed(host,
msm_host_offset->CORE_PWRCTL_STATUS);
@@ -2936,6 +2968,8 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
if (irq_status & CORE_PWRCTL_IO_LOW) {
/* Switch voltage Low */
ret = sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_LOW, 0);
+ if (!ret && vreg_io_bias)
+ ret = sdhci_msm_vreg_disable(vreg_io_bias);
if (ret)
irq_ack |= CORE_PWRCTL_IO_FAIL;
else
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index 87f651c..50cb575 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
*/
@@ -42,6 +42,8 @@ struct sdhci_msm_slot_reg_data {
struct sdhci_msm_reg_data *vdd_data;
/* keeps VDD IO regulator info */
struct sdhci_msm_reg_data *vdd_io_data;
+ /* Keeps VDD IO parent regulator info*/
+ struct sdhci_msm_reg_data *vdd_io_bias_data;
};
struct sdhci_msm_gpio {
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 6627523..2c9110f 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -648,9 +648,6 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc"))
- mdelay(5);
-
if (mask & SDHCI_RESET_ALL) {
val = sdhci_readl(host, ESDHC_TBCTL);
val &= ~ESDHC_TB_EN;
@@ -926,8 +923,8 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc")) {
- host->quirks2 |= SDHCI_QUIRK_RESET_AFTER_REQUEST;
- host->quirks2 |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+ host->quirks |= SDHCI_QUIRK_RESET_AFTER_REQUEST;
+ host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
}
if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 7179439..65985dc 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -30,6 +30,7 @@
#include <linux/mmc/slot-gpio.h>
#include <linux/mmc/sdhci-pci-data.h>
#include <linux/acpi.h>
+#include <linux/dmi.h>
#include "cqhci.h"
@@ -732,11 +733,18 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
return 0;
}
+static bool glk_broken_cqhci(struct sdhci_pci_slot *slot)
+{
+ return slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC &&
+ dmi_match(DMI_BIOS_VENDOR, "LENOVO");
+}
+
static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot)
{
int ret = byt_emmc_probe_slot(slot);
- slot->host->mmc->caps2 |= MMC_CAP2_CQE;
+ if (!glk_broken_cqhci(slot))
+ slot->host->mmc->caps2 |= MMC_CAP2_CQE;
if (slot->chip->pdev->device != PCI_DEVICE_ID_INTEL_GLK_EMMC) {
slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES,
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7fd1626..bb24903 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2089,9 +2089,7 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
else if (timing == MMC_TIMING_UHS_SDR12)
ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
- else if (timing == MMC_TIMING_SD_HS ||
- timing == MMC_TIMING_MMC_HS ||
- timing == MMC_TIMING_UHS_SDR25)
+ else if (timing == MMC_TIMING_UHS_SDR25)
ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
else if (timing == MMC_TIMING_UHS_SDR50)
ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
@@ -2718,8 +2716,8 @@ static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
sdhci_send_tuning(host, opcode);
if (!host->tuning_done) {
- pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n",
- mmc_hostname(host->mmc));
+ pr_debug("%s: Tuning timeout, falling back to fixed sampling clock\n",
+ mmc_hostname(host->mmc));
sdhci_abort_tuning(host, opcode);
return;
}
@@ -4239,6 +4237,9 @@ int sdhci_setup_host(struct sdhci_host *host)
mmc_hostname(mmc), host->version);
}
+ if (host->quirks & SDHCI_QUIRK_BROKEN_CQE)
+ mmc->caps2 &= ~MMC_CAP2_CQE;
+
if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
host->flags |= SDHCI_USE_SDMA;
else if (!(host->caps & SDHCI_CAN_DO_SDMA))
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 278ed0f..81a49ca 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -404,6 +404,8 @@ struct sdhci_host {
#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)
/* Controller reports inverted write-protect state */
#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16)
+/* Controller has unusable command queue engine */
+#define SDHCI_QUIRK_BROKEN_CQE (1<<17)
/* Controller does not like fast PIO transfers */
#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18)
/* Controller has to be forced to use block size of 2048 bytes */
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 35630cc..33c9ca8 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -1267,7 +1267,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
return ret;
}
- mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities;
+ mmc->caps |= MMC_CAP_ERASE | MMC_CAP_4_BIT_DATA | pdata->capabilities;
mmc->caps2 |= pdata->capabilities2;
mmc->max_segs = pdata->max_segs ? : 32;
mmc->max_blk_size = 512;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 9b8143d..f57b86f 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2223,9 +2223,6 @@ static void bond_miimon_commit(struct bonding *bond)
} else if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
/* make it immediately active */
bond_set_active_slave(slave);
- } else if (slave != primary) {
- /* prevent it from being the active one */
- bond_set_backup_slave(slave);
}
netdev_info(bond->dev, "link status definitely up for interface %s, %u Mbps %s duplex\n",
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
index 07d2f3a..ae4c37e 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -608,7 +608,7 @@ static int kvaser_usb_leaf_simple_cmd_async(struct kvaser_usb_net_priv *priv,
struct kvaser_cmd *cmd;
int err;
- cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
+ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
if (!cmd)
return -ENOMEM;
@@ -1140,7 +1140,7 @@ static int kvaser_usb_leaf_set_opt_mode(const struct kvaser_usb_net_priv *priv)
struct kvaser_cmd *cmd;
int rc;
- cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
@@ -1206,7 +1206,7 @@ static int kvaser_usb_leaf_flush_queue(struct kvaser_usb_net_priv *priv)
struct kvaser_cmd *cmd;
int rc;
- cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index d3ce1e4..dbfb6ad 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -66,6 +66,7 @@
config NET_DSA_SMSC_LAN9303
tristate
select NET_DSA_TAG_LAN9303
+ select REGMAP
---help---
This enables support for the SMSC/Microchip LAN9303 3 port ethernet
switch chips.
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 38e399e..8298d67 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -371,6 +371,11 @@ int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
{
u16 ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST;
+ /* Use the default high priority for management frames sent to
+ * the CPU.
+ */
+ port |= MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI;
+
return mv88e6390_g1_monitor_write(chip, ptr, port);
}
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index bef0133..70b870c 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -197,6 +197,7 @@
#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST 0x2000
#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST 0x2100
#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST 0x3000
+#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI 0x00e0
#define MV88E6390_G1_MONITOR_MGMT_CTL_DATA_MASK 0x00ff
/* Offset 0x1C: Global Control 2 */
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index b5d7281..e26c195 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -1197,8 +1197,8 @@ static int ena_io_poll(struct napi_struct *napi, int budget)
struct ena_napi *ena_napi = container_of(napi, struct ena_napi, napi);
struct ena_ring *tx_ring, *rx_ring;
- u32 tx_work_done;
- u32 rx_work_done;
+ int tx_work_done;
+ int rx_work_done = 0;
int tx_budget;
int napi_comp_call = 0;
int ret;
@@ -1215,7 +1215,11 @@ static int ena_io_poll(struct napi_struct *napi, int budget)
}
tx_work_done = ena_clean_tx_irq(tx_ring, tx_budget);
- rx_work_done = ena_clean_rx_irq(rx_ring, napi, budget);
+ /* On netpoll the budget is zero and the handler should only clean the
+ * tx completions.
+ */
+ if (likely(budget))
+ rx_work_done = ena_clean_rx_irq(rx_ring, napi, budget);
/* If the device is about to reset or down, avoid unmask
* the interrupt and return 0 so NAPI won't reschedule
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index ee5159e..df5e8c2 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -1113,7 +1113,7 @@ static inline u8 bnx2x_get_path_func_num(struct bnx2x *bp)
for (i = 0; i < E1H_FUNC_MAX / 2; i++) {
u32 func_config =
MF_CFG_RD(bp,
- func_mf_config[BP_PORT(bp) + 2 * i].
+ func_mf_config[BP_PATH(bp) + 2 * i].
config);
func_num +=
((func_config & FUNC_MF_CFG_FUNC_HIDE) ? 0 : 1);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index af57568..df4f77a 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -9995,10 +9995,18 @@ static void bnx2x_recovery_failed(struct bnx2x *bp)
*/
static void bnx2x_parity_recover(struct bnx2x *bp)
{
- bool global = false;
u32 error_recovered, error_unrecovered;
- bool is_parity;
+ bool is_parity, global = false;
+#ifdef CONFIG_BNX2X_SRIOV
+ int vf_idx;
+ for (vf_idx = 0; vf_idx < bp->requested_nr_virtfn; vf_idx++) {
+ struct bnx2x_virtf *vf = BP_VF(bp, vf_idx);
+
+ if (vf)
+ vf->state = VF_LOST;
+ }
+#endif
DP(NETIF_MSG_HW, "Handling parity\n");
while (1) {
switch (bp->recovery_state) {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 62da465..ab60f4f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -2394,15 +2394,21 @@ static int bnx2x_set_pf_tx_switching(struct bnx2x *bp, bool enable)
/* send the ramrod on all the queues of the PF */
for_each_eth_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
+ int tx_idx;
/* Set the appropriate Queue object */
q_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
- /* Update the Queue state */
- rc = bnx2x_queue_state_change(bp, &q_params);
- if (rc) {
- BNX2X_ERR("Failed to configure Tx switching\n");
- return rc;
+ for (tx_idx = FIRST_TX_COS_INDEX;
+ tx_idx < fp->max_cos; tx_idx++) {
+ q_params.params.update.cid_index = tx_idx;
+
+ /* Update the Queue state */
+ rc = bnx2x_queue_state_change(bp, &q_params);
+ if (rc) {
+ BNX2X_ERR("Failed to configure Tx switching\n");
+ return rc;
+ }
}
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
index eb814c6..4dc34de 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -139,6 +139,7 @@ struct bnx2x_virtf {
#define VF_ACQUIRED 1 /* VF acquired, but not initialized */
#define VF_ENABLED 2 /* VF Enabled */
#define VF_RESET 3 /* VF FLR'd, pending cleanup */
+#define VF_LOST 4 /* Recovery while VFs are loaded */
bool flr_clnup_stage; /* true during flr cleanup */
bool malicious; /* true if FW indicated so, until FLR */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
index 8e0a317..152758a 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -2114,6 +2114,18 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
{
int i;
+ if (vf->state == VF_LOST) {
+ /* Just ack the FW and return if VFs are lost
+ * in case of parity error. VFs are supposed to be timedout
+ * on waiting for PF response.
+ */
+ DP(BNX2X_MSG_IOV,
+ "VF 0x%x lost, not handling the request\n", vf->abs_vfid);
+
+ storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
+ return;
+ }
+
/* check if tlv type is known */
if (bnx2x_tlv_supported(mbx->first_tlv.tl.type)) {
/* Lock the per vf op mutex and note the locker's identity.
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index 2240c23..0a409ba 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -2778,8 +2778,15 @@ static int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, int msg_len,
}
}
- if (info->dest_buf)
- memcpy(info->dest_buf + off, dma_buf, 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);
+ } else {
+ rc = -ENOBUFS;
+ break;
+ }
+ }
if (cmn_req->req_type ==
cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE))
@@ -2833,7 +2840,7 @@ static int bnxt_hwrm_dbg_coredump_initiate(struct bnxt *bp, u16 component_id,
static int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id,
u16 segment_id, u32 *seg_len,
- void *buf, u32 offset)
+ void *buf, u32 buf_len, u32 offset)
{
struct hwrm_dbg_coredump_retrieve_input req = {0};
struct bnxt_hwrm_dbg_dma_info info = {NULL};
@@ -2848,8 +2855,11 @@ static int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id,
seq_no);
info.data_len_off = offsetof(struct hwrm_dbg_coredump_retrieve_output,
data_len);
- if (buf)
+ if (buf) {
info.dest_buf = buf + offset;
+ info.buf_len = buf_len;
+ info.seg_start = offset;
+ }
rc = bnxt_hwrm_dbg_dma_data(bp, &req, sizeof(req), &info);
if (!rc)
@@ -2939,14 +2949,17 @@ bnxt_fill_coredump_record(struct bnxt *bp, struct bnxt_coredump_record *record,
static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len)
{
u32 ver_get_resp_len = sizeof(struct hwrm_ver_get_output);
+ u32 offset = 0, seg_hdr_len, seg_record_len, buf_len = 0;
struct coredump_segment_record *seg_record = NULL;
- u32 offset = 0, seg_hdr_len, seg_record_len;
struct bnxt_coredump_segment_hdr seg_hdr;
struct bnxt_coredump coredump = {NULL};
time64_t start_time;
u16 start_utc;
int rc = 0, i;
+ if (buf)
+ buf_len = *dump_len;
+
start_time = ktime_get_real_seconds();
start_utc = sys_tz.tz_minuteswest * 60;
seg_hdr_len = sizeof(seg_hdr);
@@ -2979,6 +2992,12 @@ static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len)
u32 duration = 0, seg_len = 0;
unsigned long start, end;
+ if (buf && ((offset + seg_hdr_len) >
+ BNXT_COREDUMP_BUF_LEN(buf_len))) {
+ rc = -ENOBUFS;
+ goto err;
+ }
+
start = jiffies;
rc = bnxt_hwrm_dbg_coredump_initiate(bp, comp_id, seg_id);
@@ -2991,9 +3010,11 @@ static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len)
/* Write segment data into the buffer */
rc = bnxt_hwrm_dbg_coredump_retrieve(bp, comp_id, seg_id,
- &seg_len, buf,
+ &seg_len, buf, buf_len,
offset + seg_hdr_len);
- if (rc)
+ if (rc && rc == -ENOBUFS)
+ goto err;
+ else if (rc)
netdev_err(bp->dev,
"Failed to retrieve coredump for seg = %d\n",
seg_record->segment_id);
@@ -3023,7 +3044,8 @@ static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len)
rc);
kfree(coredump.data);
*dump_len += sizeof(struct bnxt_coredump_record);
-
+ if (rc == -ENOBUFS)
+ netdev_err(bp->dev, "Firmware returned large coredump buffer");
return rc;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h
index b5b65b3..3998f6e 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h
@@ -31,6 +31,8 @@ struct bnxt_coredump {
u16 total_segs;
};
+#define BNXT_COREDUMP_BUF_LEN(len) ((len) - sizeof(struct bnxt_coredump_record))
+
struct bnxt_hwrm_dbg_dma_info {
void *dest_buf;
int dest_buf_size;
@@ -38,6 +40,8 @@ struct bnxt_hwrm_dbg_dma_info {
u16 seq_off;
u16 data_len_off;
u16 segs;
+ u32 seg_start;
+ u32 buf_len;
};
struct hwrm_dbg_cmn_input {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
index b429b72..d320e9a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
@@ -3035,6 +3035,9 @@ static int sge_queue_entries(const struct adapter *adap)
int tot_uld_entries = 0;
int i;
+ if (!is_uld(adap))
+ goto lld_only;
+
mutex_lock(&uld_mutex);
for (i = 0; i < CXGB4_TX_MAX; i++)
tot_uld_entries += sge_qinfo_uld_txq_entries(adap, i);
@@ -3045,6 +3048,7 @@ static int sge_queue_entries(const struct adapter *adap)
}
mutex_unlock(&uld_mutex);
+lld_only:
return DIV_ROUND_UP(adap->sge.ethqsets, 4) +
tot_uld_entries +
DIV_ROUND_UP(MAX_CTRL_QUEUES, 4) + 1;
diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c
index 4af78de..01a2120 100644
--- a/drivers/net/ethernet/cortina/gemini.c
+++ b/drivers/net/ethernet/cortina/gemini.c
@@ -577,6 +577,8 @@ static int gmac_setup_txqs(struct net_device *netdev)
if (port->txq_dma_base & ~DMA_Q_BASE_MASK) {
dev_warn(geth->dev, "TX queue base is not aligned\n");
+ dma_free_coherent(geth->dev, len * sizeof(*desc_ring),
+ desc_ring, port->txq_dma_base);
kfree(skb_tab);
return -ENOMEM;
}
diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
index e8936ae..718afa4 100644
--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
+++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -456,9 +456,9 @@ hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
skb_tx_timestamp(skb);
hip04_set_xmit_desc(priv, phys);
- priv->tx_head = TX_NEXT(tx_head);
count++;
netdev_sent_queue(ndev, skb->len);
+ priv->tx_head = TX_NEXT(tx_head);
stats->tx_bytes += skb->len;
stats->tx_packets++;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index 0788e78..1aaf6e2 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -1474,6 +1474,9 @@ static bool hns3_get_tx_timeo_queue_info(struct net_device *ndev)
time_after(jiffies,
(trans_start + ndev->watchdog_timeo))) {
timeout_queue = i;
+ netdev_info(ndev, "queue state: 0x%lx, delta msecs: %u\n",
+ q->state,
+ jiffies_to_msecs(jiffies - trans_start));
break;
}
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 1a66373..23b31b2 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -3441,14 +3441,14 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
q_vector->rx.target_itr =
ITR_TO_REG(vsi->rx_rings[i]->itr_setting);
wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1),
- q_vector->rx.target_itr);
+ q_vector->rx.target_itr >> 1);
q_vector->rx.current_itr = q_vector->rx.target_itr;
q_vector->tx.next_update = jiffies + 1;
q_vector->tx.target_itr =
ITR_TO_REG(vsi->tx_rings[i]->itr_setting);
wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1),
- q_vector->tx.target_itr);
+ q_vector->tx.target_itr >> 1);
q_vector->tx.current_itr = q_vector->tx.target_itr;
wr32(hw, I40E_PFINT_RATEN(vector - 1),
@@ -3553,11 +3553,11 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
/* set the ITR configuration */
q_vector->rx.next_update = jiffies + 1;
q_vector->rx.target_itr = ITR_TO_REG(vsi->rx_rings[0]->itr_setting);
- wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.target_itr);
+ wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.target_itr >> 1);
q_vector->rx.current_itr = q_vector->rx.target_itr;
q_vector->tx.next_update = jiffies + 1;
q_vector->tx.target_itr = ITR_TO_REG(vsi->tx_rings[0]->itr_setting);
- wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.target_itr);
+ wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.target_itr >> 1);
q_vector->tx.current_itr = q_vector->tx.target_itr;
i40e_enable_misc_int_causes(pf);
@@ -10735,7 +10735,7 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
/* associate no queues to the misc vector */
wr32(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_END_OF_LIST);
- wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), I40E_ITR_8K);
+ wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), I40E_ITR_8K >> 1);
i40e_flush(hw);
diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c
index 89f18fe..921cc0c 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.c
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.c
@@ -911,7 +911,7 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
if (ice_sq_done(hw, cq))
break;
- mdelay(1);
+ udelay(ICE_CTL_Q_SQ_CMD_USEC);
total_delay++;
} while (total_delay < cq->sq_cmd_timeout);
diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h
index ea02b89..0f2cdb0 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.h
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.h
@@ -30,8 +30,9 @@ enum ice_ctl_q {
ICE_CTL_Q_ADMIN,
};
-/* Control Queue default settings */
-#define ICE_CTL_Q_SQ_CMD_TIMEOUT 250 /* msecs */
+/* Control Queue timeout settings - max delay 250ms */
+#define ICE_CTL_Q_SQ_CMD_TIMEOUT 2500 /* Count 2500 times */
+#define ICE_CTL_Q_SQ_CMD_USEC 100 /* Check every 100usec */
struct ice_ctl_q_ring {
void *dma_head; /* Virtual address to dma head */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index b45a6e2..de65ca1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -8551,7 +8551,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
adapter->ptp_clock) {
- if (!test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS,
+ if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON &&
+ !test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS,
&adapter->state)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index a50977c..04bee45 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -3341,7 +3341,7 @@ static int mvpp2_open(struct net_device *dev)
valid = true;
}
- if (priv->hw_version == MVPP22 && port->link_irq && !port->phylink) {
+ if (priv->hw_version == MVPP22 && port->link_irq) {
err = request_irq(port->link_irq, mvpp2_link_status_isr, 0,
dev->name, port);
if (err) {
diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c
index 993cb5b..b99169a 100644
--- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c
+++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c
@@ -37,6 +37,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netlink.h>
+#include <linux/vmalloc.h>
#include <linux/xz.h>
#include "mlxfw_mfa2.h"
#include "mlxfw_mfa2_file.h"
@@ -579,7 +580,7 @@ mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file,
comp_size = be32_to_cpu(comp->size);
comp_buf_size = comp_size + mlxfw_mfa2_comp_magic_len;
- comp_data = kmalloc(sizeof(*comp_data) + comp_buf_size, GFP_KERNEL);
+ comp_data = vzalloc(sizeof(*comp_data) + comp_buf_size);
if (!comp_data)
return ERR_PTR(-ENOMEM);
comp_data->comp.data_size = comp_size;
@@ -601,7 +602,7 @@ mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file,
comp_data->comp.data = comp_data->buff + mlxfw_mfa2_comp_magic_len;
return &comp_data->comp;
err_out:
- kfree(comp_data);
+ vfree(comp_data);
return ERR_PTR(err);
}
@@ -610,7 +611,7 @@ void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *comp)
const struct mlxfw_mfa2_comp_data *comp_data;
comp_data = container_of(comp, struct mlxfw_mfa2_comp_data, comp);
- kfree(comp_data);
+ vfree(comp_data);
}
void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c
index bdf53cf..720514b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c
@@ -650,6 +650,13 @@ mlxsw_sp_qdisc_prio_graft(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_port->tclass_qdiscs[tclass_num].handle == p->child_handle)
return 0;
+ if (!p->child_handle) {
+ /* This is an invisible FIFO replacing the original Qdisc.
+ * Ignore it--the original Qdisc's destroy will follow.
+ */
+ return 0;
+ }
+
/* See if the grafted qdisc is already offloaded on any tclass. If so,
* unoffload it.
*/
diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c
index b16ce7d..c3d5d40a 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_filter.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c
@@ -1230,7 +1230,7 @@ qede_configure_mcast_filtering(struct net_device *ndev,
netif_addr_lock_bh(ndev);
mc_count = netdev_mc_count(ndev);
- if (mc_count < 64) {
+ if (mc_count <= 64) {
netdev_for_each_mc_addr(ha, ndev) {
ether_addr_copy(temp, ha->addr);
temp += ETH_ALEN;
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c
index 630b13a..0d8e39f 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -1362,6 +1362,7 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq)
rxq->rx_buf_seg_size = roundup_pow_of_two(size);
} else {
rxq->rx_buf_seg_size = PAGE_SIZE;
+ edev->ndev->features &= ~NETIF_F_GRO_HW;
}
/* Allocate the parallel driver ring for Rx buffers */
@@ -1406,6 +1407,7 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq)
}
}
+ edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO_HW);
if (!edev->gro_disable)
qede_set_tpa_param(rxq);
err:
@@ -1606,8 +1608,6 @@ static void qede_init_fp(struct qede_dev *edev)
snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
edev->ndev->name, queue_id);
}
-
- edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO_HW);
}
static int qede_set_real_num_queues(struct qede_dev *edev)
diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
index 783ee6a..1b5e098 100644
--- a/drivers/net/ethernet/qlogic/qla3xxx.c
+++ b/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -2757,6 +2757,9 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
int err;
for (i = 0; i < qdev->num_large_buffers; i++) {
+ lrg_buf_cb = &qdev->lrg_buf[i];
+ memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
+
skb = netdev_alloc_skb(qdev->ndev,
qdev->lrg_buffer_len);
if (unlikely(!skb)) {
@@ -2767,11 +2770,7 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
ql_free_large_buffers(qdev);
return -ENOMEM;
} else {
-
- lrg_buf_cb = &qdev->lrg_buf[i];
- memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
lrg_buf_cb->index = i;
- lrg_buf_cb->skb = skb;
/*
* We save some space to copy the ethhdr from first
* buffer
@@ -2793,6 +2792,7 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
return -ENOMEM;
}
+ lrg_buf_cb->skb = skb;
dma_unmap_addr_set(lrg_buf_cb, mapaddr, map);
dma_unmap_len_set(lrg_buf_cb, maplen,
qdev->lrg_buffer_len -
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
index c597956..94b4625 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -118,6 +118,14 @@ static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
struct device *dev = dwmac->dev;
const char *parent_name, *mux_parent_names[MUX_CLK_NUM_PARENTS];
struct meson8b_dwmac_clk_configs *clk_configs;
+ static const struct clk_div_table div_table[] = {
+ { .div = 2, .val = 2, },
+ { .div = 3, .val = 3, },
+ { .div = 4, .val = 4, },
+ { .div = 5, .val = 5, },
+ { .div = 6, .val = 6, },
+ { .div = 7, .val = 7, },
+ };
clk_configs = devm_kzalloc(dev, sizeof(*clk_configs), GFP_KERNEL);
if (!clk_configs)
@@ -152,9 +160,9 @@ static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
clk_configs->m250_div.reg = dwmac->regs + PRG_ETH0;
clk_configs->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
clk_configs->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
- clk_configs->m250_div.flags = CLK_DIVIDER_ONE_BASED |
- CLK_DIVIDER_ALLOW_ZERO |
- CLK_DIVIDER_ROUND_CLOSEST;
+ clk_configs->m250_div.table = div_table;
+ clk_configs->m250_div.flags = CLK_DIVIDER_ALLOW_ZERO |
+ CLK_DIVIDER_ROUND_CLOSEST;
clk = meson8b_dwmac_register_clk(dwmac, "m250_div", &parent_name, 1,
&clk_divider_ops,
&clk_configs->m250_div.hw);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index fea286e..ef13a46 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -946,6 +946,9 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
/* default */
break;
case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII;
break;
case PHY_INTERFACE_MODE_RMII:
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
index 62ccbd4..fc1fa0f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
@@ -53,7 +53,7 @@ static int sun7i_gmac_init(struct platform_device *pdev, void *priv)
* rate, which then uses the auto-reparenting feature of the
* clock driver, and enabling/disabling the clock.
*/
- if (gmac->interface == PHY_INTERFACE_MODE_RGMII) {
+ if (phy_interface_mode_is_rgmii(gmac->interface)) {
clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE);
clk_prepare_enable(gmac->tx_clk);
gmac->clk_enabled = 1;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index 0a80fa2..2097452 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -169,6 +169,8 @@
#define XGMAC_DMA_CH_RX_CONTROL(x) (0x00003108 + (0x80 * (x)))
#define XGMAC_RxPBL GENMASK(21, 16)
#define XGMAC_RxPBL_SHIFT 16
+#define XGMAC_RBSZ GENMASK(14, 1)
+#define XGMAC_RBSZ_SHIFT 1
#define XGMAC_RXST BIT(0)
#define XGMAC_DMA_CH_TxDESC_LADDR(x) (0x00003114 + (0x80 * (x)))
#define XGMAC_DMA_CH_RxDESC_LADDR(x) (0x0000311c + (0x80 * (x)))
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index 1c39305..27942c5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -379,7 +379,8 @@ static void dwxgmac2_set_bfsize(void __iomem *ioaddr, int bfsize, u32 chan)
u32 value;
value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
- value |= bfsize << 1;
+ value &= ~XGMAC_RBSZ;
+ value |= bfsize << XGMAC_RBSZ_SHIFT;
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 014fe93..7ee0e46 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -54,7 +54,7 @@
#include "dwxgmac2.h"
#include "hwif.h"
-#define STMMAC_ALIGN(x) __ALIGN_KERNEL(x, SMP_CACHE_BYTES)
+#define STMMAC_ALIGN(x) ALIGN(ALIGN(x, SMP_CACHE_BYTES), 16)
#define TSO_MAX_BUFF_SIZE (SZ_16K - 1)
/* Module parameters */
@@ -2997,6 +2997,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
tx_q->tx_tail_addr = tx_q->dma_tx_phy + (tx_q->cur_tx * sizeof(*desc));
stmmac_set_tx_tail_ptr(priv, priv->ioaddr, tx_q->tx_tail_addr, queue);
+ stmmac_tx_timer_arm(priv, queue);
return NETDEV_TX_OK;
@@ -3210,6 +3211,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
tx_q->tx_tail_addr = tx_q->dma_tx_phy + (tx_q->cur_tx * sizeof(*desc));
stmmac_set_tx_tail_ptr(priv, priv->ioaddr, tx_q->tx_tail_addr, queue);
+ stmmac_tx_timer_arm(priv, queue);
return NETDEV_TX_OK;
@@ -3604,12 +3606,24 @@ 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);
+ int txfifosz = priv->plat->tx_fifo_size;
+
+ if (txfifosz == 0)
+ txfifosz = priv->dma_cap.tx_fifo_size;
+
+ txfifosz /= priv->plat->tx_queues_to_use;
if (netif_running(dev)) {
netdev_err(priv->dev, "must be stopped to change its MTU\n");
return -EBUSY;
}
+ new_mtu = STMMAC_ALIGN(new_mtu);
+
+ /* If condition true, FIFO is too small or MTU too large */
+ if ((txfifosz < new_mtu) || (new_mtu > BUF_SIZE_16KiB))
+ return -EINVAL;
+
dev->mtu = new_mtu;
netdev_update_features(dev);
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 5766225..c245629 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -793,6 +793,7 @@ EXPORT_SYMBOL_GPL(cpsw_ale_start);
void cpsw_ale_stop(struct cpsw_ale *ale)
{
del_timer_sync(&ale->timer);
+ cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0);
}
EXPORT_SYMBOL_GPL(cpsw_ale_stop);
@@ -877,6 +878,7 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params)
ALE_UNKNOWNVLAN_FORCE_UNTAG_EGRESS;
}
+ cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
return ale;
}
EXPORT_SYMBOL_GPL(cpsw_ale_create);
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 61a9843..1979f8f 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c
@@ -181,6 +181,9 @@ static int fjes_acpi_add(struct acpi_device *device)
/* create platform_device */
plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource,
ARRAY_SIZE(fjes_resource));
+ if (IS_ERR(plat_dev))
+ return PTR_ERR(plat_dev);
+
device->driver_data = plat_dev;
return 0;
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index d178d5b..6571cac 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -42,7 +42,6 @@ struct pdp_ctx {
struct hlist_node hlist_addr;
union {
- u64 tid;
struct {
u64 tid;
u16 flow;
@@ -545,7 +544,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
mtu = dst_mtu(&rt->dst);
}
- rt->dst.ops->update_pmtu(&rt->dst, NULL, skb, mtu);
+ rt->dst.ops->update_pmtu(&rt->dst, NULL, skb, mtu, false);
if (!skb_is_gso(skb) && (iph->frag_off & htons(IP_DF)) &&
mtu < ntohs(iph->tot_len)) {
@@ -645,9 +644,16 @@ static void gtp_link_setup(struct net_device *dev)
}
static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
-static void gtp_hashtable_free(struct gtp_dev *gtp);
static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]);
+static void gtp_destructor(struct net_device *dev)
+{
+ struct gtp_dev *gtp = netdev_priv(dev);
+
+ kfree(gtp->addr_hash);
+ kfree(gtp->tid_hash);
+}
+
static int gtp_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[],
struct netlink_ext_ack *extack)
@@ -665,10 +671,13 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev,
if (err < 0)
return err;
- if (!data[IFLA_GTP_PDP_HASHSIZE])
+ if (!data[IFLA_GTP_PDP_HASHSIZE]) {
hashsize = 1024;
- else
+ } else {
hashsize = nla_get_u32(data[IFLA_GTP_PDP_HASHSIZE]);
+ if (!hashsize)
+ hashsize = 1024;
+ }
err = gtp_hashtable_new(gtp, hashsize);
if (err < 0)
@@ -682,13 +691,15 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev,
gn = net_generic(dev_net(dev), gtp_net_id);
list_add_rcu(>p->list, &gn->gtp_dev_list);
+ dev->priv_destructor = gtp_destructor;
netdev_dbg(dev, "registered new GTP interface\n");
return 0;
out_hashtable:
- gtp_hashtable_free(gtp);
+ kfree(gtp->addr_hash);
+ kfree(gtp->tid_hash);
out_encap:
gtp_encap_disable(gtp);
return err;
@@ -697,9 +708,14 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev,
static void gtp_dellink(struct net_device *dev, struct list_head *head)
{
struct gtp_dev *gtp = netdev_priv(dev);
+ struct pdp_ctx *pctx;
+ int i;
+
+ for (i = 0; i < gtp->hash_size; i++)
+ hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid)
+ pdp_context_delete(pctx);
gtp_encap_disable(gtp);
- gtp_hashtable_free(gtp);
list_del_rcu(>p->list);
unregister_netdevice_queue(dev, head);
}
@@ -777,20 +793,6 @@ static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize)
return -ENOMEM;
}
-static void gtp_hashtable_free(struct gtp_dev *gtp)
-{
- struct pdp_ctx *pctx;
- int i;
-
- for (i = 0; i < gtp->hash_size; i++)
- hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid)
- pdp_context_delete(pctx);
-
- synchronize_rcu();
- kfree(gtp->addr_hash);
- kfree(gtp->tid_hash);
-}
-
static struct sock *gtp_encap_enable_socket(int fd, int type,
struct gtp_dev *gtp)
{
@@ -816,7 +818,7 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,
lock_sock(sock->sk);
if (sock->sk->sk_user_data) {
sk = ERR_PTR(-EBUSY);
- goto out_sock;
+ goto out_rel_sock;
}
sk = sock->sk;
@@ -829,8 +831,9 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,
setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg);
-out_sock:
+out_rel_sock:
release_sock(sock->sk);
+out_sock:
sockfd_put(sock);
return sk;
}
@@ -931,24 +934,31 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
}
}
-static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk,
- struct genl_info *info)
+static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
+ struct genl_info *info)
{
+ struct pdp_ctx *pctx, *pctx_tid = NULL;
struct net_device *dev = gtp->dev;
u32 hash_ms, hash_tid = 0;
- struct pdp_ctx *pctx;
+ unsigned int version;
bool found = false;
__be32 ms_addr;
ms_addr = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
hash_ms = ipv4_hashfn(ms_addr) % gtp->hash_size;
+ version = nla_get_u32(info->attrs[GTPA_VERSION]);
- hlist_for_each_entry_rcu(pctx, >p->addr_hash[hash_ms], hlist_addr) {
- if (pctx->ms_addr_ip4.s_addr == ms_addr) {
- found = true;
- break;
- }
- }
+ pctx = ipv4_pdp_find(gtp, ms_addr);
+ if (pctx)
+ found = true;
+ if (version == GTP_V0)
+ pctx_tid = gtp0_pdp_find(gtp,
+ nla_get_u64(info->attrs[GTPA_TID]));
+ else if (version == GTP_V1)
+ pctx_tid = gtp1_pdp_find(gtp,
+ nla_get_u32(info->attrs[GTPA_I_TEI]));
+ if (pctx_tid)
+ found = true;
if (found) {
if (info->nlhdr->nlmsg_flags & NLM_F_EXCL)
@@ -956,6 +966,11 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk,
if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP;
+ if (pctx && pctx_tid)
+ return -EEXIST;
+ if (!pctx)
+ pctx = pctx_tid;
+
ipv4_pdp_fill(pctx, info);
if (pctx->gtp_version == GTP_V0)
@@ -1079,7 +1094,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
goto out_unlock;
}
- err = ipv4_pdp_add(gtp, sk, info);
+ err = gtp_pdp_add(gtp, sk, info);
out_unlock:
rcu_read_unlock();
@@ -1237,43 +1252,46 @@ static int gtp_genl_dump_pdp(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct gtp_dev *last_gtp = (struct gtp_dev *)cb->args[2], *gtp;
+ int i, j, bucket = cb->args[0], skip = cb->args[1];
struct net *net = sock_net(skb->sk);
- struct gtp_net *gn = net_generic(net, gtp_net_id);
- unsigned long tid = cb->args[1];
- int i, k = cb->args[0], ret;
struct pdp_ctx *pctx;
+ struct gtp_net *gn;
+
+ gn = net_generic(net, gtp_net_id);
if (cb->args[4])
return 0;
+ rcu_read_lock();
list_for_each_entry_rcu(gtp, &gn->gtp_dev_list, list) {
if (last_gtp && last_gtp != gtp)
continue;
else
last_gtp = NULL;
- for (i = k; i < gtp->hash_size; i++) {
- hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid) {
- if (tid && tid != pctx->u.tid)
- continue;
- else
- tid = 0;
-
- ret = gtp_genl_fill_info(skb,
- NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq,
- cb->nlh->nlmsg_type, pctx);
- if (ret < 0) {
+ for (i = bucket; i < gtp->hash_size; i++) {
+ j = 0;
+ hlist_for_each_entry_rcu(pctx, >p->tid_hash[i],
+ hlist_tid) {
+ if (j >= skip &&
+ gtp_genl_fill_info(skb,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ cb->nlh->nlmsg_type, pctx)) {
cb->args[0] = i;
- cb->args[1] = pctx->u.tid;
+ cb->args[1] = j;
cb->args[2] = (unsigned long)gtp;
goto out;
}
+ j++;
}
+ skip = 0;
}
+ bucket = 0;
}
cb->args[4] = 1;
out:
+ rcu_read_unlock();
return skb->len;
}
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 54e63ec..8c636c4 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -654,10 +654,10 @@ static void sixpack_close(struct tty_struct *tty)
{
struct sixpack *sp;
- write_lock_bh(&disc_data_lock);
+ write_lock_irq(&disc_data_lock);
sp = tty->disc_data;
tty->disc_data = NULL;
- write_unlock_bh(&disc_data_lock);
+ write_unlock_irq(&disc_data_lock);
if (!sp)
return;
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 13e4c1e..3b14e6e 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -783,10 +783,10 @@ static void mkiss_close(struct tty_struct *tty)
{
struct mkiss *ax;
- write_lock_bh(&disc_data_lock);
+ write_lock_irq(&disc_data_lock);
ax = tty->disc_data;
tty->disc_data = NULL;
- write_unlock_bh(&disc_data_lock);
+ write_unlock_irq(&disc_data_lock);
if (!ax)
return;
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 31d8d83..50709c7 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -181,7 +181,6 @@ struct rndis_device {
u8 hw_mac_adr[ETH_ALEN];
u8 rss_key[NETVSC_HASH_KEYLEN];
- u16 rx_table[ITAB_NUM];
};
@@ -933,6 +932,8 @@ struct net_device_context {
u32 tx_table[VRSS_SEND_TAB_SIZE];
+ u16 rx_table[ITAB_NUM];
+
/* Ethtool settings */
u8 duplex;
u32 speed;
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index b7a71c2..1f9f7fc 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1688,7 +1688,7 @@ static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
rndis_dev = ndev->extension;
if (indir) {
for (i = 0; i < ITAB_NUM; i++)
- indir[i] = rndis_dev->rx_table[i];
+ indir[i] = ndc->rx_table[i];
}
if (key)
@@ -1718,7 +1718,7 @@ static int netvsc_set_rxfh(struct net_device *dev, const u32 *indir,
return -EINVAL;
for (i = 0; i < ITAB_NUM; i++)
- rndis_dev->rx_table[i] = indir[i];
+ ndc->rx_table[i] = indir[i];
}
if (!key) {
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 53c6039..f47e36a 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -719,6 +719,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev,
const u8 *rss_key, u16 flag)
{
struct net_device *ndev = rdev->ndev;
+ struct net_device_context *ndc = netdev_priv(ndev);
struct rndis_request *request;
struct rndis_set_request *set;
struct rndis_set_complete *set_complete;
@@ -758,7 +759,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev,
/* Set indirection table entries */
itab = (u32 *)(rssp + 1);
for (i = 0; i < ITAB_NUM; i++)
- itab[i] = rdev->rx_table[i];
+ itab[i] = ndc->rx_table[i];
/* Set hask key values */
keyp = (u8 *)((unsigned long)rssp + rssp->hashkey_offset);
@@ -1244,6 +1245,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
struct netvsc_device_info *device_info)
{
struct net_device *net = hv_get_drvdata(dev);
+ struct net_device_context *ndc = netdev_priv(net);
struct netvsc_device *net_device;
struct rndis_device *rndis_device;
struct ndis_recv_scale_cap rsscap;
@@ -1330,9 +1332,11 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
/* We will use the given number of channels if available. */
net_device->num_chn = min(net_device->max_chn, device_info->num_chn);
- for (i = 0; i < ITAB_NUM; i++)
- rndis_device->rx_table[i] = ethtool_rxfh_indir_default(
+ if (!netif_is_rxfh_configured(net)) {
+ for (i = 0; i < ITAB_NUM; i++)
+ ndc->rx_table[i] = ethtool_rxfh_indir_default(
i, net_device->num_chn);
+ }
atomic_set(&net_device->open_chn, 1);
vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open);
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 78789df..41c0a3b 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -263,7 +263,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
struct net_device *src,
enum macvlan_mode mode)
{
- const struct ethhdr *eth = eth_hdr(skb);
+ const struct ethhdr *eth = skb_eth_hdr(skb);
const struct macvlan_dev *vlan;
struct sk_buff *nskb;
unsigned int i;
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index eeadfde..879096d 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -86,6 +86,10 @@
#define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK (0x1f << 8)
#define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8
+/* CFG3 bits */
+#define DP83867_CFG3_INT_OE BIT(7)
+#define DP83867_CFG3_ROBUST_AUTO_MDIX BIT(9)
+
/* CFG4 bits */
#define DP83867_CFG4_PORT_MIRROR_EN BIT(0)
@@ -331,12 +335,13 @@ static int dp83867_config_init(struct phy_device *phydev)
return ret;
}
+ val = phy_read(phydev, DP83867_CFG3);
/* Enable Interrupt output INT_OE in CFG3 register */
- if (phy_interrupt_is_valid(phydev)) {
- val = phy_read(phydev, DP83867_CFG3);
- val |= BIT(7);
- phy_write(phydev, DP83867_CFG3, val);
- }
+ if (phy_interrupt_is_valid(phydev))
+ val |= DP83867_CFG3_INT_OE;
+
+ val |= DP83867_CFG3_ROBUST_AUTO_MDIX;
+ phy_write(phydev, DP83867_CFG3, val);
if (dp83867->port_mirroring != DP83867_PORT_MIRROING_KEEP)
dp83867_config_port_mirroring(phydev);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 6144146..43c4f35 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -420,8 +420,8 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
mdiodev->device_free = phy_mdio_device_free;
mdiodev->device_remove = phy_mdio_device_remove;
- dev->speed = 0;
- dev->duplex = -1;
+ dev->speed = SPEED_UNKNOWN;
+ dev->duplex = DUPLEX_UNKNOWN;
dev->pause = 0;
dev->asym_pause = 0;
dev->link = 0;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 37edf7a..dda409c 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -319,8 +319,8 @@ static void tun_napi_init(struct tun_struct *tun, struct tun_file *tfile,
tfile->napi_enabled = napi_en;
tfile->napi_frags_enabled = napi_en && napi_frags;
if (napi_en) {
- netif_napi_add(tun->dev, &tfile->napi, tun_napi_poll,
- NAPI_POLL_WEIGHT);
+ netif_tx_napi_add(tun->dev, &tfile->napi, tun_napi_poll,
+ NAPI_POLL_WEIGHT);
napi_enable(&tfile->napi);
}
}
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index 457a06aa..57236d6 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -510,7 +510,7 @@ static int lan78xx_read_stats(struct lan78xx_net *dev,
}
} else {
netdev_warn(dev->net,
- "Failed to read stat ret = 0x%x", ret);
+ "Failed to read stat ret = %d", ret);
}
kfree(stats);
@@ -1809,6 +1809,7 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
dev->mdiobus->read = lan78xx_mdiobus_read;
dev->mdiobus->write = lan78xx_mdiobus_write;
dev->mdiobus->name = "lan78xx-mdiobus";
+ dev->mdiobus->parent = &dev->udev->dev;
snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
dev->udev->bus->busnum, dev->udev->devnum);
@@ -2720,11 +2721,6 @@ static int lan78xx_stop(struct net_device *net)
return 0;
}
-static int lan78xx_linearize(struct sk_buff *skb)
-{
- return skb_linearize(skb);
-}
-
static struct sk_buff *lan78xx_tx_prep(struct lan78xx_net *dev,
struct sk_buff *skb, gfp_t flags)
{
@@ -2735,8 +2731,10 @@ static struct sk_buff *lan78xx_tx_prep(struct lan78xx_net *dev,
return NULL;
}
- if (lan78xx_linearize(skb) < 0)
+ if (skb_linearize(skb)) {
+ dev_kfree_skb_any(skb);
return NULL;
+ }
tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN_MASK_) | TX_CMD_A_FCS_;
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index d8a56df..613f366 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -2217,7 +2217,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
ndst = &rt->dst;
skb_tunnel_check_pmtu(skb, ndst, VXLAN_HEADROOM);
- tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
+ tos = ip_tunnel_ecn_encap(RT_TOS(tos), old_iph, skb);
ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr),
vni, md, flags, udp_sum);
@@ -2254,7 +2254,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
skb_tunnel_check_pmtu(skb, ndst, VXLAN6_HEADROOM);
- tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
+ tos = ip_tunnel_ecn_encap(RT_TOS(tos), old_iph, skb);
ttl = ttl ? : ip6_dst_hoplimit(ndst);
skb_scrub_packet(skb, xnet);
err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr),
diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c
index 4d28063..385b84f 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.c
+++ b/drivers/net/wireless/ath/ath10k/coredump.c
@@ -1105,9 +1105,11 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar)
dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_RAM_DATA);
dump_tlv->tlv_len = cpu_to_le32(crash_data->ramdump_buf_len);
- memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf,
- crash_data->ramdump_buf_len);
- sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len;
+ if (crash_data->ramdump_buf_len) {
+ memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf,
+ crash_data->ramdump_buf_len);
+ sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len;
+ }
}
spin_unlock_bh(&ar->data_lock);
@@ -1154,6 +1156,9 @@ int ath10k_coredump_register(struct ath10k *ar)
if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) {
crash_data->ramdump_buf_len = ath10k_coredump_get_ramdump_size(ar);
+ if (!crash_data->ramdump_buf_len)
+ return 0;
+
crash_data->ramdump_buf = vzalloc(crash_data->ramdump_buf_len);
if (!crash_data->ramdump_buf)
return -ENOMEM;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 613ca74..448e3a8 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3651,7 +3651,7 @@ static int ath10k_mac_tx(struct ath10k *ar,
struct ieee80211_vif *vif,
enum ath10k_hw_txrx_mode txmode,
enum ath10k_mac_tx_path txpath,
- struct sk_buff *skb)
+ struct sk_buff *skb, bool noque_offchan)
{
struct ieee80211_hw *hw = ar->hw;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -3679,10 +3679,10 @@ static int ath10k_mac_tx(struct ath10k *ar,
}
}
- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
+ if (!noque_offchan && info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
if (!ath10k_mac_tx_frm_has_freq(ar)) {
- ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %pK\n",
- skb);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac queued offchannel skb %pK len %d\n",
+ skb, skb->len);
skb_queue_tail(&ar->offchan_tx_queue, skb);
ieee80211_queue_work(hw, &ar->offchan_tx_work);
@@ -3744,8 +3744,8 @@ void ath10k_offchan_tx_work(struct work_struct *work)
mutex_lock(&ar->conf_mutex);
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK\n",
- skb);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK len %d\n",
+ skb, skb->len);
hdr = (struct ieee80211_hdr *)skb->data;
peer_addr = ieee80211_get_DA(hdr);
@@ -3791,7 +3791,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
- ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb);
+ ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, true);
if (ret) {
ath10k_warn(ar, "failed to transmit offchannel frame: %d\n",
ret);
@@ -3801,8 +3801,8 @@ void ath10k_offchan_tx_work(struct work_struct *work)
time_left =
wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ);
if (time_left == 0)
- ath10k_warn(ar, "timed out waiting for offchannel skb %pK\n",
- skb);
+ ath10k_warn(ar, "timed out waiting for offchannel skb %pK, len: %d\n",
+ skb, skb->len);
if (!peer && tmp_peer_created) {
ret = ath10k_peer_delete(ar, vdev_id, peer_addr);
@@ -3844,8 +3844,10 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
ar->running_fw->fw_file.fw_features)) {
paddr = dma_map_single(ar->dev, skb->data,
skb->len, DMA_TO_DEVICE);
- if (!paddr)
+ if (dma_mapping_error(ar->dev, paddr)) {
+ ieee80211_free_txskb(ar->hw, skb);
continue;
+ }
ret = ath10k_wmi_mgmt_tx_send(ar, skb, paddr);
if (ret) {
ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n",
@@ -3998,7 +4000,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
spin_unlock_bh(&ar->htt.tx_lock);
}
- ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb);
+ ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false);
if (unlikely(ret)) {
ath10k_warn(ar, "failed to push frame: %d\n", ret);
@@ -4280,7 +4282,7 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw,
spin_unlock_bh(&ar->htt.tx_lock);
}
- ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb);
+ ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false);
if (ret) {
ath10k_warn(ar, "failed to transmit frame: %d\n", ret);
if (is_htt) {
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 6f62ddc..6c47e4b 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -101,6 +101,8 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
info = IEEE80211_SKB_CB(msdu);
memset(&info->status, 0, sizeof(info->status));
+ info->status.rates[0].idx = -1;
+
trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 799010e..b5d7ef4 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -973,6 +973,8 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
struct ath_htc_rx_status *rxstatus;
struct ath_rx_status rx_stats;
bool decrypt_error = false;
+ __be16 rs_datalen;
+ bool is_phyerr;
if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
@@ -982,11 +984,24 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
rxstatus = (struct ath_htc_rx_status *)skb->data;
- if (be16_to_cpu(rxstatus->rs_datalen) -
- (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
+ rs_datalen = be16_to_cpu(rxstatus->rs_datalen);
+ if (unlikely(rs_datalen -
+ (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0)) {
ath_err(common,
"Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n",
- rxstatus->rs_datalen, skb->len);
+ rs_datalen, skb->len);
+ goto rx_next;
+ }
+
+ is_phyerr = rxstatus->rs_status & ATH9K_RXERR_PHY;
+ /*
+ * Discard zero-length packets and packets smaller than an ACK
+ * which are not PHY_ERROR (short radar pulses have a length of 3)
+ */
+ if (unlikely(!rs_datalen || (rs_datalen < 10 && !is_phyerr))) {
+ ath_warn(common,
+ "Short RX data len, dropping (dlen: %d)\n",
+ rs_datalen);
goto rx_next;
}
@@ -1011,7 +1026,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
* Process PHY errors and return so that the packet
* can be dropped.
*/
- if (rx_stats.rs_status & ATH9K_RXERR_PHY) {
+ if (unlikely(is_phyerr)) {
/* TODO: Not using DFS processing now. */
if (ath_cmn_process_fft(&priv->spec_priv, hdr,
&rx_stats, rx_status->mactime)) {
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 8a0bfa4..520b669 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/etherdevice.h>
@@ -1034,7 +1034,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wireless_dev *wdev = vif_to_wdev(vif);
int rc;
- bool fw_reset = false;
+ bool compressed_rx_status, fw_reset = false;
wil_dbg_misc(wil, "change_iface: type=%d\n", type);
@@ -1046,6 +1046,13 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
}
}
+ /* monitor mode uses uncompressed rx status to get phy statistics */
+ compressed_rx_status = wil->use_compressed_rx_status;
+ if (type == NL80211_IFTYPE_MONITOR)
+ wil->use_compressed_rx_status = false;
+ else if (wdev->iftype == NL80211_IFTYPE_MONITOR)
+ wil->use_compressed_rx_status = true;
+
/* do not reset FW when there are active VIFs,
* because it can cause significant disruption
*/
@@ -1059,7 +1066,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
mutex_unlock(&wil->mutex);
if (rc)
- return rc;
+ goto fail;
fw_reset = true;
}
@@ -1074,7 +1081,8 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
wil->monitor_flags = params->flags;
break;
default:
- return -EOPNOTSUPP;
+ rc = -EOPNOTSUPP;
+ goto fail;
}
if (vif->mid != 0 && wil_has_active_ifaces(wil, true, false)) {
@@ -1082,14 +1090,18 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
wil_vif_prepare_stop(vif);
rc = wmi_port_delete(wil, vif->mid);
if (rc)
- return rc;
+ goto fail;
rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr, type);
if (rc)
- return rc;
+ goto fail;
}
wdev->iftype = type;
return 0;
+
+fail:
+ wil->use_compressed_rx_status = compressed_rx_status;
+ return rc;
}
static int wil_cfg80211_scan(struct wiphy *wiphy,
@@ -1378,7 +1390,7 @@ static int wil_ft_connect(struct wiphy *wiphy,
if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities))
if (wil->force_edmg_channel) {
rc = wil_spec2wmi_ch(wil->force_edmg_channel,
- &auth_cmd.channel);
+ &auth_cmd.edmg_channel);
if (rc)
wil_err(wil, "FT: wmi channel for channel %d not found",
wil->force_edmg_channel);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index bac1ec3..311941b 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1,11 +1,10 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/etherdevice.h>
-#include <net/ieee80211_radiotap.h>
#include <linux/if_arp.h>
#include <linux/moduleparam.h>
#include <linux/ip.h>
@@ -331,19 +330,6 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct wil_ring *vring,
static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
struct sk_buff *skb)
{
- struct wil6210_rtap {
- struct ieee80211_radiotap_header rthdr;
- /* fields should be in the order of bits in rthdr.it_present */
- /* flags */
- u8 flags;
- /* channel */
- __le16 chnl_freq __aligned(2);
- __le16 chnl_flags;
- /* MCS */
- u8 mcs_present;
- u8 mcs_flags;
- u8 mcs_index;
- } __packed;
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
struct wil6210_rtap *rtap;
int rtap_len = sizeof(struct wil6210_rtap);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index d9e116b..ba0403b 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -1,12 +1,13 @@
/* SPDX-License-Identifier: ISC */
/*
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#ifndef WIL6210_TXRX_H
#define WIL6210_TXRX_H
+#include <net/ieee80211_radiotap.h>
#include "wil6210.h"
#include "txrx_edma.h"
@@ -491,6 +492,20 @@ struct packet_rx_info {
u8 cid;
};
+struct wil6210_rtap {
+ struct ieee80211_radiotap_header rthdr;
+ /* fields should be in the order of bits in rthdr.it_present */
+ /* flags */
+ u8 flags;
+ /* channel */
+ __le16 chnl_freq __aligned(2);
+ __le16 chnl_flags;
+ /* MCS */
+ u8 mcs_present;
+ u8 mcs_flags;
+ u8 mcs_index;
+} __packed;
+
/* this struct will be stored in the skb cb buffer
* max length of the struct is limited to 48 bytes
*/
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index b72c248..8e7a27b 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: ISC
/*
- * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
*/
#include <linux/etherdevice.h>
#include <linux/moduleparam.h>
+#include <net/ieee80211_radiotap.h>
+#include <linux/if_arp.h>
#include <linux/prefetch.h>
#include <linux/types.h>
#include <linux/list.h>
@@ -181,17 +183,20 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil,
struct wil_rx_enhanced_desc dd, *d = ⅆ
struct wil_rx_enhanced_desc *_d = (struct wil_rx_enhanced_desc *)
&ring->va[i].rx.enhanced;
+ struct net_device *ndev = wil->main_ndev;
+ int headroom = ndev->type == ARPHRD_IEEE80211_RADIOTAP ?
+ WIL6210_RTAP_SIZE : headroom_size;
if (unlikely(list_empty(free))) {
wil->rx_buff_mgmt.free_list_empty_cnt++;
return -EAGAIN;
}
- skb = dev_alloc_skb(sz + headroom_size);
+ skb = dev_alloc_skb(sz + headroom);
if (unlikely(!skb))
return -ENOMEM;
- skb_reserve(skb, headroom_size);
+ skb_reserve(skb, headroom);
skb_put(skb, sz);
/**
@@ -902,6 +907,48 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil,
return 0;
}
+/**
+ * Adds radiotap header
+ *
+ * Any error indicated as "Bad FCS"
+ */
+static void wil_rx_add_radiotap_header_edma(struct wil6210_priv *wil,
+ struct wil_rx_status_extended *s,
+ struct sk_buff *skb)
+{
+ struct wil6210_rtap *rtap;
+ int rtap_len = sizeof(struct wil6210_rtap);
+ struct ieee80211_channel *ch = wil->monitor_chandef.chan;
+
+ if (skb_headroom(skb) < rtap_len &&
+ pskb_expand_head(skb, rtap_len, 0, GFP_ATOMIC)) {
+ wil_err(wil, "Unable to expand headroom to %d\n", rtap_len);
+ return;
+ }
+
+#if defined(BACKPORT_HAS_SKB_PUT_PUSH_RETURN_VOID)
+ rtap = skb_push(skb, rtap_len);
+#else
+ rtap = (void *)skb_push(skb, rtap_len);
+#endif
+ memset(rtap, 0, rtap_len);
+
+ rtap->rthdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ rtap->rthdr.it_len = cpu_to_le16(rtap_len);
+ rtap->rthdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_MCS));
+ if (wil_rx_status_get_error(s))
+ rtap->flags |= IEEE80211_RADIOTAP_F_BADFCS;
+
+ rtap->chnl_freq = cpu_to_le16(ch ? ch->center_freq : 58320);
+ rtap->chnl_flags = cpu_to_le16(0);
+
+ rtap->mcs_present = IEEE80211_RADIOTAP_MCS_HAVE_MCS;
+ rtap->mcs_flags = 0;
+ rtap->mcs_index = wil_rx_status_get_mcs(s);
+}
+
static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
struct wil_status_ring *sring)
{
@@ -922,6 +969,8 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
u8 data_offset;
struct wil_rx_status_extended *s;
u16 sring_idx = sring - wil->srings;
+ struct net_device *ndev = wil->main_ndev;
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
BUILD_BUG_ON(sizeof(struct wil_rx_status_extended) > sizeof(skb->cb));
@@ -1011,13 +1060,6 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
}
stats = &wil->sta[cid].stats;
- if (unlikely(dmalen < ETH_HLEN)) {
- wil_dbg_txrx(wil, "Short frame, len = %d\n", dmalen);
- stats->rx_short_frame++;
- rxdata->skipping = true;
- goto skipping;
- }
-
if (unlikely(dmalen > sz)) {
wil_err(wil, "Rx size too large: %d bytes!\n", dmalen);
print_hex_dump(KERN_ERR, "RxS ", DUMP_PREFIX_OFFSET, 16, 1,
@@ -1027,6 +1069,17 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
stats->rx_large_frame++;
rxdata->skipping = true;
+ goto skipping;
+ }
+
+ /* no extra checks if in sniffer mode */
+ if (wdev->iftype == NL80211_IFTYPE_MONITOR)
+ goto skipping;
+
+ if (unlikely(dmalen < ETH_HLEN)) {
+ wil_dbg_txrx(wil, "Short frame, len = %d\n", dmalen);
+ stats->rx_short_frame++;
+ rxdata->skipping = true;
}
skipping:
@@ -1106,6 +1159,10 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb_headlen(skb), false);
+ /* use radiotap header only if required */
+ if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
+ wil_rx_add_radiotap_header_edma(wil, msg, skb);
+
/* Has to be done after dma_unmap_single as skb->cb is also
* used for holding the pa
*/
@@ -1122,6 +1179,7 @@ void wil_rx_handle_edma(struct wil6210_priv *wil, int *quota)
struct wil_status_ring *sring;
struct sk_buff *skb;
int i;
+ struct wireless_dev *wdev;
if (unlikely(!ring->va)) {
wil_err(wil, "Rx IRQ while Rx not yet initialized\n");
@@ -1155,6 +1213,14 @@ void wil_rx_handle_edma(struct wil6210_priv *wil, int *quota)
continue;
}
ndev = vif_to_ndev(vif);
+ wdev = ndev->ieee80211_ptr;
+ if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
+ skb->dev = ndev;
+ skb_reset_mac_header(skb);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ }
wil_netif_rx_any(skb, ndev);
} else {
wil_rx_reorder(wil, skb);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 818e38d..1119f00 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/moduleparam.h>
@@ -4053,8 +4053,10 @@ int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil,
u16 max_rx_pl_per_desc, bool checksum)
{
struct net_device *ndev = wil->main_ndev;
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
struct wil6210_vif *vif = ndev_to_vif(ndev);
int rc;
+ u8 edmg_channel = 0;
struct wmi_cfg_def_rx_offload_cmd cmd = {
.max_msdu_size = cpu_to_le16(wil_mtu2macbuf(WIL_MAX_ETH_MTU)),
.max_rx_pl_per_desc = cpu_to_le16(max_rx_pl_per_desc),
@@ -4070,6 +4072,27 @@ int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil,
.evt = {.status = WMI_FW_STATUS_FAILURE},
};
+ if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
+ struct ieee80211_channel *ch = wil->monitor_chandef.chan;
+
+ cmd.sniffer_cfg.phy_support =
+ wil->monitor_flags & MONITOR_FLAG_CONTROL ?
+ WMI_SNIFFER_EDMA_CP : WMI_SNIFFER_EDMA_BOTH;
+ if (ch)
+ cmd.sniffer_cfg.channel = ch->hw_value - 1;
+
+ if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING,
+ wil->fw_capabilities))
+ if (wil->force_edmg_channel) {
+ rc = wil_spec2wmi_ch(wil->force_edmg_channel,
+ &edmg_channel);
+ if (rc)
+ wil_err(wil, "wmi channel for channel %d not found\n",
+ wil->force_edmg_channel);
+ }
+ cmd.sniffer_cfg.edmg_channel = edmg_channel;
+ }
+
rc = wmi_call(wil, WMI_CFG_DEF_RX_OFFLOAD_CMDID, vif->mid, &cmd,
sizeof(cmd), WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID, &reply,
sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 3cb6444..e15d4da 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: ISC */
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2006-2012 Wilocity
*/
@@ -1032,6 +1032,26 @@ struct wmi_rx_status_ring_add_cmd {
u8 reserved[2];
} __packed;
+enum wmi_sniffer_edma_cfg_phy_support {
+ WMI_SNIFFER_EDMA_NONE = 0x00,
+ WMI_SNIFFER_EDMA_CP = 0x01,
+ WMI_SNIFFER_EDMA_DP = 0x02,
+ WMI_SNIFFER_EDMA_BOTH = 0x03,
+};
+
+/* wmi_sniffer_edma_cfg */
+struct wmi_sniffer_edma_cfg {
+ /* wmi_sniffer_edma_cfg_phy_support */
+ u8 phy_support;
+ /* enum wmi_channel WMI_CHANNEL_1..WMI_CHANNEL_6; for EDMG this is
+ * the primary channel number
+ */
+ u8 channel;
+ /* enum wmi_channel WMI_CHANNEL_9..WMI_CHANNEL_12 */
+ u8 edmg_channel;
+ u8 reserved;
+} __packed;
+
struct wmi_cfg_def_rx_offload_cmd {
__le16 max_msdu_size;
__le16 max_rx_pl_per_desc;
@@ -1041,7 +1061,8 @@ struct wmi_cfg_def_rx_offload_cmd {
u8 vlan_id;
u8 nwifi_ds_trans_type;
u8 l3_l4_ctrl;
- u8 reserved[6];
+ u8 reserved[2];
+ struct wmi_sniffer_edma_cfg sniffer_cfg;
} __packed;
struct wmi_tx_desc_ring_add_cmd {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 0f56be1..584e05fd 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1246,6 +1246,11 @@ void brcmf_detach(struct device *dev)
brcmf_proto_detach_pre_delif(drvr);
+ if (drvr->mon_if) {
+ brcmf_net_detach(drvr->mon_if->ndev, false);
+ drvr->mon_if = NULL;
+ }
+
/* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
brcmf_remove_interface(drvr->iflist[i], false);
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index d52c5e53..e0e1afe 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -32,6 +32,7 @@
#define FW_ASSERT_TIMEOUT 5000
#define CNSS_EVENT_PENDING 2989
#define COLD_BOOT_CAL_SHUTDOWN_DELAY_MS 50
+#define WLAN_WD_TIMEOUT_MS 60000
#define CNSS_QUIRKS_DEFAULT BIT(DISABLE_IO_COHERENCY)
#ifdef CONFIG_CNSS_EMULATION
@@ -686,7 +687,8 @@ int cnss_idle_restart(struct device *dev)
timeout = cnss_get_boot_timeout(dev);
ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
- msecs_to_jiffies(timeout) << 2);
+ msecs_to_jiffies((timeout << 1) +
+ WLAN_WD_TIMEOUT_MS));
if (!ret) {
cnss_pr_err("Timeout waiting for idle restart to complete\n");
ret = -ETIMEDOUT;
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index 840250a..de95448 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -764,6 +764,22 @@ int cnss_resume_pci_link(struct cnss_pci_data *pci_priv)
return ret;
}
+int cnss_pci_prevent_l1(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+
+ return msm_pcie_prevent_l1(pci_dev);
+}
+EXPORT_SYMBOL(cnss_pci_prevent_l1);
+
+void cnss_pci_allow_l1(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+
+ msm_pcie_allow_l1(pci_dev);
+}
+EXPORT_SYMBOL(cnss_pci_allow_l1);
+
int cnss_pci_link_down(struct device *dev)
{
unsigned long flags;
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index fb109fd..22f059c 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -1029,7 +1029,7 @@ int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv,
return -ENODEV;
if (!data || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) {
- cnss_pr_err("Invalid parameters for athdiag read: data %p, data_len %u\n",
+ cnss_pr_err("Invalid parameters for athdiag read: data %pK, data_len %u\n",
data, data_len);
return -EINVAL;
}
@@ -1116,12 +1116,12 @@ int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
return -ENODEV;
if (!data || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) {
- cnss_pr_err("Invalid parameters for athdiag write: data %p, data_len %u\n",
+ cnss_pr_err("Invalid parameters for athdiag write: data %pK, data_len %u\n",
data, data_len);
return -EINVAL;
}
- cnss_pr_dbg("athdiag write: state 0x%lx, offset %x, mem_type %x, data_len %u, data %p\n",
+ cnss_pr_dbg("athdiag write: state 0x%lx, offset %x, mem_type %x, data_len %u, data %pK\n",
plat_priv->driver_state, offset, mem_type, data_len, data);
req = kzalloc(sizeof(*req), GFP_KERNEL);
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/led.c b/drivers/net/wireless/intel/iwlwifi/dvm/led.c
index 1bbd17a..20e16c4 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/led.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/led.c
@@ -185,6 +185,9 @@ void iwl_leds_init(struct iwl_priv *priv)
priv->led.name = kasprintf(GFP_KERNEL, "%s-led",
wiphy_name(priv->hw->wiphy));
+ if (!priv->led.name)
+ return;
+
priv->led.brightness_set = iwl_led_brightness_set;
priv->led.blink_set = iwl_led_blink_set;
priv->led.max_brightness = 1;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c
index b272695..072f80c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c
@@ -131,6 +131,9 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm)
mvm->led.name = kasprintf(GFP_KERNEL, "%s-led",
wiphy_name(mvm->hw->wiphy));
+ if (!mvm->led.name)
+ return -ENOMEM;
+
mvm->led.brightness_set = iwl_led_brightness_set;
mvm->led.max_brightness = 1;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index bfb1634..e6a67bc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -62,6 +62,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
+#include <asm/unaligned.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "iwl-trans.h"
@@ -360,7 +361,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data;
hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res));
len = le16_to_cpu(rx_res->byte_count);
- rx_pkt_status = le32_to_cpup((__le32 *)
+ rx_pkt_status = get_unaligned_le32((__le32 *)
(pkt->data + sizeof(*rx_res) + len));
/* Dont use dev_alloc_skb(), we'll have enough headroom once
diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c
index 39bf85d..c7f8a29 100644
--- a/drivers/net/wireless/marvell/libertas/if_sdio.c
+++ b/drivers/net/wireless/marvell/libertas/if_sdio.c
@@ -1183,6 +1183,10 @@ static int if_sdio_probe(struct sdio_func *func,
spin_lock_init(&card->lock);
card->workqueue = alloc_workqueue("libertas_sdio", WQ_MEM_RECLAIM, 0);
+ if (unlikely(!card->workqueue)) {
+ ret = -ENOMEM;
+ goto err_queue;
+ }
INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
init_waitqueue_head(&card->pwron_waitq);
@@ -1234,6 +1238,7 @@ static int if_sdio_probe(struct sdio_func *func,
lbs_remove_card(priv);
free:
destroy_workqueue(card->workqueue);
+err_queue:
while (card->packets) {
packet = card->packets;
card->packets = card->packets->next;
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 3fe81b2..918c699 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -691,8 +691,11 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
skb_put(skb, MAX_EVENT_SIZE);
if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
- PCI_DMA_FROMDEVICE))
+ PCI_DMA_FROMDEVICE)) {
+ kfree_skb(skb);
+ kfree(card->evtbd_ring_vbase);
return -1;
+ }
buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c
index 27779d7..6058c48 100644
--- a/drivers/net/wireless/marvell/mwifiex/tdls.c
+++ b/drivers/net/wireless/marvell/mwifiex/tdls.c
@@ -956,59 +956,117 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
switch (*pos) {
case WLAN_EID_SUPP_RATES:
+ if (pos[1] > 32)
+ return;
sta_ptr->tdls_cap.rates_len = pos[1];
for (i = 0; i < pos[1]; i++)
sta_ptr->tdls_cap.rates[i] = pos[i + 2];
break;
case WLAN_EID_EXT_SUPP_RATES:
+ if (pos[1] > 32)
+ return;
basic = sta_ptr->tdls_cap.rates_len;
+ if (pos[1] > 32 - basic)
+ return;
for (i = 0; i < pos[1]; i++)
sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2];
sta_ptr->tdls_cap.rates_len += pos[1];
break;
case WLAN_EID_HT_CAPABILITY:
- memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos,
+ if (pos > end - sizeof(struct ieee80211_ht_cap) - 2)
+ return;
+ if (pos[1] != sizeof(struct ieee80211_ht_cap))
+ return;
+ /* copy the ie's value into ht_capb*/
+ memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos + 2,
sizeof(struct ieee80211_ht_cap));
sta_ptr->is_11n_enabled = 1;
break;
case WLAN_EID_HT_OPERATION:
- memcpy(&sta_ptr->tdls_cap.ht_oper, pos,
+ if (pos > end -
+ sizeof(struct ieee80211_ht_operation) - 2)
+ return;
+ if (pos[1] != sizeof(struct ieee80211_ht_operation))
+ return;
+ /* copy the ie's value into ht_oper*/
+ memcpy(&sta_ptr->tdls_cap.ht_oper, pos + 2,
sizeof(struct ieee80211_ht_operation));
break;
case WLAN_EID_BSS_COEX_2040:
+ if (pos > end - 3)
+ return;
+ if (pos[1] != 1)
+ return;
sta_ptr->tdls_cap.coex_2040 = pos[2];
break;
case WLAN_EID_EXT_CAPABILITY:
+ if (pos > end - sizeof(struct ieee_types_header))
+ return;
+ if (pos[1] < sizeof(struct ieee_types_header))
+ return;
+ if (pos[1] > 8)
+ return;
memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos,
sizeof(struct ieee_types_header) +
min_t(u8, pos[1], 8));
break;
case WLAN_EID_RSN:
+ if (pos > end - sizeof(struct ieee_types_header))
+ return;
+ if (pos[1] < sizeof(struct ieee_types_header))
+ return;
+ if (pos[1] > IEEE_MAX_IE_SIZE -
+ sizeof(struct ieee_types_header))
+ return;
memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,
sizeof(struct ieee_types_header) +
min_t(u8, pos[1], IEEE_MAX_IE_SIZE -
sizeof(struct ieee_types_header)));
break;
case WLAN_EID_QOS_CAPA:
+ if (pos > end - 3)
+ return;
+ if (pos[1] != 1)
+ return;
sta_ptr->tdls_cap.qos_info = pos[2];
break;
case WLAN_EID_VHT_OPERATION:
- if (priv->adapter->is_hw_11ac_capable)
- memcpy(&sta_ptr->tdls_cap.vhtoper, pos,
+ if (priv->adapter->is_hw_11ac_capable) {
+ if (pos > end -
+ sizeof(struct ieee80211_vht_operation) - 2)
+ return;
+ if (pos[1] !=
+ sizeof(struct ieee80211_vht_operation))
+ return;
+ /* copy the ie's value into vhtoper*/
+ memcpy(&sta_ptr->tdls_cap.vhtoper, pos + 2,
sizeof(struct ieee80211_vht_operation));
+ }
break;
case WLAN_EID_VHT_CAPABILITY:
if (priv->adapter->is_hw_11ac_capable) {
- memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos,
+ if (pos > end -
+ sizeof(struct ieee80211_vht_cap) - 2)
+ return;
+ if (pos[1] != sizeof(struct ieee80211_vht_cap))
+ return;
+ /* copy the ie's value into vhtcap*/
+ memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos + 2,
sizeof(struct ieee80211_vht_cap));
sta_ptr->is_11ac_enabled = 1;
}
break;
case WLAN_EID_AID:
- if (priv->adapter->is_hw_11ac_capable)
+ if (priv->adapter->is_hw_11ac_capable) {
+ if (pos > end - 4)
+ return;
+ if (pos[1] != 2)
+ return;
sta_ptr->tdls_cap.aid =
get_unaligned_le16((pos + 2));
+ }
+ break;
default:
break;
}
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
index 8828baf..47c2bfe 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
@@ -1349,6 +1349,7 @@ struct rtl8xxxu_fileops {
u8 has_s0s1:1;
u8 has_tx_report:1;
u8 gen2_thermal_meter:1;
+ u8 needs_full_init:1;
u32 adda_1t_init;
u32 adda_1t_path_on;
u32 adda_2t_path_on_a;
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
index 26b674a..14e207f 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
@@ -1673,6 +1673,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = {
.has_s0s1 = 1,
.has_tx_report = 1,
.gen2_thermal_meter = 1,
+ .needs_full_init = 1,
.adda_1t_init = 0x01c00014,
.adda_1t_path_on = 0x01c00014,
.adda_2t_path_on_a = 0x01c00014,
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
index 2b4fcdf..66c6ee7 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
@@ -3905,6 +3905,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
else
macpower = true;
+ if (fops->needs_full_init)
+ macpower = false;
+
ret = fops->power_on(priv);
if (ret < 0) {
dev_warn(dev, "%s: Failed power on\n", __func__);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c
index 1e60f70..8c60a84 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c
@@ -1556,6 +1556,8 @@ static bool usb_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb)
* This is maybe necessary:
* rtlpriv->cfg->ops->fill_tx_cmddesc(hw, buffer, 1, 1, skb);
*/
+ dev_kfree_skb(skb);
+
return true;
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c
index 5adb939..1181b72 100644
--- a/drivers/net/wireless/realtek/rtlwifi/usb.c
+++ b/drivers/net/wireless/realtek/rtlwifi/usb.c
@@ -1050,8 +1050,10 @@ int rtl_usb_probe(struct usb_interface *intf,
rtlpriv->hw = hw;
rtlpriv->usb_data = kcalloc(RTL_USB_MAX_RX_COUNT, sizeof(u32),
GFP_KERNEL);
- if (!rtlpriv->usb_data)
+ if (!rtlpriv->usb_data) {
+ ieee80211_free_hw(hw);
return -ENOMEM;
+ }
/* this spin lock must be initialized early */
spin_lock_init(&rtlpriv->locks.usb_lock);
@@ -1112,6 +1114,7 @@ int rtl_usb_probe(struct usb_interface *intf,
_rtl_usb_io_handler_release(hw);
usb_put_dev(udev);
complete(&rtlpriv->firmware_loading_complete);
+ kfree(rtlpriv->usb_data);
return -ENODEV;
}
EXPORT_SYMBOL(rtl_usb_probe);
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 0360c01..75ae2c5 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -1260,11 +1260,11 @@ static int btt_read_pg(struct btt *btt, struct bio_integrity_payload *bip,
ret = btt_data_read(arena, page, off, postmap, cur_len);
if (ret) {
- int rc;
-
/* Media error - set the e_flag */
- rc = btt_map_write(arena, premap, postmap, 0, 1,
- NVDIMM_IO_ATOMIC);
+ if (btt_map_write(arena, premap, postmap, 0, 1, NVDIMM_IO_ATOMIC))
+ dev_warn_ratelimited(to_dev(arena),
+ "Error persistently tracking bad blocks at %#x\n",
+ premap);
goto out_rtt;
}
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index b2d9bd5..b7bd89b 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -551,8 +551,14 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
struct nvme_dsm_range *range;
struct bio *bio;
- range = kmalloc_array(segments, sizeof(*range),
- GFP_ATOMIC | __GFP_NOWARN);
+ /*
+ * Some devices do not consider the DSM 'Number of Ranges' field when
+ * determining how much data to DMA. Always allocate memory for maximum
+ * number of segments to prevent device reading beyond end of buffer.
+ */
+ static const size_t alloc_size = sizeof(*range) * NVME_DSM_MAX_RANGES;
+
+ range = kzalloc(alloc_size, GFP_ATOMIC | __GFP_NOWARN);
if (!range) {
/*
* If we fail allocation our range, fallback to the controller
@@ -593,7 +599,7 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
req->special_vec.bv_page = virt_to_page(range);
req->special_vec.bv_offset = offset_in_page(range);
- req->special_vec.bv_len = sizeof(*range) * segments;
+ req->special_vec.bv_len = alloc_size;
req->rq_flags |= RQF_SPECIAL_PAYLOAD;
return BLK_STS_OK;
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 565bddc..1875f6b 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -342,7 +342,8 @@ nvme_fc_register_localport(struct nvme_fc_port_info *pinfo,
!template->ls_req || !template->fcp_io ||
!template->ls_abort || !template->fcp_abort ||
!template->max_hw_queues || !template->max_sgl_segments ||
- !template->max_dif_sgl_segments || !template->dma_boundary) {
+ !template->max_dif_sgl_segments || !template->dma_boundary ||
+ !template->module) {
ret = -EINVAL;
goto out_reghost_failed;
}
@@ -1986,6 +1987,7 @@ nvme_fc_ctrl_free(struct kref *ref)
{
struct nvme_fc_ctrl *ctrl =
container_of(ref, struct nvme_fc_ctrl, ref);
+ struct nvme_fc_lport *lport = ctrl->lport;
unsigned long flags;
if (ctrl->ctrl.tagset) {
@@ -2011,6 +2013,7 @@ nvme_fc_ctrl_free(struct kref *ref)
if (ctrl->ctrl.opts)
nvmf_free_options(ctrl->ctrl.opts);
kfree(ctrl);
+ module_put(lport->ops->module);
}
static void
@@ -2891,10 +2894,22 @@ nvme_fc_reconnect_or_delete(struct nvme_fc_ctrl *ctrl, int status)
static void
__nvme_fc_terminate_io(struct nvme_fc_ctrl *ctrl)
{
- nvme_stop_keep_alive(&ctrl->ctrl);
+ /*
+ * if state is connecting - the error occurred as part of a
+ * reconnect attempt. The create_association error paths will
+ * clean up any outstanding io.
+ *
+ * if it's a different state - ensure all pending io is
+ * terminated. Given this can delay while waiting for the
+ * aborted io to return, we recheck adapter state below
+ * before changing state.
+ */
+ if (ctrl->ctrl.state != NVME_CTRL_CONNECTING) {
+ nvme_stop_keep_alive(&ctrl->ctrl);
- /* will block will waiting for io to terminate */
- nvme_fc_delete_association(ctrl);
+ /* will block will waiting for io to terminate */
+ nvme_fc_delete_association(ctrl);
+ }
if (ctrl->ctrl.state != NVME_CTRL_CONNECTING &&
!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING))
@@ -3040,10 +3055,15 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
goto out_fail;
}
+ if (!try_module_get(lport->ops->module)) {
+ ret = -EUNATCH;
+ goto out_free_ctrl;
+ }
+
idx = ida_simple_get(&nvme_fc_ctrl_cnt, 0, 0, GFP_KERNEL);
if (idx < 0) {
ret = -ENOSPC;
- goto out_free_ctrl;
+ goto out_mod_put;
}
ctrl->ctrl.opts = opts;
@@ -3185,6 +3205,8 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
out_free_ida:
put_device(ctrl->dev);
ida_simple_remove(&nvme_fc_ctrl_cnt, ctrl->cnum);
+out_mod_put:
+ module_put(lport->ops->module);
out_free_ctrl:
kfree(ctrl);
out_fail:
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index 291f412..f0536d3 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -825,6 +825,7 @@ fcloop_targetport_delete(struct nvmet_fc_target_port *targetport)
#define FCLOOP_DMABOUND_4G 0xFFFFFFFF
static struct nvme_fc_port_template fctemplate = {
+ .module = THIS_MODULE,
.localport_delete = fcloop_localport_delete,
.remoteport_delete = fcloop_remoteport_delete,
.create_queue = fcloop_create_queue,
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index afb429a..926d9cc 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -466,6 +466,10 @@ static int imx_ocotp_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
+ clk_prepare_enable(priv->clk);
+ imx_ocotp_clr_err_if_set(priv->base);
+ clk_disable_unprepare(priv->clk);
+
priv->params = of_device_get_match_data(&pdev->dev);
imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
imx_ocotp_nvmem_config.dev = dev;
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 7b4ee33..15c81cf 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -230,6 +230,18 @@ static int port_check(struct device *dev, void *dev_drv)
return 0;
}
+/*
+ * Iterates through all the devices connected to the bus and return 1
+ * if the device is a parallel port.
+ */
+
+static int port_detect(struct device *dev, void *dev_drv)
+{
+ if (is_parport(dev))
+ return 1;
+ return 0;
+}
+
/**
* parport_register_driver - register a parallel port device driver
* @drv: structure describing the driver
@@ -282,6 +294,15 @@ int __parport_register_driver(struct parport_driver *drv, struct module *owner,
if (ret)
return ret;
+ /*
+ * check if bus has any parallel port registered, if
+ * none is found then load the lowlevel driver.
+ */
+ ret = bus_for_each_dev(&parport_bus_type, NULL, NULL,
+ port_detect);
+ if (!ret)
+ get_lowlevel_driver();
+
mutex_lock(®istration_lock);
if (drv->match_port)
bus_for_each_dev(&parport_bus_type, NULL, drv,
diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c
index 13e80d3..3d40cae 100644
--- a/drivers/pci/controller/pci-msm.c
+++ b/drivers/pci/controller/pci-msm.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.*/
+/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.*/
#include <dt-bindings/regulator/qcom,rpmh-regulator-levels.h>
#include <linux/bitops.h>
@@ -4752,7 +4752,7 @@ static void msm_pcie_notify_client(struct msm_pcie_dev_t *dev,
notify->event = event;
notify->user = dev->event_reg->user;
- PCIE_DBG(dev, "PCIe: callback RC%d for event %d\n",
+ PCIE_DUMP(dev, "PCIe: callback RC%d for event %d\n",
dev->rc_idx, event);
dev->event_reg->callback(notify);
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index cc860c5..a306cad 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -154,11 +154,11 @@ static enum pci_bus_speed get_max_bus_speed(struct slot *slot)
return speed;
}
-static int get_children_props(struct device_node *dn, const int **drc_indexes,
- const int **drc_names, const int **drc_types,
- const int **drc_power_domains)
+static int get_children_props(struct device_node *dn, const __be32 **drc_indexes,
+ const __be32 **drc_names, const __be32 **drc_types,
+ const __be32 **drc_power_domains)
{
- const int *indexes, *names, *types, *domains;
+ const __be32 *indexes, *names, *types, *domains;
indexes = of_get_property(dn, "ibm,drc-indexes", NULL);
names = of_get_property(dn, "ibm,drc-names", NULL);
@@ -194,8 +194,8 @@ static int rpaphp_check_drc_props_v1(struct device_node *dn, char *drc_name,
char *drc_type, unsigned int my_index)
{
char *name_tmp, *type_tmp;
- const int *indexes, *names;
- const int *types, *domains;
+ const __be32 *indexes, *names;
+ const __be32 *types, *domains;
int i, rc;
rc = get_children_props(dn->parent, &indexes, &names, &types, &domains);
@@ -208,7 +208,7 @@ static int rpaphp_check_drc_props_v1(struct device_node *dn, char *drc_name,
/* Iterate through parent properties, looking for my-drc-index */
for (i = 0; i < be32_to_cpu(indexes[0]); i++) {
- if ((unsigned int) indexes[i + 1] == my_index)
+ if (be32_to_cpu(indexes[i + 1]) == my_index)
break;
name_tmp += (strlen(name_tmp) + 1);
@@ -239,6 +239,8 @@ static int rpaphp_check_drc_props_v2(struct device_node *dn, char *drc_name,
value = of_prop_next_u32(info, NULL, &entries);
if (!value)
return -EINVAL;
+ else
+ value++;
for (j = 0; j < entries; j++) {
of_read_drc_info_cell(&info, &value, &drc);
@@ -246,9 +248,10 @@ static int rpaphp_check_drc_props_v2(struct device_node *dn, char *drc_name,
/* Should now know end of current entry */
/* Found it */
- if (my_index <= drc.last_drc_index) {
+ if (my_index >= drc.drc_index_start && my_index <= drc.last_drc_index) {
+ int index = my_index - drc.drc_index_start;
sprintf(cell_drc_name, "%s%d", drc.drc_name_prefix,
- my_index);
+ drc.drc_name_suffix_start + index);
break;
}
}
@@ -265,7 +268,7 @@ static int rpaphp_check_drc_props_v2(struct device_node *dn, char *drc_name,
int rpaphp_check_drc_props(struct device_node *dn, char *drc_name,
char *drc_type)
{
- const unsigned int *my_index;
+ const __be32 *my_index;
my_index = of_get_property(dn, "ibm,my-drc-index", NULL);
if (!my_index) {
@@ -273,12 +276,12 @@ int rpaphp_check_drc_props(struct device_node *dn, char *drc_name,
return -EINVAL;
}
- if (firmware_has_feature(FW_FEATURE_DRC_INFO))
+ if (of_find_property(dn->parent, "ibm,drc-info", NULL))
return rpaphp_check_drc_props_v2(dn, drc_name, drc_type,
- *my_index);
+ be32_to_cpu(*my_index));
else
return rpaphp_check_drc_props_v1(dn, drc_name, drc_type,
- *my_index);
+ be32_to_cpu(*my_index));
}
EXPORT_SYMBOL_GPL(rpaphp_check_drc_props);
@@ -309,10 +312,11 @@ static int is_php_type(char *drc_type)
* for built-in pci slots (even when the built-in slots are
* dlparable.)
*/
-static int is_php_dn(struct device_node *dn, const int **indexes,
- const int **names, const int **types, const int **power_domains)
+static int is_php_dn(struct device_node *dn, const __be32 **indexes,
+ const __be32 **names, const __be32 **types,
+ const __be32 **power_domains)
{
- const int *drc_types;
+ const __be32 *drc_types;
int rc;
rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
@@ -347,7 +351,7 @@ int rpaphp_add_slot(struct device_node *dn)
struct slot *slot;
int retval = 0;
int i;
- const int *indexes, *names, *types, *power_domains;
+ const __be32 *indexes, *names, *types, *power_domains;
char *name, *type;
if (!dn->name || strcmp(dn->name, "pci"))
diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c
index 72db2e0..5aaa4ce 100644
--- a/drivers/pci/switch/switchtec.c
+++ b/drivers/pci/switch/switchtec.c
@@ -13,7 +13,7 @@
#include <linux/uaccess.h>
#include <linux/poll.h>
#include <linux/wait.h>
-
+#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/nospec.h>
MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver");
@@ -633,7 +633,7 @@ static int ioctl_event_summary(struct switchtec_dev *stdev,
u32 reg;
s.global = ioread32(&stdev->mmio_sw_event->global_summary);
- s.part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap);
+ s.part_bitmap = readq(&stdev->mmio_sw_event->part_event_bitmap);
s.local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary);
for (i = 0; i < stdev->partition_count; i++) {
diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c
index abbbe75..5629d56 100644
--- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c
+++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c
@@ -160,8 +160,8 @@ static int qcom_usb_hs_phy_power_on(struct phy *phy)
/* setup initial state */
qcom_usb_hs_phy_vbus_notifier(&uphy->vbus_notify, state,
uphy->vbus_edev);
- ret = devm_extcon_register_notifier(&ulpi->dev, uphy->vbus_edev,
- EXTCON_USB, &uphy->vbus_notify);
+ ret = extcon_register_notifier(uphy->vbus_edev, EXTCON_USB,
+ &uphy->vbus_notify);
if (ret)
goto err_ulpi;
}
@@ -182,6 +182,9 @@ static int qcom_usb_hs_phy_power_off(struct phy *phy)
{
struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy);
+ if (uphy->vbus_edev)
+ extcon_unregister_notifier(uphy->vbus_edev, EXTCON_USB,
+ &uphy->vbus_notify);
regulator_disable(uphy->v3p3);
regulator_disable(uphy->v1p8);
clk_disable_unprepare(uphy->sleep_clk);
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index 2969ff3..177ee11 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -40,6 +40,13 @@ struct pinctrl_dt_map {
static void dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps)
{
+ int i;
+
+ for (i = 0; i < num_maps; ++i) {
+ kfree_const(map[i].dev_name);
+ map[i].dev_name = NULL;
+ }
+
if (pctldev) {
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
if (ops->dt_free_map)
@@ -74,7 +81,13 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
/* Initialize common mapping table entry fields */
for (i = 0; i < num_maps; i++) {
- map[i].dev_name = dev_name(p->dev);
+ const char *devname;
+
+ devname = kstrdup_const(dev_name(p->dev), GFP_KERNEL);
+ if (!devname)
+ goto err_free_map;
+
+ map[i].dev_name = devname;
map[i].name = statename;
if (pctldev)
map[i].ctrl_dev_name = dev_name(pctldev->dev);
@@ -82,10 +95,8 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
/* Remember the converted mapping table entries */
dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
- if (!dt_map) {
- dt_free_map(pctldev, map, num_maps);
- return -ENOMEM;
- }
+ if (!dt_map)
+ goto err_free_map;
dt_map->pctldev = pctldev;
dt_map->map = map;
@@ -93,6 +104,10 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
list_add_tail(&dt_map->node, &p->dt_maps);
return pinctrl_register_map(map, num_maps, false);
+
+err_free_map:
+ dt_free_map(pctldev, map, num_maps);
+ return -ENOMEM;
}
struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index f38d596..021e28f 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -196,7 +196,6 @@ struct byt_gpio {
struct platform_device *pdev;
struct pinctrl_dev *pctl_dev;
struct pinctrl_desc pctl_desc;
- raw_spinlock_t lock;
const struct byt_pinctrl_soc_data *soc_data;
struct byt_community *communities_copy;
struct byt_gpio_pin_context *saved_context;
@@ -707,6 +706,8 @@ static const struct byt_pinctrl_soc_data *byt_soc_data[] = {
NULL,
};
+static DEFINE_RAW_SPINLOCK(byt_lock);
+
static struct byt_community *byt_get_community(struct byt_gpio *vg,
unsigned int pin)
{
@@ -848,7 +849,7 @@ static void byt_set_group_simple_mux(struct byt_gpio *vg,
unsigned long flags;
int i;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
for (i = 0; i < group.npins; i++) {
void __iomem *padcfg0;
@@ -868,7 +869,7 @@ static void byt_set_group_simple_mux(struct byt_gpio *vg,
writel(value, padcfg0);
}
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
}
static void byt_set_group_mixed_mux(struct byt_gpio *vg,
@@ -878,7 +879,7 @@ static void byt_set_group_mixed_mux(struct byt_gpio *vg,
unsigned long flags;
int i;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
for (i = 0; i < group.npins; i++) {
void __iomem *padcfg0;
@@ -898,7 +899,7 @@ static void byt_set_group_mixed_mux(struct byt_gpio *vg,
writel(value, padcfg0);
}
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
}
static int byt_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
@@ -947,11 +948,11 @@ static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned int offset)
unsigned long flags;
u32 value;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
value = readl(reg);
value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
writel(value, reg);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
}
static int byt_gpio_request_enable(struct pinctrl_dev *pctl_dev,
@@ -963,7 +964,7 @@ static int byt_gpio_request_enable(struct pinctrl_dev *pctl_dev,
u32 value, gpio_mux;
unsigned long flags;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
/*
* In most cases, func pin mux 000 means GPIO function.
@@ -985,7 +986,7 @@ static int byt_gpio_request_enable(struct pinctrl_dev *pctl_dev,
"pin %u forcibly re-configured as GPIO\n", offset);
}
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
pm_runtime_get(&vg->pdev->dev);
@@ -1013,7 +1014,7 @@ static int byt_gpio_set_direction(struct pinctrl_dev *pctl_dev,
unsigned long flags;
u32 value;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
value = readl(val_reg);
value &= ~BYT_DIR_MASK;
@@ -1030,7 +1031,7 @@ static int byt_gpio_set_direction(struct pinctrl_dev *pctl_dev,
"Potential Error: Setting GPIO with direct_irq_en to output");
writel(value, val_reg);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0;
}
@@ -1099,11 +1100,11 @@ static int byt_pin_config_get(struct pinctrl_dev *pctl_dev, unsigned int offset,
u32 conf, pull, val, debounce;
u16 arg = 0;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
conf = readl(conf_reg);
pull = conf & BYT_PULL_ASSIGN_MASK;
val = readl(val_reg);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
@@ -1130,9 +1131,9 @@ static int byt_pin_config_get(struct pinctrl_dev *pctl_dev, unsigned int offset,
if (!(conf & BYT_DEBOUNCE_EN))
return -EINVAL;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
debounce = readl(db_reg);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
switch (debounce & BYT_DEBOUNCE_PULSE_MASK) {
case BYT_DEBOUNCE_PULSE_375US:
@@ -1184,7 +1185,7 @@ static int byt_pin_config_set(struct pinctrl_dev *pctl_dev,
u32 conf, val, debounce;
int i, ret = 0;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
conf = readl(conf_reg);
val = readl(val_reg);
@@ -1292,7 +1293,7 @@ static int byt_pin_config_set(struct pinctrl_dev *pctl_dev,
if (!ret)
writel(conf, conf_reg);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
return ret;
}
@@ -1317,9 +1318,9 @@ static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
unsigned long flags;
u32 val;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
val = readl(reg);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
return !!(val & BYT_LEVEL);
}
@@ -1334,13 +1335,13 @@ static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
if (!reg)
return;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
old_val = readl(reg);
if (value)
writel(old_val | BYT_LEVEL, reg);
else
writel(old_val & ~BYT_LEVEL, reg);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
}
static int byt_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
@@ -1353,9 +1354,9 @@ static int byt_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
if (!reg)
return -EINVAL;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
value = readl(reg);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
if (!(value & BYT_OUTPUT_EN))
return GPIOF_DIR_OUT;
@@ -1398,14 +1399,14 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
const char *label;
unsigned int pin;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
pin = vg->soc_data->pins[i].number;
reg = byt_gpio_reg(vg, pin, BYT_CONF0_REG);
if (!reg) {
seq_printf(s,
"Could not retrieve pin %i conf0 reg\n",
pin);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
continue;
}
conf0 = readl(reg);
@@ -1414,11 +1415,11 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
if (!reg) {
seq_printf(s,
"Could not retrieve pin %i val reg\n", pin);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
continue;
}
val = readl(reg);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
comm = byt_get_community(vg, pin);
if (!comm) {
@@ -1502,9 +1503,9 @@ static void byt_irq_ack(struct irq_data *d)
if (!reg)
return;
- raw_spin_lock(&vg->lock);
+ raw_spin_lock(&byt_lock);
writel(BIT(offset % 32), reg);
- raw_spin_unlock(&vg->lock);
+ raw_spin_unlock(&byt_lock);
}
static void byt_irq_mask(struct irq_data *d)
@@ -1528,7 +1529,7 @@ static void byt_irq_unmask(struct irq_data *d)
if (!reg)
return;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
value = readl(reg);
switch (irqd_get_trigger_type(d)) {
@@ -1551,7 +1552,7 @@ static void byt_irq_unmask(struct irq_data *d)
writel(value, reg);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
}
static int byt_irq_type(struct irq_data *d, unsigned int type)
@@ -1565,7 +1566,7 @@ static int byt_irq_type(struct irq_data *d, unsigned int type)
if (!reg || offset >= vg->chip.ngpio)
return -EINVAL;
- raw_spin_lock_irqsave(&vg->lock, flags);
+ raw_spin_lock_irqsave(&byt_lock, flags);
value = readl(reg);
WARN(value & BYT_DIRECT_IRQ_EN,
@@ -1587,7 +1588,7 @@ static int byt_irq_type(struct irq_data *d, unsigned int type)
else if (type & IRQ_TYPE_LEVEL_MASK)
irq_set_handler_locked(d, handle_level_irq);
- raw_spin_unlock_irqrestore(&vg->lock, flags);
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0;
}
@@ -1623,9 +1624,9 @@ static void byt_gpio_irq_handler(struct irq_desc *desc)
continue;
}
- raw_spin_lock(&vg->lock);
+ raw_spin_lock(&byt_lock);
pending = readl(reg);
- raw_spin_unlock(&vg->lock);
+ raw_spin_unlock(&byt_lock);
for_each_set_bit(pin, &pending, 32) {
virq = irq_find_mapping(vg->chip.irq.domain, base + pin);
generic_handle_irq(virq);
@@ -1828,8 +1829,6 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
return PTR_ERR(vg->pctl_dev);
}
- raw_spin_lock_init(&vg->lock);
-
ret = byt_gpio_probe(vg);
if (ret)
return ret;
@@ -1845,8 +1844,11 @@ static int byt_gpio_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct byt_gpio *vg = platform_get_drvdata(pdev);
+ unsigned long flags;
int i;
+ raw_spin_lock_irqsave(&byt_lock, flags);
+
for (i = 0; i < vg->soc_data->npins; i++) {
void __iomem *reg;
u32 value;
@@ -1867,6 +1869,7 @@ static int byt_gpio_suspend(struct device *dev)
vg->saved_context[i].val = value;
}
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0;
}
@@ -1874,8 +1877,11 @@ static int byt_gpio_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct byt_gpio *vg = platform_get_drvdata(pdev);
+ unsigned long flags;
int i;
+ raw_spin_lock_irqsave(&byt_lock, flags);
+
for (i = 0; i < vg->soc_data->npins; i++) {
void __iomem *reg;
u32 value;
@@ -1913,6 +1919,7 @@ static int byt_gpio_resume(struct device *dev)
}
}
+ raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0;
}
#endif
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index cd7a5d9..b1ffdd3 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -544,7 +544,8 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
irqreturn_t ret = IRQ_NONE;
unsigned int i, irqnr;
unsigned long flags;
- u32 *regs, regval;
+ u32 __iomem *regs;
+ u32 regval;
u64 status, mask;
/* Read the wake status */
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
index 3323204..3eccc9b 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
@@ -1453,7 +1453,7 @@ static const struct pinmux_func pinmux_func_gpios[] = {
GPIO_FN(ET0_ETXD2_A),
GPIO_FN(EX_CS5), GPIO_FN(SD1_CMD_A), GPIO_FN(ATADIR), GPIO_FN(QSSL_B),
GPIO_FN(ET0_ETXD3_A),
- GPIO_FN(RD_WR), GPIO_FN(TCLK1_B),
+ GPIO_FN(RD_WR), GPIO_FN(TCLK0), GPIO_FN(CAN_CLK_B), GPIO_FN(ET0_ETXD4),
GPIO_FN(EX_WAIT0), GPIO_FN(TCLK1_B),
GPIO_FN(EX_WAIT1), GPIO_FN(SD1_DAT0_A), GPIO_FN(DREQ2),
GPIO_FN(CAN1_TX_C), GPIO_FN(ET0_LINK_C), GPIO_FN(ET0_ETXD5_A),
@@ -1949,7 +1949,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
/* IP3_20 [1] */
FN_EX_WAIT0, FN_TCLK1_B,
/* IP3_19_18 [2] */
- FN_RD_WR, FN_TCLK1_B, 0, 0,
+ FN_RD_WR, FN_TCLK0, FN_CAN_CLK_B, FN_ET0_ETXD4,
/* IP3_17_15 [3] */
FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B,
FN_ET0_ETXD3_A, 0, 0, 0,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index b57aaf1..ccf0d26 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -721,7 +721,8 @@ static ssize_t ipa3_read_rt(struct file *file, char __user *ubuf, size_t count,
list_for_each_entry(tbl, &set->head_rt_tbl_list, link) {
i = 0;
list_for_each_entry(entry, &tbl->head_rt_rule_list, link) {
- if (entry->proc_ctx) {
+ if (entry->proc_ctx &&
+ (!ipa3_check_idr_if_freed(entry->proc_ctx))) {
ofst = entry->proc_ctx->offset_entry->offset;
ofst_words =
(ofst +
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c
index 69d35a3..84d760b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include "ipa_i.h"
@@ -418,6 +418,7 @@ static int ipa_adpl_open(struct inode *inode, struct file *filp)
int ret = 0;
IPADBG("Called the function :\n");
+ mutex_lock(&ipa3_odl_ctx->pipe_lock);
if (ipa3_odl_ctx->odl_state.odl_init &&
!ipa3_odl_ctx->odl_state.adpl_open) {
/* Activate ipa_pm*/
@@ -431,6 +432,7 @@ static int ipa_adpl_open(struct inode *inode, struct file *filp)
print_ipa_odl_state_bit_mask();
ret = -ENODEV;
}
+ mutex_unlock(&ipa3_odl_ctx->pipe_lock);
return ret;
}
@@ -439,6 +441,7 @@ static int ipa_adpl_release(struct inode *inode, struct file *filp)
{
int ret = 0;
/* Deactivate ipa_pm */
+ mutex_lock(&ipa3_odl_ctx->pipe_lock);
ret = ipa_pm_deactivate_sync(ipa3_odl_ctx->odl_pm_hdl);
if (ret)
IPAERR("failed to activate pm\n");
@@ -451,6 +454,7 @@ static int ipa_adpl_release(struct inode *inode, struct file *filp)
IPAERR("mpm failed to disable ADPL over ODL\n");
}
+ mutex_unlock(&ipa3_odl_ctx->pipe_lock);
return ret;
}
@@ -667,6 +671,7 @@ int ipa_odl_init(void)
odl_cdev = ipa3_odl_ctx->odl_cdev;
INIT_LIST_HEAD(&ipa3_odl_ctx->adpl_msg_list);
mutex_init(&ipa3_odl_ctx->adpl_msg_lock);
+ mutex_init(&ipa3_odl_ctx->pipe_lock);
odl_cdev[loop].class = class_create(THIS_MODULE, "ipa_adpl");
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h
index 5049001..72c07b0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _IPA3_ODL_H_
@@ -51,6 +51,7 @@ struct ipa_odl_context {
struct ipa3_odl_char_device_context odl_cdev[2];
struct list_head adpl_msg_list;
struct mutex adpl_msg_lock;
+ struct mutex pipe_lock;
struct ipa_sys_connect_params odl_sys_param;
u32 odl_client_hdl;
struct odl_state_bit_mask odl_state;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index 7c6f123..5ee5ebd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/bitops.h>
@@ -1741,7 +1741,8 @@ int __ipa3_del_rt_rule(u32 rule_hdl)
return -EINVAL;
}
- if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
+ if (!ipa3_check_idr_if_freed(entry) &&
+ !strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
IPADBG("Deleting rule from default rt table idx=%u\n",
entry->tbl->idx);
if (entry->tbl->rule_cnt == 1) {
@@ -1971,7 +1972,8 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only)
}
}
tbl->rule_cnt--;
- if (rule->hdr)
+ if (rule->hdr &&
+ (!ipa3_check_idr_if_freed(rule->hdr)))
__ipa3_release_hdr(rule->hdr->id);
else if (rule->proc_ctx &&
(!ipa3_check_idr_if_freed(
@@ -2174,7 +2176,8 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy_i *rtrule)
goto error;
}
- if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
+ if (!ipa3_check_idr_if_freed(entry) &&
+ !strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
IPAERR_RL("Default tbl rule cannot be modified\n");
return -EINVAL;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index dbe30cf..9703a56 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -2068,6 +2068,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 12, 4, 4, 4, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} },
+ [IPA_4_2][IPA_CLIENT_ODL_DPL_CONS] = {
+ true, IPA_v4_2_GROUP_UL_DL,
+ false,
+ IPA_DPS_HPS_SEQ_TYPE_INVALID,
+ QMB_MASTER_SELECT_DDR,
+ { 13, 10, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} },
[IPA_4_2][IPA_CLIENT_APPS_LAN_CONS] = {
true, IPA_v4_2_GROUP_UL_DL,
false,
@@ -2092,12 +2098,6 @@ static const struct ipa_ep_configuration ipa3_ep_mapping
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 10, 2, 6, 6, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY} },
- [IPA_4_2][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = {
- true, IPA_v4_2_GROUP_UL_DL,
- false,
- IPA_DPS_HPS_SEQ_TYPE_INVALID,
- QMB_MASTER_SELECT_DDR,
- { 13, 4, 6, 6, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY} },
[IPA_4_2][IPA_CLIENT_ETHERNET_CONS] = {
true, IPA_v4_2_GROUP_UL_DL,
false,
@@ -6205,7 +6205,7 @@ void ipa3_counter_remove_hdl(int hdl)
}
/* remove counters belong to this hdl, set used back to 0 */
offset = counter->hw_counter.start_id - 1;
- if (offset >= 0 && offset + counter->hw_counter.num_counters
+ if (offset >= 0 && (offset + counter->hw_counter.num_counters)
< IPA_FLT_RT_HW_COUNTER) {
memset(&ipa3_ctx->flt_rt_counters.used_hw + offset,
0, counter->hw_counter.num_counters * sizeof(bool));
@@ -6214,7 +6214,7 @@ void ipa3_counter_remove_hdl(int hdl)
goto err;
}
offset = counter->sw_counter.start_id - 1 - IPA_FLT_RT_HW_COUNTER;
- if (offset >= 0 && offset + counter->sw_counter.num_counters
+ if (offset >= 0 && (offset + counter->sw_counter.num_counters)
< IPA_FLT_RT_SW_COUNTER) {
memset(&ipa3_ctx->flt_rt_counters.used_sw + offset,
0, counter->sw_counter.num_counters * sizeof(bool));
diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c
index 1a31ef1..4537ad2 100644
--- a/drivers/platform/msm/msm_ext_display.c
+++ b/drivers/platform/msm/msm_ext_display.c
@@ -128,6 +128,7 @@ static int msm_ext_disp_remove_intf_data(struct msm_ext_disp *ext_disp,
if (node->data == data) {
list_del(pos);
pr_debug("Deleted the intf data\n");
+ kfree(node);
return 0;
}
}
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index b253405..2d2980f 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -53,12 +53,15 @@ static const char *const pmic_names[] = {
[PM660L_SUBTYPE] = "PM660L",
[PM660_SUBTYPE] = "PM660",
[PMI632_SUBTYPE] = "PMI632",
- [PMI8937_SUBTYPE] = "PMI8937",
+ [PM2250_SUBTYPE] = "PM2250",
[PM8150_SUBTYPE] = "PM8150",
[PM8150B_SUBTYPE] = "PM8150B",
[PM8150L_SUBTYPE] = "PM8150L",
[PM6150_SUBTYPE] = "PM6150",
[PM7250B_SUBTYPE] = "PM7250B",
+ [PM6350_SUBTYPE] = "PM6350",
+ [PMK8350_SUBTYPE] = "PMK8350",
+ [PMR735B_SUBTYPE] = "PMR735B",
[PM6125_SUBTYPE] = "PM6125",
[PM8008_SUBTYPE] = "PM8008",
[SMB1355_SUBTYPE] = "SMB1355",
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index d0ffdd5..06a3c1e 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -313,7 +313,7 @@ static int __init hp_wmi_bios_2008_later(void)
static int __init hp_wmi_bios_2009_later(void)
{
- int state = 0;
+ u8 state[128];
int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, HPWMI_READ, &state,
sizeof(state), sizeof(state));
if (!ret)
diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c
index 429166e6..9c94ebb 100644
--- a/drivers/platform/x86/pmc_atom.c
+++ b/drivers/platform/x86/pmc_atom.c
@@ -452,6 +452,14 @@ static const struct dmi_system_id critclk_systems[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "6ES7647-8B"),
},
},
+ {
+ .ident = "CONNECT X300",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "A5E45074588"),
+ },
+ },
+
{ /*sentinel*/ }
};
diff --git a/drivers/power/supply/qcom/battery.h b/drivers/power/supply/qcom/battery.h
index b25afd6..acb4984 100644
--- a/drivers/power/supply/qcom/battery.h
+++ b/drivers/power/supply/qcom/battery.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (c) 2017, 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019-2020 The Linux Foundation. All rights reserved.
*/
#ifndef __BATTERY_H
@@ -10,6 +10,7 @@ struct charger_param {
u32 fcc_step_delay_ms;
u32 fcc_step_size_ua;
u32 smb_version;
+ u32 hvdcp2_max_icl_ua;
u32 hvdcp3_max_icl_ua;
u32 forced_main_fcc;
};
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c
index 38af5c9..7ae08c7 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen4.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "FG: %s: " fmt, __func__
@@ -2745,14 +2745,14 @@ static int fg_gen4_update_maint_soc(struct fg_dev *fg)
goto out;
}
- if (msoc > fg->maint_soc) {
+ if (msoc >= fg->maint_soc) {
/*
* When the monotonic SOC goes above maintenance SOC, we should
* stop showing the maintenance SOC.
*/
fg->delta_soc = 0;
fg->maint_soc = 0;
- } else if (fg->maint_soc && msoc <= fg->last_msoc) {
+ } else if (fg->maint_soc && msoc < fg->last_msoc) {
/* MSOC is decreasing. Decrease maintenance SOC as well */
fg->maint_soc -= 1;
if (!(msoc % 10)) {
@@ -4209,13 +4209,11 @@ static void status_change_work(struct work_struct *work)
cycle_count_update(chip->counter, (u32)batt_soc >> 24,
fg->charge_status, fg->charge_done, input_present);
- if (fg->charge_status != fg->prev_charge_status) {
- batt_soc_cp = div64_u64((u64)(u32)batt_soc * CENTI_FULL_SOC,
- BATT_SOC_32BIT);
- cap_learning_update(chip->cl, batt_temp, batt_soc_cp,
+ batt_soc_cp = div64_u64((u64)(u32)batt_soc * CENTI_FULL_SOC,
+ BATT_SOC_32BIT);
+ cap_learning_update(chip->cl, batt_temp, batt_soc_cp,
fg->charge_status, fg->charge_done, input_present,
qnovo_en);
- }
rc = fg_gen4_charge_full_update(fg);
if (rc < 0)
@@ -4251,7 +4249,6 @@ static void status_change_work(struct work_struct *work)
pr_err("Failed to validate SOC scale mode, rc=%d\n", rc);
ttf_update(chip->ttf, input_present);
- fg->prev_charge_status = fg->charge_status;
out:
fg_dbg(fg, FG_STATUS, "charge_status:%d charge_type:%d charge_done:%d\n",
fg->charge_status, fg->charge_type, fg->charge_done);
@@ -6209,7 +6206,6 @@ static int fg_gen4_probe(struct platform_device *pdev)
fg->debug_mask = &fg_gen4_debug_mask;
fg->irqs = fg_irqs;
fg->charge_status = -EINVAL;
- fg->prev_charge_status = -EINVAL;
fg->online_status = -EINVAL;
fg->batt_id_ohms = -EINVAL;
chip->ki_coeff_full_soc[0] = -EINVAL;
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index 45912b3..9785605 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -600,6 +600,11 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node)
if (chg->chg_param.hvdcp3_max_icl_ua <= 0)
chg->chg_param.hvdcp3_max_icl_ua = MICRO_3PA;
+ of_property_read_u32(node, "qcom,hvdcp2-max-icl-ua",
+ &chg->chg_param.hvdcp2_max_icl_ua);
+ if (chg->chg_param.hvdcp2_max_icl_ua <= 0)
+ chg->chg_param.hvdcp2_max_icl_ua = MICRO_3PA;
+
return 0;
}
@@ -1302,7 +1307,7 @@ static int smb5_usb_main_get_prop(struct power_supply *psy,
break;
/* Use this property to report SMB health */
case POWER_SUPPLY_PROP_HEALTH:
- val->intval = smblib_get_prop_smb_health(chg);
+ rc = val->intval = smblib_get_prop_smb_health(chg);
break;
/* Use this property to report overheat status */
case POWER_SUPPLY_PROP_HOT_TEMP:
@@ -1313,12 +1318,10 @@ static int smb5_usb_main_get_prop(struct power_supply *psy,
rc = -EINVAL;
break;
}
- if (rc < 0) {
+ if (rc < 0)
pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
- return -ENODATA;
- }
- return 0;
+ return rc;
}
static int smb5_usb_main_set_prop(struct power_supply *psy,
@@ -2116,14 +2119,18 @@ static int smb5_configure_typec(struct smb_charger *chg)
return rc;
}
+ val = EN_TRY_SNK_BIT;
+ /* PMI632 doesn't support try snk */
+ if (chg->chg_param.smb_version == PMI632_SUBTYPE)
+ val = 0;
+
/* enable try.snk and clear force sink for DRP mode */
rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
EN_TRY_SNK_BIT | EN_SNK_ONLY_BIT,
- EN_TRY_SNK_BIT);
+ val);
if (rc < 0) {
dev_err(chg->dev,
- "Couldn't configure TYPE_C_MODE_CFG_REG rc=%d\n",
- rc);
+ "Couldn't configure TYPE_C_MODE_CFG_REG rc=%d\n", rc);
return rc;
}
chg->typec_try_mode |= EN_TRY_SNK_BIT;
diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c
index 5bbaca7..e93cb9d 100644
--- a/drivers/power/supply/qcom/smb1355-charger.c
+++ b/drivers/power/supply/qcom/smb1355-charger.c
@@ -1197,6 +1197,16 @@ static int smb1355_init_hw(struct smb1355 *chip)
return rc;
}
+ /* disable charging when watchdog bites & set bite-timeout to 8secs */
+ val = BITE_WDOG_DISABLE_CHARGING_CFG_BIT | 0x3;
+ rc = smb1355_masked_write(chip, SNARL_BARK_BITE_WD_CFG_REG,
+ BITE_WDOG_DISABLE_CHARGING_CFG_BIT |
+ BITE_WDOG_TIMEOUT_MASK, val);
+ if (rc < 0) {
+ pr_err("Couldn't configure the watchdog bite rc=%d\n", rc);
+ return rc;
+ }
+
/* enable watchdog bark and bite interrupts, and disable the watchdog */
rc = smb1355_masked_write(chip, WD_CFG_REG, WDOG_TIMER_EN_BIT
| WDOG_TIMER_EN_ON_PLUGIN_BIT | BITE_WDOG_INT_EN_BIT
@@ -1207,15 +1217,6 @@ static int smb1355_init_hw(struct smb1355 *chip)
return rc;
}
- /* disable charging when watchdog bites */
- rc = smb1355_masked_write(chip, SNARL_BARK_BITE_WD_CFG_REG,
- BITE_WDOG_DISABLE_CHARGING_CFG_BIT,
- BITE_WDOG_DISABLE_CHARGING_CFG_BIT);
- if (rc < 0) {
- pr_err("Couldn't configure the watchdog bite rc=%d\n", rc);
- return rc;
- }
-
/*
* Disable command based SMB1355 enablement and disable parallel
* charging path by switching to command based mode.
diff --git a/drivers/power/supply/qcom/smb1390-charger-psy.c b/drivers/power/supply/qcom/smb1390-charger-psy.c
index 5d35981..833c8b6 100644
--- a/drivers/power/supply/qcom/smb1390-charger-psy.c
+++ b/drivers/power/supply/qcom/smb1390-charger-psy.c
@@ -1393,6 +1393,7 @@ static int smb1390_get_prop(struct power_supply *psy,
rc = smb1390_get_prop_suspended(chip, prop, val);
if (!rc)
return rc;
+ rc = 0;
}
switch (prop) {
diff --git a/drivers/power/supply/qcom/smb1398-charger.c b/drivers/power/supply/qcom/smb1398-charger.c
index 5b373a2..15ca324 100644
--- a/drivers/power/supply/qcom/smb1398-charger.c
+++ b/drivers/power/supply/qcom/smb1398-charger.c
@@ -310,6 +310,12 @@ struct smb1398_chip {
u32 pl_input_mode;
enum isns_mode current_capability;
int cc_mode_taper_main_icl_ua;
+ int cp_status1;
+ int cp_status2;
+ int cp_enable;
+ int cp_isns_master;
+ int cp_isns_slave;
+ int cp_ilim;
bool status_change_running;
bool taper_work_running;
@@ -486,7 +492,7 @@ static int smb1398_get_die_temp(struct smb1398_chip *chip, int *temp)
dev_err(chip->dev, "Couldn't read die_temp_chan, rc=%d\n", rc);
} else {
*temp = die_temp_deciC / 100;
- dev_dbg(chip->dev, "Couldn't get die temp %d\n", *temp);
+ dev_dbg(chip->dev, "die temp %d\n", *temp);
}
return rc;
@@ -827,6 +833,45 @@ static enum power_supply_property div2_cp_master_props[] = {
POWER_SUPPLY_PROP_MIN_ICL,
};
+static int div2_cp_master_get_prop_suspended(struct smb1398_chip *chip,
+ enum power_supply_property prop,
+ union power_supply_propval *val)
+{
+ switch (prop) {
+ case POWER_SUPPLY_PROP_CP_STATUS1:
+ val->intval = chip->cp_status1;
+ break;
+ case POWER_SUPPLY_PROP_CP_STATUS2:
+ val->intval = chip->cp_status2;
+ break;
+ case POWER_SUPPLY_PROP_CP_ENABLE:
+ val->intval = chip->cp_enable;
+ break;
+ case POWER_SUPPLY_PROP_CP_SWITCHER_EN:
+ val->intval = chip->switcher_en;
+ break;
+ case POWER_SUPPLY_PROP_CP_DIE_TEMP:
+ val->intval = chip->die_temp;
+ break;
+ case POWER_SUPPLY_PROP_CP_ISNS:
+ val->intval = chip->cp_isns_master;
+ break;
+ case POWER_SUPPLY_PROP_CP_ISNS_SLAVE:
+ val->intval = chip->cp_isns_slave;
+ break;
+ case POWER_SUPPLY_PROP_CP_IRQ_STATUS:
+ val->intval = chip->div2_irq_status;
+ break;
+ case POWER_SUPPLY_PROP_CP_ILIM:
+ val->intval = chip->cp_ilim;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int div2_cp_master_get_prop(struct power_supply *psy,
enum power_supply_property prop,
union power_supply_propval *val)
@@ -835,21 +880,32 @@ static int div2_cp_master_get_prop(struct power_supply *psy,
int rc = 0, ilim_ma, temp, isns_ua;
u8 status;
+ /*
+ * Return the cached values when the system is in suspend state
+ * instead of reading the registers to avoid read failures.
+ */
+ if (chip->in_suspend) {
+ rc = div2_cp_master_get_prop_suspended(chip, prop, val);
+ if (!rc)
+ return rc;
+ rc = 0;
+ }
+
switch (prop) {
case POWER_SUPPLY_PROP_CP_STATUS1:
rc = smb1398_div2_cp_get_status1(chip, &status);
if (!rc)
- val->intval = status;
+ chip->cp_status1 = val->intval = status;
break;
case POWER_SUPPLY_PROP_CP_STATUS2:
rc = smb1398_div2_cp_get_status2(chip, &status);
if (!rc)
- val->intval = status;
+ chip->cp_status2 = val->intval = status;
break;
case POWER_SUPPLY_PROP_CP_ENABLE:
rc = smb1398_get_enable_status(chip);
if (!rc)
- val->intval = chip->smb_en &&
+ chip->cp_enable = val->intval = chip->smb_en &&
!get_effective_result(
chip->div2_cp_disable_votable);
break;
@@ -861,27 +917,27 @@ static int div2_cp_master_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_CP_ISNS:
rc = smb1398_div2_cp_get_master_isns(chip, &isns_ua);
if (rc >= 0)
- val->intval = isns_ua;
+ chip->cp_isns_master = val->intval = isns_ua;
break;
case POWER_SUPPLY_PROP_CP_ISNS_SLAVE:
rc = smb1398_div2_cp_get_slave_isns(chip, &isns_ua);
if (rc >= 0)
- val->intval = isns_ua;
+ chip->cp_isns_slave = val->intval = isns_ua;
break;
case POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER:
val->intval = 0;
break;
case POWER_SUPPLY_PROP_CP_DIE_TEMP:
- if (!chip->in_suspend) {
- rc = smb1398_get_die_temp(chip, &temp);
- if ((rc >= 0) && (temp <= THERMAL_SUSPEND_DECIDEGC))
+ rc = smb1398_get_die_temp(chip, &temp);
+ if (rc >= 0) {
+ val->intval = temp;
+ if (temp <= THERMAL_SUSPEND_DECIDEGC)
chip->die_temp = temp;
+ else if (chip->die_temp == -ENODATA)
+ rc = -ENODATA;
+ else
+ val->intval = chip->die_temp;
}
-
- if (chip->die_temp != -ENODATA)
- val->intval = chip->die_temp;
- else
- rc = -ENODATA;
break;
case POWER_SUPPLY_PROP_CP_IRQ_STATUS:
val->intval = chip->div2_irq_status;
@@ -899,6 +955,7 @@ static int div2_cp_master_get_prop(struct power_supply *psy,
if (!rc)
val->intval = ilim_ma * 1000;
}
+ chip->cp_ilim = val->intval;
break;
case POWER_SUPPLY_PROP_CHIP_VERSION:
val->intval = chip->pmic_rev_id->rev4;
@@ -1429,6 +1486,13 @@ static int smb1398_request_interrupt(struct smb1398_chip *chip,
if (!smb_irqs[irq_index].handler)
return 0;
+ /*
+ * Do not register temp-shdwn interrupt as it may misfire on toggling
+ * the SMB_EN input.
+ */
+ if (irq_index == TEMP_SHDWN_IRQ)
+ return 0;
+
rc = devm_request_threaded_irq(chip->dev, irq, NULL,
smb_irqs[irq_index].handler,
IRQF_ONESHOT, irq_name, chip);
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index 682c0fc..a6329ca 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -3953,7 +3953,6 @@ int smblib_get_pe_start(struct smb_charger *chg,
int smblib_get_prop_smb_health(struct smb_charger *chg)
{
int rc;
- u8 stat;
int input_present;
union power_supply_propval prop = {0, };
@@ -3961,50 +3960,21 @@ int smblib_get_prop_smb_health(struct smb_charger *chg)
if (rc < 0)
return rc;
- if (input_present == INPUT_NOT_PRESENT)
+ if ((input_present == INPUT_NOT_PRESENT) || (!is_cp_available(chg)))
return POWER_SUPPLY_HEALTH_UNKNOWN;
- /*
- * SMB health is used only for CP, report UNKNOWN if
- * switcher is not enabled.
- */
- if (is_cp_available(chg)) {
- rc = power_supply_get_property(chg->cp_psy,
- POWER_SUPPLY_PROP_CP_SWITCHER_EN, &prop);
- if (!rc && !prop.intval)
- return POWER_SUPPLY_HEALTH_UNKNOWN;
- }
+ rc = power_supply_get_property(chg->cp_psy,
+ POWER_SUPPLY_PROP_CP_DIE_TEMP, &prop);
+ if (rc < 0)
+ return rc;
- if (chg->wa_flags & SW_THERM_REGULATION_WA) {
- if (chg->smb_temp == -ENODATA)
- return POWER_SUPPLY_HEALTH_UNKNOWN;
-
- if (chg->smb_temp > SMB_TEMP_RST_THRESH)
- return POWER_SUPPLY_HEALTH_OVERHEAT;
-
- if (chg->smb_temp > SMB_TEMP_REG_H_THRESH)
- return POWER_SUPPLY_HEALTH_HOT;
-
- if (chg->smb_temp > SMB_TEMP_REG_L_THRESH)
- return POWER_SUPPLY_HEALTH_WARM;
-
- return POWER_SUPPLY_HEALTH_COOL;
- }
-
- rc = smblib_read(chg, SMB_TEMP_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read SMB_TEMP_STATUS_REG, rc=%d\n",
- rc);
- return POWER_SUPPLY_HEALTH_UNKNOWN;
- }
-
- if (stat & SMB_TEMP_RST_BIT)
+ if (prop.intval > SMB_TEMP_RST_THRESH)
return POWER_SUPPLY_HEALTH_OVERHEAT;
- if (stat & SMB_TEMP_UB_BIT)
+ if (prop.intval > SMB_TEMP_REG_H_THRESH)
return POWER_SUPPLY_HEALTH_HOT;
- if (stat & SMB_TEMP_LB_BIT)
+ if (prop.intval > SMB_TEMP_REG_L_THRESH)
return POWER_SUPPLY_HEALTH_WARM;
return POWER_SUPPLY_HEALTH_COOL;
@@ -5056,6 +5026,7 @@ static void smblib_eval_chg_termination(struct smb_charger *chg, u8 batt_status)
if ((batt_status == TERMINATE_CHARGE) && (pval.intval == 100)) {
chg->cc_soc_ref = 0;
chg->last_cc_soc = 0;
+ chg->term_vbat_uv = 0;
alarm_start_relative(&chg->chg_termination_alarm,
ms_to_ktime(CHG_TERM_WA_ENTRY_DELAY_MS));
} else if (pval.intval < 100) {
@@ -5065,6 +5036,7 @@ static void smblib_eval_chg_termination(struct smb_charger *chg, u8 batt_status)
*/
chg->cc_soc_ref = 0;
chg->last_cc_soc = 0;
+ chg->term_vbat_uv = 0;
}
}
@@ -5552,16 +5524,23 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
bool rising, bool qc_charger)
{
+ u32 hvdcp_ua = 0;
+
if (rising) {
if (qc_charger) {
+ hvdcp_ua = (chg->real_charger_type ==
+ POWER_SUPPLY_TYPE_USB_HVDCP) ?
+ chg->chg_param.hvdcp2_max_icl_ua :
+ HVDCP_CURRENT_UA;
+
/* enable HDC and ICL irq for QC2/3 charger */
vote(chg->limited_irq_disable_votable,
CHARGER_TYPE_VOTER, false, 0);
vote(chg->hdc_irq_disable_votable,
CHARGER_TYPE_VOTER, false, 0);
vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
- HVDCP_CURRENT_UA);
+ hvdcp_ua);
} else {
/* A plain DCP, enforce DCP ICL if specified */
vote(chg->usb_icl_votable, DCP_VOTER,
@@ -5898,23 +5877,26 @@ static int typec_partner_register(struct smb_charger *chg)
{
int typec_mode, rc = 0;
- if (!chg->typec_port)
- return 0;
+ mutex_lock(&chg->typec_lock);
- if (chg->typec_partner && chg->pr_swap_in_progress)
- return 0;
+ if (!chg->typec_port || chg->pr_swap_in_progress)
+ goto unlock;
- if (chg->sink_src_mode == AUDIO_ACCESS_MODE)
- chg->typec_partner_desc.accessory = TYPEC_ACCESSORY_AUDIO;
- else
- chg->typec_partner_desc.accessory = TYPEC_ACCESSORY_NONE;
+ if (!chg->typec_partner) {
+ if (chg->sink_src_mode == AUDIO_ACCESS_MODE)
+ chg->typec_partner_desc.accessory =
+ TYPEC_ACCESSORY_AUDIO;
+ else
+ chg->typec_partner_desc.accessory =
+ TYPEC_ACCESSORY_NONE;
- chg->typec_partner = typec_register_partner(chg->typec_port,
- &chg->typec_partner_desc);
- if (IS_ERR(chg->typec_partner)) {
- rc = PTR_ERR(chg->typec_partner);
- pr_err("failed to register typec_partner rc=%d\n", rc);
- return rc;
+ chg->typec_partner = typec_register_partner(chg->typec_port,
+ &chg->typec_partner_desc);
+ if (IS_ERR(chg->typec_partner)) {
+ rc = PTR_ERR(chg->typec_partner);
+ pr_err("failed to register typec_partner rc=%d\n", rc);
+ goto unlock;
+ }
}
typec_mode = smblib_get_prop_typec_mode(chg);
@@ -5928,16 +5910,22 @@ static int typec_partner_register(struct smb_charger *chg)
typec_set_pwr_role(chg->typec_port, TYPEC_SOURCE);
}
+unlock:
+ mutex_unlock(&chg->typec_lock);
return rc;
}
static void typec_partner_unregister(struct smb_charger *chg)
{
+ mutex_lock(&chg->typec_lock);
+
if (chg->typec_partner && !chg->pr_swap_in_progress) {
smblib_dbg(chg, PR_MISC, "Un-registering typeC partner\n");
typec_unregister_partner(chg->typec_partner);
chg->typec_partner = NULL;
}
+
+ mutex_unlock(&chg->typec_lock);
}
static const char * const dr_mode_text[] = {
@@ -6476,10 +6464,13 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data)
* swap is not in progress, to ensure forced sink or src
* mode configuration is reset properly.
*/
+ mutex_lock(&chg->typec_lock);
if (chg->typec_port && !chg->pr_swap_in_progress)
smblib_force_dr_mode(chg, TYPEC_PORT_DRP);
+ mutex_unlock(&chg->typec_lock);
+
if (chg->lpd_stage == LPD_STAGE_FLOAT_CANCEL)
schedule_delayed_work(&chg->lpd_detach_work,
msecs_to_jiffies(1000));
@@ -7347,6 +7338,7 @@ static void smblib_chg_termination_work(struct work_struct *work)
struct smb_charger *chg = container_of(work, struct smb_charger,
chg_termination_work);
int rc, input_present, delay = CHG_TERM_WA_ENTRY_DELAY_MS;
+ int vbat_now_uv, max_fv_uv;
/*
* Hold awake votable to prevent pm_relax being called prior to
@@ -7366,6 +7358,14 @@ static void smblib_chg_termination_work(struct work_struct *work)
goto out;
}
+ /* Get the battery float voltage */
+ rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ &pval);
+ if (rc < 0)
+ goto out;
+
+ max_fv_uv = pval.intval;
+
rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CHARGE_FULL,
&pval);
if (rc < 0)
@@ -7379,6 +7379,20 @@ static void smblib_chg_termination_work(struct work_struct *work)
*/
if (pval.intval != chg->charge_full_cc || !chg->cc_soc_ref) {
chg->charge_full_cc = pval.intval;
+
+ rc = smblib_get_prop_from_bms(chg,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval);
+ if (rc < 0)
+ goto out;
+
+ /*
+ * Store the Vbat at the charge termination to compare with
+ * the current voltage to see if the Vbat is increasing after
+ * charge termination in BSM.
+ */
+ chg->term_vbat_uv = pval.intval;
+ vbat_now_uv = pval.intval;
+
rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CC_SOC,
&pval);
if (rc < 0)
@@ -7386,6 +7400,13 @@ static void smblib_chg_termination_work(struct work_struct *work)
chg->cc_soc_ref = pval.intval;
} else {
+ rc = smblib_get_prop_from_bms(chg,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval);
+ if (rc < 0)
+ goto out;
+
+ vbat_now_uv = pval.intval;
+
rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CC_SOC,
&pval);
if (rc < 0)
@@ -7406,15 +7427,18 @@ static void smblib_chg_termination_work(struct work_struct *work)
/*
* Suspend/Unsuspend USB input to keep cc_soc within the 0.5% to 0.75%
- * overshoot range of the cc_soc value at termination, to prevent
- * overcharging.
+ * overshoot range of the cc_soc value at termination and make sure that
+ * vbat is indeed rising above vfloat.
*/
if (pval.intval < DIV_ROUND_CLOSEST(chg->cc_soc_ref * 10050, 10000)) {
vote(chg->usb_icl_votable, CHG_TERMINATION_VOTER, false, 0);
vote(chg->dc_suspend_votable, CHG_TERMINATION_VOTER, false, 0);
delay = CHG_TERM_WA_ENTRY_DELAY_MS;
- } else if (pval.intval > DIV_ROUND_CLOSEST(chg->cc_soc_ref * 10075,
- 10000)) {
+ } else if ((pval.intval > DIV_ROUND_CLOSEST(chg->cc_soc_ref * 10075,
+ 10000))
+ && ((vbat_now_uv > chg->term_vbat_uv) &&
+ (vbat_now_uv > max_fv_uv))) {
+
if (input_present & INPUT_PRESENT_USB)
vote(chg->usb_icl_votable, CHG_TERMINATION_VOTER,
true, 0);
@@ -7424,8 +7448,9 @@ static void smblib_chg_termination_work(struct work_struct *work)
delay = CHG_TERM_WA_EXIT_DELAY_MS;
}
- smblib_dbg(chg, PR_MISC, "Chg Term WA readings: cc_soc: %d, cc_soc_ref: %d, delay: %d\n",
- pval.intval, chg->cc_soc_ref, delay);
+ smblib_dbg(chg, PR_MISC, "Chg Term WA readings: cc_soc: %d, cc_soc_ref: %d, delay: %d vbat_now %d term_vbat %d\n",
+ pval.intval, chg->cc_soc_ref, delay, vbat_now_uv,
+ chg->term_vbat_uv);
alarm_start_relative(&chg->chg_termination_alarm, ms_to_ktime(delay));
out:
vote(chg->awake_votable, CHG_TERMINATION_VOTER, false, 0);
diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h
index 0ec3828..a6d14b7 100644
--- a/drivers/power/supply/qcom/smb5-lib.h
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -568,6 +568,7 @@ struct smb_charger {
int charge_full_cc;
int cc_soc_ref;
int last_cc_soc;
+ int term_vbat_uv;
int usbin_forced_max_uv;
int init_thermal_ua;
u32 comp_clamp_level;
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index c64903a..b818f65 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -175,9 +175,9 @@ static struct posix_clock_operations ptp_clock_ops = {
.read = ptp_read,
};
-static void delete_ptp_clock(struct posix_clock *pc)
+static void ptp_clock_release(struct device *dev)
{
- struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+ struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev);
mutex_destroy(&ptp->tsevq_mux);
mutex_destroy(&ptp->pincfg_mux);
@@ -222,7 +222,6 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
}
ptp->clock.ops = ptp_clock_ops;
- ptp->clock.release = delete_ptp_clock;
ptp->info = info;
ptp->devid = MKDEV(major, index);
ptp->index = index;
@@ -249,15 +248,6 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
if (err)
goto no_pin_groups;
- /* Create a new device in our class. */
- ptp->dev = device_create_with_groups(ptp_class, parent, ptp->devid,
- ptp, ptp->pin_attr_groups,
- "ptp%d", ptp->index);
- if (IS_ERR(ptp->dev)) {
- err = PTR_ERR(ptp->dev);
- goto no_device;
- }
-
/* Register a new PPS source. */
if (info->pps) {
struct pps_source_info pps;
@@ -273,8 +263,18 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
}
}
- /* Create a posix clock. */
- err = posix_clock_register(&ptp->clock, ptp->devid);
+ /* Initialize a new device of our class in our clock structure. */
+ device_initialize(&ptp->dev);
+ ptp->dev.devt = ptp->devid;
+ ptp->dev.class = ptp_class;
+ ptp->dev.parent = parent;
+ ptp->dev.groups = ptp->pin_attr_groups;
+ ptp->dev.release = ptp_clock_release;
+ dev_set_drvdata(&ptp->dev, ptp);
+ dev_set_name(&ptp->dev, "ptp%d", ptp->index);
+
+ /* Create a posix clock and link it to the device. */
+ err = posix_clock_register(&ptp->clock, &ptp->dev);
if (err) {
pr_err("failed to create posix clock\n");
goto no_clock;
@@ -286,8 +286,6 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
if (ptp->pps_source)
pps_unregister_source(ptp->pps_source);
no_pps:
- device_destroy(ptp_class, ptp->devid);
-no_device:
ptp_cleanup_pin_groups(ptp);
no_pin_groups:
if (ptp->kworker)
@@ -317,7 +315,6 @@ int ptp_clock_unregister(struct ptp_clock *ptp)
if (ptp->pps_source)
pps_unregister_source(ptp->pps_source);
- device_destroy(ptp_class, ptp->devid);
ptp_cleanup_pin_groups(ptp);
posix_clock_unregister(&ptp->clock);
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
index c7c62b7..05f6b6a 100644
--- a/drivers/ptp/ptp_private.h
+++ b/drivers/ptp/ptp_private.h
@@ -41,7 +41,7 @@ struct timestamp_event_queue {
struct ptp_clock {
struct posix_clock clock;
- struct device *dev;
+ struct device dev;
struct ptp_clock_info *info;
dev_t devid;
int index; /* index into clocks.map */
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index 83dba3f..6057882 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -956,23 +956,6 @@ static struct ab8500_regulator_info
.update_val_idle = 0x82,
.update_val_normal = 0x02,
},
- [AB8505_LDO_USB] = {
- .desc = {
- .name = "LDO-USB",
- .ops = &ab8500_regulator_mode_ops,
- .type = REGULATOR_VOLTAGE,
- .id = AB8505_LDO_USB,
- .owner = THIS_MODULE,
- .n_voltages = 1,
- .volt_table = fixed_3300000_voltage,
- },
- .update_bank = 0x03,
- .update_reg = 0x82,
- .update_mask = 0x03,
- .update_val = 0x01,
- .update_val_idle = 0x03,
- .update_val_normal = 0x01,
- },
[AB8505_LDO_AUDIO] = {
.desc = {
.name = "LDO-AUDIO",
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 316861b..f2360fa 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1742,8 +1742,8 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
regulator = create_regulator(rdev, dev, id);
if (regulator == NULL) {
regulator = ERR_PTR(-ENOMEM);
- put_device(&rdev->dev);
module_put(rdev->owner);
+ put_device(&rdev->dev);
return regulator;
}
@@ -1869,13 +1869,13 @@ static void _regulator_put(struct regulator *regulator)
rdev->open_count--;
rdev->exclusive = 0;
- put_device(&rdev->dev);
regulator_unlock(rdev);
kfree_const(regulator->supply_name);
kfree(regulator);
module_put(rdev->owner);
+ put_device(&rdev->dev);
}
/**
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c
index 860400d..a8f2f07 100644
--- a/drivers/regulator/max8907-regulator.c
+++ b/drivers/regulator/max8907-regulator.c
@@ -299,7 +299,10 @@ static int max8907_regulator_probe(struct platform_device *pdev)
memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
/* Backwards compatibility with MAX8907B; SD1 uses different voltages */
- regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
+ ret = regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
+ if (ret)
+ return ret;
+
if ((val & MAX8907_II2RR_VERSION_MASK) ==
MAX8907_II2RR_VERSION_REV_B) {
pmic->desc[MAX8907_SD1].min_uV = 637500;
@@ -336,14 +339,20 @@ static int max8907_regulator_probe(struct platform_device *pdev)
}
if (pmic->desc[i].ops == &max8907_ldo_ops) {
- regmap_read(config.regmap, pmic->desc[i].enable_reg,
+ ret = regmap_read(config.regmap, pmic->desc[i].enable_reg,
&val);
+ if (ret)
+ return ret;
+
if ((val & MAX8907_MASK_LDO_SEQ) !=
MAX8907_MASK_LDO_SEQ)
pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
} else if (pmic->desc[i].ops == &max8907_out5v_ops) {
- regmap_read(config.regmap, pmic->desc[i].enable_reg,
+ ret = regmap_read(config.regmap, pmic->desc[i].enable_reg,
&val);
+ if (ret)
+ return ret;
+
if ((val & (MAX8907_MASK_OUT5V_VINEN |
MAX8907_MASK_OUT5V_ENSRC)) !=
MAX8907_MASK_OUT5V_ENSRC)
diff --git a/drivers/regulator/qcom_pm8008-regulator.c b/drivers/regulator/qcom_pm8008-regulator.c
index ae7271f..15e0829 100644
--- a/drivers/regulator/qcom_pm8008-regulator.c
+++ b/drivers/regulator/qcom_pm8008-regulator.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2019, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */
#define pr_fmt(fmt) "PM8008: %s: " fmt, __func__
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/interrupt.h>
@@ -24,6 +25,7 @@
#define STARTUP_DELAY_USEC 20
#define VSET_STEP_SIZE_MV 1
#define VSET_STEP_MV 8
+#define VSET_STEP_UV (VSET_STEP_MV * 1000)
#define MISC_BASE 0x900
@@ -187,9 +189,16 @@ static int pm8008_regulator_is_enabled(struct regulator_dev *rdev)
static int pm8008_regulator_enable(struct regulator_dev *rdev)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
- int rc, init_mv, delay_us, delay_ms, retry_count = 10;
+ int rc, rc2, current_uv, delay_us, delay_ms, retry_count = 10;
u8 reg;
+ current_uv = pm8008_regulator_get_voltage(rdev);
+ if (current_uv < 0) {
+ pm8008_err(pm8008_reg, "failed to get current voltage rc=%d\n",
+ current_uv);
+ return current_uv;
+ }
+
rc = regulator_enable(pm8008_reg->en_supply);
if (rc < 0) {
pm8008_err(pm8008_reg,
@@ -198,12 +207,22 @@ static int pm8008_regulator_enable(struct regulator_dev *rdev)
}
if (pm8008_reg->parent_supply) {
+ rc = regulator_set_voltage(pm8008_reg->parent_supply,
+ current_uv + pm8008_reg->min_dropout_uv,
+ INT_MAX);
+ if (rc < 0) {
+ pm8008_err(pm8008_reg, "failed to request parent supply voltage rc=%d\n",
+ rc);
+ goto remove_en;
+ }
+
rc = regulator_enable(pm8008_reg->parent_supply);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to enable parent rc=%d\n", rc);
- regulator_disable(pm8008_reg->en_supply);
- return rc;
+ regulator_set_voltage(pm8008_reg->parent_supply, 0,
+ INT_MAX);
+ goto remove_en;
}
}
@@ -217,20 +236,14 @@ static int pm8008_regulator_enable(struct regulator_dev *rdev)
}
/*
- * wait for VREG_OK
- * Read voltage and calculate the delay.
+ * Wait for the VREG_READY status bit to be set using a timeout delay
+ * calculated from the current commanded voltage.
*/
- init_mv = pm8008_regulator_get_voltage(rdev) / 1000;
- if (init_mv < 0) {
- pm8008_err(pm8008_reg,
- "failed to get regulator voltage rc=%d\n", rc);
- goto out;
- }
delay_us = STARTUP_DELAY_USEC
- + DIV_ROUND_UP(init_mv * 1000, pm8008_reg->step_rate);
+ + DIV_ROUND_UP(current_uv, pm8008_reg->step_rate);
delay_ms = DIV_ROUND_UP(delay_us, 1000);
- /* Retry 10 times for VREG_OK before bailing out */
+ /* Retry 10 times for VREG_READY before bailing out */
while (retry_count--) {
if (delay_ms > 20)
msleep(delay_ms);
@@ -242,7 +255,7 @@ static int pm8008_regulator_enable(struct regulator_dev *rdev)
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to read regulator status rc=%d\n", rc);
- goto out;
+ goto disable_ldo;
}
if (reg & VREG_READY_BIT) {
pm8008_debug(pm8008_reg, "regulator enabled\n");
@@ -250,20 +263,33 @@ static int pm8008_regulator_enable(struct regulator_dev *rdev)
}
}
- pm8008_err(pm8008_reg,
- "failed to enable regulator VREG_READY not set\n");
-out:
+ pm8008_err(pm8008_reg, "failed to enable regulator, VREG_READY not set\n");
+ rc = -ETIME;
+
+disable_ldo:
pm8008_masked_write(pm8008_reg->regmap,
LDO_ENABLE_REG(pm8008_reg->base), ENABLE_BIT, 0);
-remove_vote:
- rc = regulator_disable(pm8008_reg->en_supply);
- if (pm8008_reg->parent_supply)
- rc |= regulator_disable(pm8008_reg->parent_supply);
- if (rc < 0)
- pm8008_err(pm8008_reg,
- "failed to disable parent regulator rc=%d\n", rc);
- return -ETIME;
+remove_vote:
+ if (pm8008_reg->parent_supply) {
+ rc2 = regulator_disable(pm8008_reg->parent_supply);
+ if (rc2 < 0)
+ pm8008_err(pm8008_reg, "failed to disable parent supply rc=%d\n",
+ rc2);
+ rc2 = regulator_set_voltage(pm8008_reg->parent_supply, 0,
+ INT_MAX);
+ if (rc2 < 0)
+ pm8008_err(pm8008_reg, "failed to remove voltage vote for parent supply rc=%d\n",
+ rc2);
+ }
+
+remove_en:
+ rc2 = regulator_disable(pm8008_reg->en_supply);
+ if (rc2 < 0)
+ pm8008_err(pm8008_reg, "failed to disable en_supply rc=%d\n",
+ rc2);
+
+ return rc;
}
static int pm8008_regulator_disable(struct regulator_dev *rdev)
@@ -280,28 +306,29 @@ static int pm8008_regulator_disable(struct regulator_dev *rdev)
return rc;
}
- /* remove vote from chip enable regulator */
- rc = regulator_disable(pm8008_reg->en_supply);
- if (rc < 0) {
- pm8008_err(pm8008_reg,
- "failed to disable en_supply rc=%d\n", rc);
- }
-
/* remove voltage vote from parent regulator */
if (pm8008_reg->parent_supply) {
+ rc = regulator_disable(pm8008_reg->parent_supply);
+ if (rc < 0) {
+ pm8008_err(pm8008_reg, "failed to disable parent rc=%d\n",
+ rc);
+ return rc;
+ }
rc = regulator_set_voltage(pm8008_reg->parent_supply,
0, INT_MAX);
if (rc < 0) {
- pm8008_err(pm8008_reg,
- "failed to remove parent voltage rc=%d\n", rc);
+ pm8008_err(pm8008_reg, "failed to remove parent voltage rc=%d\n",
+ rc);
return rc;
}
- rc = regulator_disable(pm8008_reg->parent_supply);
- if (rc < 0) {
- pm8008_err(pm8008_reg,
- "failed to disable parent rc=%d\n", rc);
- return rc;
- }
+ }
+
+ /* remove vote from chip enable regulator */
+ rc = regulator_disable(pm8008_reg->en_supply);
+ if (rc < 0) {
+ pm8008_err(pm8008_reg, "failed to disable en_supply rc=%d\n",
+ rc);
+ return rc;
}
pm8008_debug(pm8008_reg, "regulator disabled\n");
@@ -341,31 +368,76 @@ static int pm8008_write_voltage(struct pm8008_regulator *pm8008_reg, int min_uv,
return 0;
}
+static int pm8008_regulator_set_voltage_time(struct regulator_dev *rdev,
+ int old_uV, int new_uv)
+{
+ struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
+
+ return DIV_ROUND_UP(abs(new_uv - old_uV), pm8008_reg->step_rate);
+}
+
static int pm8008_regulator_set_voltage(struct regulator_dev *rdev,
int min_uv, int max_uv, unsigned int *selector)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
- int rc = 0;
+ int rc = 0, current_uv = 0, rounded_uv = 0, enabled = 0;
if (pm8008_reg->parent_supply) {
- /* request on parent regulator with headroom */
+ enabled = pm8008_regulator_is_enabled(rdev);
+ if (enabled < 0) {
+ return enabled;
+ } else if (enabled) {
+ current_uv = pm8008_regulator_get_voltage(rdev);
+ if (current_uv < 0)
+ return current_uv;
+ rounded_uv = roundup(min_uv, VSET_STEP_UV);
+ }
+ }
+
+ /*
+ * Set the parent_supply voltage before changing the LDO voltage when
+ * the LDO voltage is being increased.
+ */
+ if (pm8008_reg->parent_supply && enabled && rounded_uv >= current_uv) {
+ /* Request parent voltage with headroom */
rc = regulator_set_voltage(pm8008_reg->parent_supply,
- pm8008_reg->min_dropout_uv + min_uv,
+ rounded_uv + pm8008_reg->min_dropout_uv,
INT_MAX);
if (rc < 0) {
- pm8008_err(pm8008_reg,
- "failed to request parent supply voltage rc=%d\n",
+ pm8008_err(pm8008_reg, "failed to request parent supply voltage rc=%d\n",
rc);
return rc;
}
}
rc = pm8008_write_voltage(pm8008_reg, min_uv, max_uv);
- if (rc < 0) {
- /* remove parent's voltage vote */
- if (pm8008_reg->parent_supply)
- regulator_set_voltage(pm8008_reg->parent_supply,
- 0, INT_MAX);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * Set the parent_supply voltage after changing the LDO voltage when
+ * the LDO voltage is being reduced.
+ */
+ if (pm8008_reg->parent_supply && enabled && rounded_uv < current_uv) {
+ /*
+ * Ensure sufficient time for the LDO voltage to slew down
+ * before reducing the parent supply voltage. The regulator
+ * framework will add the same delay after this function returns
+ * in all cases (i.e. enabled/disabled and increasing/decreasing
+ * voltage).
+ */
+ udelay(pm8008_regulator_set_voltage_time(rdev, rounded_uv,
+ current_uv));
+
+ /* Request parent voltage with headroom */
+ rc = regulator_set_voltage(pm8008_reg->parent_supply,
+ rounded_uv + pm8008_reg->min_dropout_uv,
+ INT_MAX);
+ if (rc < 0) {
+ pm8008_err(pm8008_reg, "failed to request parent supply voltage rc=%d\n",
+ rc);
+ return rc;
+ }
}
pm8008_debug(pm8008_reg, "voltage set to %d\n", min_uv);
@@ -423,14 +495,6 @@ static int pm8008_regulator_set_load(struct regulator_dev *rdev, int load_uA)
return pm8008_regulator_set_mode(rdev, mode);
}
-static int pm8008_regulator_set_voltage_time(struct regulator_dev *rdev,
- int old_uV, int new_uv)
-{
- struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
-
- return DIV_ROUND_UP(abs(new_uv - old_uV), pm8008_reg->step_rate);
-}
-
static struct regulator_ops pm8008_regulator_ops = {
.enable = pm8008_regulator_enable,
.disable = pm8008_regulator_disable,
@@ -506,6 +570,7 @@ static int pm8008_register_ldo(struct pm8008_regulator *pm8008_reg,
struct device_node *reg_node = pm8008_reg->of_node;
char buff[MAX_REG_NAME];
int rc, i, init_voltage;
+ u32 base = 0;
u8 reg;
/* get regulator data */
@@ -518,11 +583,12 @@ static int pm8008_register_ldo(struct pm8008_regulator *pm8008_reg,
return -EINVAL;
}
- rc = of_property_read_u16(reg_node, "reg", &pm8008_reg->base);
+ rc = of_property_read_u32(reg_node, "reg", &base);
if (rc < 0) {
pr_err("%s: failed to get regulator base rc=%d\n", name, rc);
return rc;
}
+ pm8008_reg->base = base;
pm8008_reg->min_dropout_uv = reg_data[i].min_dropout_uv;
of_property_read_u32(reg_node, "qcom,min-dropout-voltage",
@@ -709,7 +775,7 @@ static int pm8008_regulator_probe(struct platform_device *pdev)
/* PM8008 chip enable regulator callbacks */
static int pm8008_enable_regulator_enable(struct regulator_dev *rdev)
{
- struct pm8008_regulator *chip = rdev_get_drvdata(rdev);
+ struct pm8008_chip *chip = rdev_get_drvdata(rdev);
int rc;
rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG,
@@ -725,7 +791,7 @@ static int pm8008_enable_regulator_enable(struct regulator_dev *rdev)
static int pm8008_enable_regulator_disable(struct regulator_dev *rdev)
{
- struct pm8008_regulator *chip = rdev_get_drvdata(rdev);
+ struct pm8008_chip *chip = rdev_get_drvdata(rdev);
int rc;
rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG,
@@ -741,7 +807,7 @@ static int pm8008_enable_regulator_disable(struct regulator_dev *rdev)
static int pm8008_enable_regulator_is_enabled(struct regulator_dev *rdev)
{
- struct pm8008_regulator *chip = rdev_get_drvdata(rdev);
+ struct pm8008_chip *chip = rdev_get_drvdata(rdev);
int rc;
u8 reg;
diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c
index 790a4a7..40b7464 100644
--- a/drivers/regulator/rn5t618-regulator.c
+++ b/drivers/regulator/rn5t618-regulator.c
@@ -154,6 +154,7 @@ static struct platform_driver rn5t618_regulator_driver = {
module_platform_driver(rn5t618_regulator_driver);
+MODULE_ALIAS("platform:rn5t618-regulator");
MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
MODULE_DESCRIPTION("RN5T618 regulator driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index f89f9d0..a2e34c8 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1135,7 +1135,8 @@ static u32 get_fcx_max_data(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
int fcx_in_css, fcx_in_gneq, fcx_in_features;
- int tpm, mdc;
+ unsigned int mdc;
+ int tpm;
if (dasd_nofcx)
return 0;
@@ -1149,7 +1150,7 @@ static u32 get_fcx_max_data(struct dasd_device *device)
return 0;
mdc = ccw_device_get_mdc(device->cdev, 0);
- if (mdc < 0) {
+ if (mdc == 0) {
dev_warn(&device->cdev->dev, "Detecting the maximum supported data size for zHPF requests failed\n");
return 0;
} else {
@@ -1160,12 +1161,12 @@ static u32 get_fcx_max_data(struct dasd_device *device)
static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm)
{
struct dasd_eckd_private *private = device->private;
- int mdc;
+ unsigned int mdc;
u32 fcx_max_data;
if (private->fcx_max_data) {
mdc = ccw_device_get_mdc(device->cdev, lpm);
- if ((mdc < 0)) {
+ if (mdc == 0) {
dev_warn(&device->cdev->dev,
"Detecting the maximum data size for zHPF "
"requests failed (rc=%d) for a new path %x\n",
@@ -1769,7 +1770,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
dasd_free_block(device->block);
device->block = NULL;
out_err1:
- kfree(private->conf_data);
+ dasd_eckd_clear_conf_data(device);
kfree(device->private);
device->private = NULL;
return rc;
@@ -1778,7 +1779,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
static void dasd_eckd_uncheck_device(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
- int i;
if (!private)
return;
@@ -1788,21 +1788,7 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device)
private->sneq = NULL;
private->vdsneq = NULL;
private->gneq = NULL;
- private->conf_len = 0;
- for (i = 0; i < 8; i++) {
- kfree(device->path[i].conf_data);
- if ((__u8 *)device->path[i].conf_data ==
- private->conf_data) {
- private->conf_data = NULL;
- private->conf_len = 0;
- }
- device->path[i].conf_data = NULL;
- device->path[i].cssid = 0;
- device->path[i].ssid = 0;
- device->path[i].chpid = 0;
- }
- kfree(private->conf_data);
- private->conf_data = NULL;
+ dasd_eckd_clear_conf_data(device);
}
static struct dasd_ccw_req *
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 4435ae0..f0cae19 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -624,7 +624,7 @@ EXPORT_SYMBOL(ccw_device_tm_start_timeout);
* @mask: mask of paths to use
*
* Return the number of 64K-bytes blocks all paths at least support
- * for a transport command. Return values <= 0 indicate failures.
+ * for a transport command. Return value 0 indicates failure.
*/
int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
{
diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h
index 2e1a27b..2126f4c 100644
--- a/drivers/s390/crypto/zcrypt_error.h
+++ b/drivers/s390/crypto/zcrypt_error.h
@@ -62,6 +62,7 @@ struct error_hdr {
#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
#define REP82_ERROR_RESERVED_FIELD 0x88
#define REP82_ERROR_INVALID_DOMAIN_PENDING 0x8A
+#define REP82_ERROR_FILTERED_BY_HYPERVISOR 0x8B
#define REP82_ERROR_TRANSPORT_FAIL 0x90
#define REP82_ERROR_PACKET_TRUNCATED 0xA0
#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0
@@ -92,6 +93,7 @@ static inline int convert_error(struct zcrypt_queue *zq,
case REP82_ERROR_INVALID_DOMAIN_PRECHECK:
case REP82_ERROR_INVALID_DOMAIN_PENDING:
case REP82_ERROR_INVALID_SPECIAL_CMD:
+ case REP82_ERROR_FILTERED_BY_HYPERVISOR:
// REP88_ERROR_INVALID_KEY // '82' CEX2A
// REP88_ERROR_OPERAND // '84' CEX2A
// REP88_ERROR_OPERAND_EVEN_MOD // '85' CEX2A
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 8ec68dc..95a3e3b 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -129,6 +129,9 @@
#define NCR5380_release_dma_irq(x)
#endif
+static unsigned int disconnect_mask = ~0;
+module_param(disconnect_mask, int, 0444);
+
static int do_abort(struct Scsi_Host *);
static void do_reset(struct Scsi_Host *);
static void bus_reset_cleanup(struct Scsi_Host *);
@@ -946,7 +949,8 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
int err;
bool ret = true;
bool can_disconnect = instance->irq != NO_IRQ &&
- cmd->cmnd[0] != REQUEST_SENSE;
+ cmd->cmnd[0] != REQUEST_SENSE &&
+ (disconnect_mask & BIT(scmd_id(cmd)));
NCR5380_dprint(NDEBUG_ARBITRATION, instance);
dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n",
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 89f5154..764c46d7 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -742,7 +742,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
atari_scsi_template.sg_tablesize = SG_ALL;
} else {
atari_scsi_template.can_queue = 1;
- atari_scsi_template.sg_tablesize = SG_NONE;
+ atari_scsi_template.sg_tablesize = 1;
}
if (setup_can_queue > 0)
@@ -751,8 +751,8 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
if (setup_cmd_per_lun > 0)
atari_scsi_template.cmd_per_lun = setup_cmd_per_lun;
- /* Leave sg_tablesize at 0 on a Falcon! */
- if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
+ /* Don't increase sg_tablesize on Falcon! */
+ if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize > 0)
atari_scsi_template.sg_tablesize = setup_sg_tablesize;
if (setup_hostid >= 0) {
diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c
index cc5611e..a8e29e3 100644
--- a/drivers/scsi/csiostor/csio_lnode.c
+++ b/drivers/scsi/csiostor/csio_lnode.c
@@ -301,6 +301,7 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
struct fc_fdmi_port_name *port_name;
uint8_t buf[64];
uint8_t *fc4_type;
+ unsigned long flags;
if (fdmi_req->wr_status != FW_SUCCESS) {
csio_ln_dbg(ln, "WR error:%x in processing fdmi rhba cmd\n",
@@ -385,13 +386,13 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
len = (uint32_t)(pld - (uint8_t *)cmd);
/* Submit FDMI RPA request */
- spin_lock_irq(&hw->lock);
+ spin_lock_irqsave(&hw->lock, flags);
if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_done,
FCOE_CT, &fdmi_req->dma_buf, len)) {
CSIO_INC_STATS(ln, n_fdmi_err);
csio_ln_dbg(ln, "Failed to issue fdmi rpa req\n");
}
- spin_unlock_irq(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
}
/*
@@ -412,6 +413,7 @@ csio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
struct fc_fdmi_rpl *reg_pl;
struct fs_fdmi_attrs *attrib_blk;
uint8_t buf[64];
+ unsigned long flags;
if (fdmi_req->wr_status != FW_SUCCESS) {
csio_ln_dbg(ln, "WR error:%x in processing fdmi dprt cmd\n",
@@ -491,13 +493,13 @@ csio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
attrib_blk->numattrs = htonl(numattrs);
/* Submit FDMI RHBA request */
- spin_lock_irq(&hw->lock);
+ spin_lock_irqsave(&hw->lock, flags);
if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_rhba_cbfn,
FCOE_CT, &fdmi_req->dma_buf, len)) {
CSIO_INC_STATS(ln, n_fdmi_err);
csio_ln_dbg(ln, "Failed to issue fdmi rhba req\n");
}
- spin_unlock_irq(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
}
/*
@@ -512,6 +514,7 @@ csio_ln_fdmi_dhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
void *cmd;
struct fc_fdmi_port_name *port_name;
uint32_t len;
+ unsigned long flags;
if (fdmi_req->wr_status != FW_SUCCESS) {
csio_ln_dbg(ln, "WR error:%x in processing fdmi dhba cmd\n",
@@ -542,13 +545,13 @@ csio_ln_fdmi_dhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
len += sizeof(*port_name);
/* Submit FDMI request */
- spin_lock_irq(&hw->lock);
+ spin_lock_irqsave(&hw->lock, flags);
if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_dprt_cbfn,
FCOE_CT, &fdmi_req->dma_buf, len)) {
CSIO_INC_STATS(ln, n_fdmi_err);
csio_ln_dbg(ln, "Failed to issue fdmi dprt req\n");
}
- spin_unlock_irq(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
}
/**
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index f35c562..3319167 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -485,7 +485,13 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
struct hisi_sas_dq *dq = NULL;
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) {
- if (in_softirq())
+ /*
+ * For IOs from upper layer, it may already disable preempt
+ * in the IO path, if disable preempt again in down(),
+ * function schedule() will report schedule_bug(), so check
+ * preemptible() before goto down().
+ */
+ if (!preemptible())
return -EINVAL;
down(&hisi_hba->sem);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 23354f2..55181d2 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -374,8 +374,16 @@ static int iscsi_sw_tcp_pdu_xmit(struct iscsi_task *task)
{
struct iscsi_conn *conn = task->conn;
unsigned int noreclaim_flag;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
int rc = 0;
+ if (!tcp_sw_conn->sock) {
+ iscsi_conn_printk(KERN_ERR, conn,
+ "Transport not bound to socket!\n");
+ return -EINVAL;
+ }
+
noreclaim_flag = memalloc_noreclaim_save();
while (iscsi_sw_tcp_xmit_qlen(conn)) {
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 0148ae62..e320534 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -97,12 +97,21 @@ static int sas_get_port_device(struct asd_sas_port *port)
else
dev->dev_type = SAS_SATA_DEV;
dev->tproto = SAS_PROTOCOL_SATA;
- } else {
+ } else if (port->oob_mode == SAS_OOB_MODE) {
struct sas_identify_frame *id =
(struct sas_identify_frame *) dev->frame_rcvd;
dev->dev_type = id->dev_type;
dev->iproto = id->initiator_bits;
dev->tproto = id->target_bits;
+ } else {
+ /* If the oob mode is OOB_NOT_CONNECTED, the port is
+ * disconnected due to race with PHY down. We cannot
+ * continue to discover this port
+ */
+ sas_put_device(dev);
+ pr_warn("Port %016llx is disconnected when discovering\n",
+ SAS_ADDR(port->attached_sas_addr));
+ return -ENODEV;
}
sas_init_dev(dev);
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 99aea52..21f104c 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -4419,12 +4419,6 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job,
phba->mbox_ext_buf_ctx.seqNum++;
nemb_tp = phba->mbox_ext_buf_ctx.nembType;
- dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
- if (!dd_data) {
- rc = -ENOMEM;
- goto job_error;
- }
-
pbuf = (uint8_t *)dmabuf->virt;
size = job->request_payload.payload_len;
sg_copy_to_buffer(job->request_payload.sg_list,
@@ -4461,6 +4455,13 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job,
"2968 SLI_CONFIG ext-buffer wr all %d "
"ebuffers received\n",
phba->mbox_ext_buf_ctx.numBuf);
+
+ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+ if (!dd_data) {
+ rc = -ENOMEM;
+ goto job_error;
+ }
+
/* mailbox command structure for base driver */
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmboxq) {
@@ -4509,6 +4510,8 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job,
return SLI_CONFIG_HANDLED;
job_error:
+ if (pmboxq)
+ mempool_free(pmboxq, phba->mbox_mem_pool);
lpfc_bsg_dma_page_free(phba, dmabuf);
kfree(dd_data);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 4f4d1b3..7398350 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -4110,7 +4110,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
mempool_free(mbox, phba->mbox_mem_pool);
}
out:
- if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
+ if (ndlp && NLP_CHK_NODE_ACT(ndlp) && shost) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
spin_unlock_irq(shost->host_lock);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index b36b3da..5d65717 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -5231,9 +5231,14 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
/* If we've already received a PLOGI from this NPort
* we don't need to try to discover it again.
*/
- if (ndlp->nlp_flag & NLP_RCV_PLOGI)
+ if (ndlp->nlp_flag & NLP_RCV_PLOGI &&
+ !(ndlp->nlp_type &
+ (NLP_FCP_TARGET | NLP_NVME_TARGET)))
return NULL;
+ ndlp->nlp_prev_state = ndlp->nlp_state;
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
spin_unlock_irq(shost->host_lock);
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index bd8dc6a..3dfed19 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -483,8 +483,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
* single discovery thread, this will cause a huge delay in
* discovery. Also this will cause multiple state machines
* running in parallel for this node.
+ * This only applies to a fabric environment.
*/
- if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
+ if ((ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) &&
+ (vport->fc_flag & FC_FABRIC)) {
/* software abort outstanding PLOGI */
lpfc_els_abort(phba, ndlp);
}
diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
index f73726e55..6c355d8 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.c
+++ b/drivers/scsi/lpfc/lpfc_nvme.c
@@ -1903,6 +1903,8 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
/* Declare and initialization an instance of the FC NVME template. */
static struct nvme_fc_port_template lpfc_nvme_template = {
+ .module = THIS_MODULE,
+
/* initiator-based functions */
.localport_delete = lpfc_nvme_localport_delete,
.remoteport_delete = lpfc_nvme_remoteport_delete,
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index f459fd6..a801917 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -12928,13 +12928,19 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe)
phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
/* Setting active mailbox pointer need to be in sync to flag clear */
phba->sli.mbox_active = NULL;
+ if (bf_get(lpfc_trailer_consumed, mcqe))
+ lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
spin_unlock_irqrestore(&phba->hbalock, iflags);
/* Wake up worker thread to post the next pending mailbox command */
lpfc_worker_wake_up(phba);
+ return workposted;
+
out_no_mqe_complete:
+ spin_lock_irqsave(&phba->hbalock, iflags);
if (bf_get(lpfc_trailer_consumed, mcqe))
lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
- return workposted;
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return false;
}
/**
@@ -17861,6 +17867,13 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
static void
__lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
{
+ /*
+ * if the rpi value indicates a prior unreg has already
+ * been done, skip the unreg.
+ */
+ if (rpi == LPFC_RPI_ALLOC_ERROR)
+ return;
+
if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) {
phba->sli4_hba.rpi_count--;
phba->sli4_hba.max_cfg_param.rpi_used--;
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 643321f..b5050c2 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -429,7 +429,7 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
mac_scsi_template.can_queue = setup_can_queue;
if (setup_cmd_per_lun > 0)
mac_scsi_template.cmd_per_lun = setup_cmd_per_lun;
- if (setup_sg_tablesize >= 0)
+ if (setup_sg_tablesize > 0)
mac_scsi_template.sg_tablesize = setup_sg_tablesize;
if (setup_hostid >= 0)
mac_scsi_template.this_id = setup_hostid & 7;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index 5e8c059..0734501 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -1597,7 +1597,8 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
" for diag buffers, requested size(%d)\n",
ioc->name, __func__, request_data_sz);
mpt3sas_base_free_smid(ioc, smid);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto out;
}
ioc->diag_buffer[buffer_type] = request_data;
ioc->diag_buffer_sz[buffer_type] = request_data_sz;
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 5021aed..8627feb 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -2382,6 +2382,8 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
pm8001_printk("task 0x%p done with io_status 0x%x"
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, status, ts->resp, ts->stat));
+ if (t->slow_task)
+ complete(&t->slow_task->completion);
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
} else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
diff --git a/drivers/scsi/qedf/qedf_els.c b/drivers/scsi/qedf/qedf_els.c
index 04f0c4d..5178cd0 100644
--- a/drivers/scsi/qedf/qedf_els.c
+++ b/drivers/scsi/qedf/qedf_els.c
@@ -23,8 +23,6 @@ static int qedf_initiate_els(struct qedf_rport *fcport, unsigned int op,
int rc = 0;
uint32_t did, sid;
uint16_t xid;
- uint32_t start_time = jiffies / HZ;
- uint32_t current_time;
struct fcoe_wqe *sqe;
unsigned long flags;
u16 sqe_idx;
@@ -59,18 +57,12 @@ static int qedf_initiate_els(struct qedf_rport *fcport, unsigned int op,
goto els_err;
}
-retry_els:
els_req = qedf_alloc_cmd(fcport, QEDF_ELS);
if (!els_req) {
- current_time = jiffies / HZ;
- if ((current_time - start_time) > 10) {
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS,
- "els: Failed els 0x%x\n", op);
- rc = -ENOMEM;
- goto els_err;
- }
- mdelay(20 * USEC_PER_MSEC);
- goto retry_els;
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_ELS,
+ "Failed to alloc ELS request 0x%x\n", op);
+ rc = -ENOMEM;
+ goto els_err;
}
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "initiate_els els_req = "
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 4512aaa..851f75b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -4815,14 +4815,8 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
set_bit(RSCN_UPDATE, &flags);
clear_bit(LOCAL_LOOP_UPDATE, &flags);
- } else if (ha->current_topology == ISP_CFG_N) {
- clear_bit(RSCN_UPDATE, &flags);
- if (qla_tgt_mode_enabled(vha)) {
- /* allow the other side to start the login */
- clear_bit(LOCAL_LOOP_UPDATE, &flags);
- set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
- }
- } else if (ha->current_topology == ISP_CFG_NL) {
+ } else if (ha->current_topology == ISP_CFG_NL ||
+ ha->current_topology == ISP_CFG_N) {
clear_bit(RSCN_UPDATE, &flags);
set_bit(LOCAL_LOOP_UPDATE, &flags);
} else if (!vha->flags.online ||
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c699bbb..7e47321 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2537,7 +2537,8 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073,
"PLOGI ELS IOCB:\n");
ql_dump_buffer(ql_log_info, vha, 0x0109,
- (uint8_t *)els_iocb, 0x70);
+ (uint8_t *)els_iocb,
+ sizeof(*els_iocb));
} else {
els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
els_iocb->tx_address[0] =
@@ -2703,7 +2704,8 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x3073, "PLOGI buffer:\n");
ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x0109,
- (uint8_t *)elsio->u.els_plogi.els_plogi_pyld, 0x70);
+ (uint8_t *)elsio->u.els_plogi.els_plogi_pyld,
+ sizeof(*elsio->u.els_plogi.els_plogi_pyld));
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS) {
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index afe15b3..e6d1629 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1049,8 +1049,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
ql_dbg(ql_dbg_async, vha, 0x5011,
"Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
mb[1], mb[2], mb[3]);
-
- qlt_async_event(mb[0], vha, mb);
break;
}
@@ -1067,8 +1065,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
set_bit(VP_CONFIG_OK, &vha->vp_flags);
-
- qlt_async_event(mb[0], vha, mb);
break;
case MBA_RSCN_UPDATE: /* State Change Registration */
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index b01f69d..abef3b2 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3871,6 +3871,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
vha->d_id.b24 = 0;
vha->d_id.b.al_pa = 1;
ha->flags.n2n_bigger = 1;
+ ha->flags.n2n_ae = 0;
id.b.al_pa = 2;
ql_dbg(ql_dbg_async, vha, 0x5075,
@@ -3881,6 +3882,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
"Format 1: Remote login - Waiting for WWPN %8phC.\n",
rptid_entry->u.f1.port_name);
ha->flags.n2n_bigger = 0;
+ ha->flags.n2n_ae = 1;
}
qla24xx_post_newsess_work(vha, &id,
rptid_entry->u.f1.port_name,
@@ -3892,7 +3894,6 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
/* if our portname is higher then initiate N2N login */
set_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags);
- ha->flags.n2n_ae = 1;
return;
break;
case TOPO_FL:
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 5590d6e..db367e4 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -560,6 +560,7 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
}
static struct nvme_fc_port_template qla_nvme_fc_transport = {
+ .module = THIS_MODULE,
.localport_delete = qla_nvme_localport_delete,
.remoteport_delete = qla_nvme_remoteport_delete,
.create_queue = qla_nvme_alloc_queue,
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 210ce29..e954541 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -1261,7 +1261,6 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
"Scheduling sess %p for deletion %8phC\n",
sess, sess->port_name);
- INIT_WORK(&sess->del_work, qla24xx_delete_sess_fn);
WARN_ON(!queue_work(sess->vha->hw->wq, &sess->del_work));
}
@@ -4780,6 +4779,7 @@ static int qlt_handle_login(struct scsi_qla_host *vha,
switch (sess->disc_state) {
case DSC_DELETED:
+ case DSC_LOGIN_PEND:
qlt_plogi_ack_unref(vha, pla);
break;
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 25c8ce5..f8acf10 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -4280,7 +4280,6 @@ static int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
return QLA_SUCCESS;
mem_alloc_error_exit:
- qla4xxx_mem_free(ha);
return QLA_ERROR;
}
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 65305b3..a1dbae8 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -5351,6 +5351,11 @@ static int __init scsi_debug_init(void)
return -EINVAL;
}
+ if (sdebug_num_tgts < 0) {
+ pr_err("num_tgts must be >= 0\n");
+ return -EINVAL;
+ }
+
if (sdebug_guard > 1) {
pr_err("guard must be 0 or 1\n");
return -EINVAL;
diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c
index 0ff083b..617a607 100644
--- a/drivers/scsi/scsi_trace.c
+++ b/drivers/scsi/scsi_trace.c
@@ -30,15 +30,18 @@ static const char *
scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
{
const char *ret = trace_seq_buffer_ptr(p);
- sector_t lba = 0, txlen = 0;
+ u32 lba = 0, txlen;
lba |= ((cdb[1] & 0x1F) << 16);
lba |= (cdb[2] << 8);
lba |= cdb[3];
- txlen = cdb[4];
+ /*
+ * From SBC-2: a TRANSFER LENGTH field set to zero specifies that 256
+ * logical blocks shall be read (READ(6)) or written (WRITE(6)).
+ */
+ txlen = cdb[4] ? cdb[4] : 256;
- trace_seq_printf(p, "lba=%llu txlen=%llu",
- (unsigned long long)lba, (unsigned long long)txlen);
+ trace_seq_printf(p, "lba=%u txlen=%u", lba, txlen);
trace_seq_putc(p, 0);
return ret;
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 9492638..af8a7ef 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -498,7 +498,7 @@ static struct scsi_host_template sun3_scsi_template = {
.eh_host_reset_handler = sun3scsi_host_reset,
.can_queue = 16,
.this_id = 7,
- .sg_tablesize = SG_NONE,
+ .sg_tablesize = 1,
.cmd_per_lun = 2,
.use_clustering = DISABLE_CLUSTERING,
.cmd_size = NCR5380_CMD_SIZE,
@@ -520,7 +520,7 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
sun3_scsi_template.can_queue = setup_can_queue;
if (setup_cmd_per_lun > 0)
sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
- if (setup_sg_tablesize >= 0)
+ if (setup_sg_tablesize > 0)
sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
if (setup_hostid >= 0)
sun3_scsi_template.this_id = setup_hostid & 7;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3e86261..445cbec 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4383,10 +4383,10 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
goto out_unlock;
}
- hba->dev_cmd.query.descriptor = NULL;
*buf_len = be16_to_cpu(response->upiu_res.length);
out_unlock:
+ hba->dev_cmd.query.descriptor = NULL;
mutex_unlock(&hba->dev_cmd.lock);
out:
ufshcd_release_all(hba);
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 72efa39..9b1bfc0 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -273,7 +273,7 @@ static int dsp_domr_notify_cb(struct notifier_block *n, unsigned long code,
break;
case SUBSYS_AFTER_POWERUP:
case SERVREG_NOTIF_SERVICE_STATE_UP_V01:
- SLIM_INFO(dev, "SLIM DSP SSR notify cb:%lu\n", code);
+ SLIM_INFO(dev, "SLIM DSP SSR notify cb:0x%x\n", code);
/* Hold wake lock until notify slaves thread is done */
pm_stay_awake(dev->dev);
atomic_set(&dev->init_in_progress, 1);
@@ -303,9 +303,21 @@ static int dsp_domr_notify_cb(struct notifier_block *n, unsigned long code,
&cur);
SLIM_INFO(dev, "reg-PD client:%s with service:%s\n",
reg->client_name, reg->service_name);
- SLIM_INFO(dev, "reg-PD dom:%s instance:%d, cur:%d\n",
+ SLIM_INFO(dev, "reg-PD dom:%s instance:%d, cur:0x%x\n",
reg->domain_list->name,
reg->domain_list->instance_id, cur);
+
+ if (cur == SERVREG_NOTIF_SERVICE_STATE_UP_V01) {
+ pm_stay_awake(dev->dev);
+ atomic_set(&dev->init_in_progress, 1);
+ if (dev->lpass_mem_usage) {
+ dev->lpass_mem->start = dev->lpass_phy_base;
+ dev->lpass.base = dev->lpass_virt_base;
+ }
+ atomic_set(&dev->ssr_in_progress, 0);
+ schedule_work(&dev->dsp.dom_up);
+ }
+
if (IS_ERR_OR_NULL(dev->dsp.domr))
ngd_reg_ssr(dev);
else
diff --git a/drivers/soc/qcom/fsa4480-i2c.c b/drivers/soc/qcom/fsa4480-i2c.c
index 707d249..2fc871c 100644
--- a/drivers/soc/qcom/fsa4480-i2c.c
+++ b/drivers/soc/qcom/fsa4480-i2c.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
@@ -228,8 +228,11 @@ EXPORT_SYMBOL(fsa4480_reg_notifier);
int fsa4480_unreg_notifier(struct notifier_block *nb,
struct device_node *node)
{
+ int rc = 0;
struct i2c_client *client = of_find_i2c_device_by_node(node);
struct fsa4480_priv *fsa_priv;
+ struct device *dev;
+ union power_supply_propval mode;
if (!client)
return -EINVAL;
@@ -237,10 +240,27 @@ int fsa4480_unreg_notifier(struct notifier_block *nb,
fsa_priv = (struct fsa4480_priv *)i2c_get_clientdata(client);
if (!fsa_priv)
return -EINVAL;
+ dev = fsa_priv->dev;
+ if (!dev)
+ return -EINVAL;
- fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98);
- return blocking_notifier_chain_unregister
+ mutex_lock(&fsa_priv->notification_lock);
+ /* get latest mode within locked context */
+ rc = power_supply_get_property(fsa_priv->usb_psy,
+ POWER_SUPPLY_PROP_TYPEC_MODE, &mode);
+ if (rc) {
+ dev_dbg(dev, "%s: Unable to read USB TYPEC_MODE: %d\n",
+ __func__, rc);
+ goto done;
+ }
+ /* Do not reset switch settings for usb digital hs */
+ if (mode.intval != POWER_SUPPLY_TYPEC_SINK)
+ fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98);
+ rc = blocking_notifier_chain_unregister
(&fsa_priv->fsa4480_notifier, nb);
+done:
+ mutex_unlock(&fsa_priv->notification_lock);
+ return rc;
}
EXPORT_SYMBOL(fsa4480_unreg_notifier);
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index a889bb2..b9205f4 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "icnss: " fmt
@@ -1398,7 +1398,8 @@ static void icnss_update_state_send_modem_shutdown(struct icnss_priv *priv,
if (atomic_read(&priv->is_shutdown)) {
atomic_set(&priv->is_shutdown, false);
if (!test_bit(ICNSS_PD_RESTART, &priv->state) &&
- !test_bit(ICNSS_SHUTDOWN_DONE, &priv->state)) {
+ !test_bit(ICNSS_SHUTDOWN_DONE, &priv->state) &&
+ !test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) {
icnss_call_driver_remove(priv);
}
}
diff --git a/drivers/soc/qcom/l2_reuse.c b/drivers/soc/qcom/l2_reuse.c
index 622e914..e20b49a 100644
--- a/drivers/soc/qcom/l2_reuse.c
+++ b/drivers/soc/qcom/l2_reuse.c
@@ -11,7 +11,7 @@
#include <linux/sysfs.h>
#include <linux/kobject.h>
-#define L2_REUSE_SMC_ID 0x02001F01
+#define L2_REUSE_SMC_ID 0x00200090C
static bool l2_reuse_enable = true;
static struct kobject *l2_reuse_kobj;
diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c
index e9f986b..4e20ba8 100644
--- a/drivers/soc/qcom/qmi_rmnet.c
+++ b/drivers/soc/qcom/qmi_rmnet.c
@@ -808,11 +808,11 @@ static int qmi_rmnet_get_queue_sa(struct qos_info *qos, struct sk_buff *skb)
int ip_type;
int txq = DEFAULT_MQ_NUM;
- /* Put RS/NS in default mq */
+ /* Put NDP in default mq */
if (skb->protocol == htons(ETH_P_IPV6) &&
ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6 &&
- (icmp6_hdr(skb)->icmp6_type == 133 ||
- icmp6_hdr(skb)->icmp6_type == 135)) {
+ icmp6_hdr(skb)->icmp6_type >= 133 &&
+ icmp6_hdr(skb)->icmp6_type <= 137) {
return DEFAULT_MQ_NUM;
}
diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index 4b477cb..6d63e7d 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -1,9 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
-
#ifndef __RPM_INTERNAL_H__
#define __RPM_INTERNAL_H__
@@ -124,5 +123,5 @@ void rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable);
void rpmh_tx_done(const struct tcs_request *msg, int r);
-void rpmh_rsc_debug(struct rsc_drv *drv);
+void rpmh_rsc_debug(struct rsc_drv *drv, struct completion *compl);
#endif /* __RPM_INTERNAL_H__ */
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 7537d18..ceedbff 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "%s " fmt, KBUILD_MODNAME
@@ -692,7 +692,7 @@ static void print_tcs_info(struct rsc_drv *drv, int tcs_id, unsigned long *accl)
}
}
-void rpmh_rsc_debug(struct rsc_drv *drv)
+void rpmh_rsc_debug(struct rsc_drv *drv, struct completion *compl)
{
struct irq_data *rsc_irq_data = irq_get_irq_data(drv->irq);
bool irq_sts;
@@ -718,6 +718,8 @@ void rpmh_rsc_debug(struct rsc_drv *drv)
irq_get_irqchip_state(drv->irq, IRQCHIP_STATE_PENDING, &irq_sts);
pr_warn("HW IRQ %lu is %s at GIC\n", rsc_irq_data->hwirq,
irq_sts ? "PENDING" : "NOT PENDING");
+ pr_warn("Completion is %s to finish\n",
+ completion_done(compl) ? "PENDING" : "NOT PENDING");
for_each_set_bit(i, &accl, ARRAY_SIZE(accl_str)) {
strlcat(str, accl_str[i], sizeof(str));
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 82691f7..bda109f 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/atomic.h>
@@ -336,7 +336,7 @@ int rpmh_write(const struct device *dev, enum rpmh_state state,
ret = wait_for_completion_timeout(&compl, RPMH_TIMEOUT_MS);
if (!ret) {
- rpmh_rsc_debug(ctrlr_to_drv(ctrlr));
+ rpmh_rsc_debug(ctrlr_to_drv(ctrlr), &compl);
return -ETIMEDOUT;
}
@@ -477,7 +477,7 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
* the completion that we're going to free once
* we've returned from this function.
*/
- rpmh_rsc_debug(ctrlr_to_drv(ctrlr));
+ rpmh_rsc_debug(ctrlr_to_drv(ctrlr), &compls[i]);
ret = -ETIMEDOUT;
goto exit;
}
diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c
index 3d9d379..77e2503 100644
--- a/drivers/soc/qcom/smcinvoke.c
+++ b/drivers/soc/qcom/smcinvoke.c
@@ -827,9 +827,17 @@ static void process_kernel_obj(void *buf, size_t buf_len)
{
struct smcinvoke_tzcb_req *cb_req = buf;
- cb_req->result = (cb_req->hdr.op == OBJECT_OP_MAP_REGION) ?
- smcinvoke_map_mem_region(buf, buf_len) :
- OBJECT_ERROR_INVALID;
+ switch (cb_req->hdr.op) {
+ case OBJECT_OP_MAP_REGION:
+ cb_req->result = smcinvoke_map_mem_region(buf, buf_len);
+ break;
+ case OBJECT_OP_YIELD:
+ cb_req->result = OBJECT_OK;
+ break;
+ default:
+ cb_req->result = OBJECT_ERROR_INVALID;
+ break;
+ }
}
static void process_mem_obj(void *buf, size_t buf_len)
diff --git a/drivers/soc/qcom/smcinvoke_object.h b/drivers/soc/qcom/smcinvoke_object.h
index 175a794..09972e4 100644
--- a/drivers/soc/qcom/smcinvoke_object.h
+++ b/drivers/soc/qcom/smcinvoke_object.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#ifndef __SMCINVOKE_OBJECT_H
#define __SMCINVOKE_OBJECT_H
@@ -16,6 +16,7 @@
#define OBJECT_OP_RELEASE (OBJECT_OP_METHOD_MASK - 0)
#define OBJECT_OP_RETAIN (OBJECT_OP_METHOD_MASK - 1)
#define OBJECT_OP_MAP_REGION 0
+#define OBJECT_OP_YIELD 1
#define OBJECT_COUNTS_MAX_BI 0xF
#define OBJECT_COUNTS_MAX_BO 0xF
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index d24eb7c..8a9d08f 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -73,23 +73,23 @@
} while (0)
#define spcom_pr_err(_fmt, ...) do { \
- pr_err(_fmt); \
+ pr_err(_fmt, ##__VA_ARGS__); \
spcom_ipc_log_string("%s" pr_fmt(_fmt), "", ##__VA_ARGS__); \
} while (0)
#define spcom_pr_warn(_fmt, ...) do { \
- pr_warn(_fmt); \
+ pr_warn(_fmt, ##__VA_ARGS__); \
spcom_ipc_log_string("%s" pr_fmt(_fmt), "", ##__VA_ARGS__); \
} while (0)
#define spcom_pr_info(_fmt, ...) do { \
- pr_info(_fmt); \
+ pr_info(_fmt, ##__VA_ARGS__); \
spcom_ipc_log_string("%s" pr_fmt(_fmt), "", ##__VA_ARGS__); \
} while (0)
#if defined(DEBUG)
#define spcom_pr_dbg(_fmt, ...) do { \
- pr_debug(_fmt); \
+ pr_debug(_fmt, ##__VA_ARGS__); \
spcom_ipc_log_string("%s" pr_fmt(_fmt), "", ##__VA_ARGS__); \
} while (0)
#else
diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c
index 5eabb2b..e3ab1c4 100644
--- a/drivers/soc/qcom/spss_utils.c
+++ b/drivers/soc/qcom/spss_utils.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
/*
@@ -33,6 +33,7 @@
#include <linux/notifier.h>
#include <linux/sizes.h> /* SZ_4K */
#include <linux/uaccess.h> /* copy_from_user() */
+#include <linux/completion.h> /* wait_for_completion_timeout() */
#include <soc/qcom/subsystem_notif.h>
#include <soc/qcom/subsystem_restart.h>
@@ -91,6 +92,13 @@ static phys_addr_t cmac_mem_addr;
#define SPU_EMULATUION (BIT(0) | BIT(1))
#define SPU_PRESENT_IN_EMULATION BIT(2)
+/* Events notification */
+static struct completion spss_events[SPSS_NUM_EVENTS];
+static bool spss_events_signaled[SPSS_NUM_EVENTS];
+
+/* Protect from ioctl signal func called by multiple-proc at the same time */
+static struct mutex event_lock;
+
/**
* struct device state
*/
@@ -376,15 +384,119 @@ static int spss_create_sysfs(struct device *dev)
/*==========================================================================*/
/* IOCTL */
/*==========================================================================*/
+static int spss_wait_for_event(struct spss_ioc_wait_for_event *req)
+{
+ int ret;
+ uint32_t event_id;
+ uint32_t timeout_sec;
+ long timeleft = 1;
+
+ event_id = req->event_id;
+ timeout_sec = req->timeout_sec;
+
+ if (event_id >= SPSS_NUM_EVENTS) {
+ pr_err("event_id [%d] invalid\n", event_id);
+ return -EINVAL;
+ }
+
+ pr_debug("wait for event [%d], timeout_sec [%d]\n",
+ event_id, timeout_sec);
+
+ if (timeout_sec) {
+ unsigned long jiffies = 0;
+
+ jiffies = msecs_to_jiffies(timeout_sec*1000);
+ timeleft = wait_for_completion_interruptible_timeout(
+ &spss_events[event_id], jiffies);
+ ret = timeleft;
+ } else {
+ ret = wait_for_completion_interruptible(
+ &spss_events[event_id]);
+ }
+
+ if (timeleft == 0) {
+ pr_err("wait for event [%d] timeout [%d] sec expired\n",
+ event_id, timeout_sec);
+ req->status = EVENT_STATUS_TIMEOUT;
+ } else if (ret < 0) {
+ pr_err("wait for event [%d] interrupted. ret [%d]\n",
+ event_id, ret);
+ req->status = EVENT_STATUS_ABORTED;
+ if (ret == -ERESTARTSYS) /* handle LPM event */
+ return ret;
+ } else {
+ pr_debug("wait for event [%d] completed.\n", event_id);
+ req->status = EVENT_STATUS_SIGNALED;
+ }
+
+ return 0;
+}
+
+static int spss_signal_event(struct spss_ioc_signal_event *req)
+{
+ uint32_t event_id;
+
+ mutex_lock(&event_lock);
+
+ event_id = req->event_id;
+
+ if (event_id >= SPSS_NUM_EVENTS) {
+ pr_err("event_id [%d] invalid\n", event_id);
+ mutex_unlock(&event_lock);
+ return -EINVAL;
+ }
+
+ if (spss_events_signaled[event_id]) {
+ pr_err("event_id [%d] already signaled\n", event_id);
+ mutex_unlock(&event_lock);
+ return -EINVAL;
+ }
+
+ pr_debug("signal event [%d]\n", event_id);
+ complete_all(&spss_events[event_id]);
+ req->status = EVENT_STATUS_SIGNALED;
+ spss_events_signaled[event_id] = true;
+
+ mutex_unlock(&event_lock);
+
+ return 0;
+}
+
+static int spss_is_event_signaled(struct spss_ioc_is_signaled *req)
+{
+ uint32_t event_id;
+
+ mutex_lock(&event_lock);
+
+ event_id = req->event_id;
+
+ if (event_id >= SPSS_NUM_EVENTS) {
+ pr_err("event_id [%d] invalid\n", event_id);
+ mutex_unlock(&event_lock);
+ return -EINVAL;
+ }
+
+ if (spss_events_signaled[event_id])
+ req->status = EVENT_STATUS_SIGNALED;
+ else
+ req->status = EVENT_STATUS_NOT_SIGNALED;
+
+ mutex_unlock(&event_lock);
+
+ return 0;
+}
+
static long spss_utils_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
+ int ret;
void *buf = (void *) arg;
unsigned char data[64] = {0};
size_t size = 0;
u32 i = 0;
/* Saved cmacs of spu firmware and UEFI loaded spu apps */
u32 fw_and_apps_cmacs[FW_AND_APPS_CMAC_SIZE];
+ void *req = (void *) data;
if (buf == NULL) {
pr_err("invalid ioctl arg\n");
@@ -429,7 +541,7 @@ static long spss_utils_ioctl(struct file *file,
/*
* SPSS is loaded now by UEFI,
- * so IAR callback is not being called on powerup by PIL.
+ * so IAR callback is not being called on power-up by PIL.
* therefore read the spu pbl fw cmac and apps cmac from ioctl.
* The callback shall be called on spss SSR.
*/
@@ -439,6 +551,42 @@ static long spss_utils_ioctl(struct file *file,
spss_get_saved_uefi_apps_cmac();
break;
+ case SPSS_IOC_WAIT_FOR_EVENT:
+ /* check input params */
+ if (size != sizeof(struct spss_ioc_wait_for_event)) {
+ pr_err("cmd [0x%x] invalid size [0x%x]\n", cmd, size);
+ return -EINVAL;
+ }
+ ret = spss_wait_for_event(req);
+ copy_to_user((void __user *)arg, data, size);
+ if (ret < 0)
+ return ret;
+ break;
+
+ case SPSS_IOC_SIGNAL_EVENT:
+ /* check input params */
+ if (size != sizeof(struct spss_ioc_signal_event)) {
+ pr_err("cmd [0x%x] invalid size [0x%x]\n", cmd, size);
+ return -EINVAL;
+ }
+ ret = spss_signal_event(req);
+ copy_to_user((void __user *)arg, data, size);
+ if (ret < 0)
+ return ret;
+ break;
+
+ case SPSS_IOC_IS_EVENT_SIGNALED:
+ /* check input params */
+ if (size != sizeof(struct spss_ioc_is_signaled)) {
+ pr_err("cmd [0x%x] invalid size [0x%x]\n", cmd, size);
+ return -EINVAL;
+ }
+ ret = spss_is_event_signaled(req);
+ copy_to_user((void __user *)arg, data, size);
+ if (ret < 0)
+ return ret;
+ break;
+
default:
pr_err("invalid ioctl cmd [0x%x]\n", cmd);
return -EINVAL;
@@ -772,7 +920,7 @@ static int spss_parse_dt(struct device_node *node)
iar_state = val1;
- pr_info("iar_state [%d]\n", iar_state);
+ pr_debug("iar_state [%d]\n", iar_state);
return 0;
}
@@ -909,28 +1057,65 @@ static int spss_set_saved_uefi_apps_cmac(void)
return 0;
}
-static int spss_utils_iar_callback(struct notifier_block *nb,
+static int spss_utils_pil_callback(struct notifier_block *nb,
unsigned long code,
void *data)
{
- /* do nothing if IAR is not active */
- if (!is_iar_active)
- return NOTIFY_OK;
+ int i, event_id;
switch (code) {
case SUBSYS_BEFORE_SHUTDOWN:
pr_debug("[SUBSYS_BEFORE_SHUTDOWN] event.\n");
+ mutex_lock(&event_lock);
+ /* Reset NVM-ready and SPU-ready events */
+ for (i = SPSS_EVENT_ID_NVM_READY;
+ i <= SPSS_EVENT_ID_SPU_READY; i++) {
+ reinit_completion(&spss_events[i]);
+ spss_events_signaled[i] = false;
+ }
+ mutex_unlock(&event_lock);
+ pr_debug("reset spss events.\n");
break;
case SUBSYS_AFTER_SHUTDOWN:
pr_debug("[SUBSYS_AFTER_SHUTDOWN] event.\n");
+ mutex_lock(&event_lock);
+ event_id = SPSS_EVENT_ID_SPU_POWER_DOWN;
+ complete_all(&spss_events[event_id]);
+ spss_events_signaled[event_id] = true;
+
+ event_id = SPSS_EVENT_ID_SPU_POWER_UP;
+ reinit_completion(&spss_events[event_id]);
+ spss_events_signaled[event_id] = false;
+ mutex_unlock(&event_lock);
break;
case SUBSYS_BEFORE_POWERUP:
pr_debug("[SUBSYS_BEFORE_POWERUP] event.\n");
break;
case SUBSYS_AFTER_POWERUP:
pr_debug("[SUBSYS_AFTER_POWERUP] event.\n");
+ mutex_lock(&event_lock);
+ event_id = SPSS_EVENT_ID_SPU_POWER_UP;
+ complete_all(&spss_events[event_id]);
+ spss_events_signaled[event_id] = true;
+
+ event_id = SPSS_EVENT_ID_SPU_POWER_DOWN;
+ reinit_completion(&spss_events[event_id]);
+ spss_events_signaled[event_id] = false;
+ mutex_unlock(&event_lock);
+ break;
+ case SUBSYS_RAMDUMP_NOTIFICATION:
+ pr_debug("[SUBSYS_RAMDUMP_NOTIFICATION] event.\n");
+ break;
+ case SUBSYS_PROXY_VOTE:
+ pr_debug("[SUBSYS_PROXY_VOTE] event.\n");
+ break;
+ case SUBSYS_PROXY_UNVOTE:
+ pr_debug("[SUBSYS_PROXY_UNVOTE] event.\n");
break;
case SUBSYS_BEFORE_AUTH_AND_RESET:
+ /* do nothing if IAR is not active */
+ if (!is_iar_active)
+ return NOTIFY_OK;
pr_debug("[SUBSYS_BEFORE_AUTH_AND_RESET] event.\n");
/* Called on SSR as spss firmware is loaded by UEFI */
spss_set_fw_cmac(cmac_buf, sizeof(cmac_buf));
@@ -951,6 +1136,7 @@ static int spss_utils_iar_callback(struct notifier_block *nb,
static int spss_probe(struct platform_device *pdev)
{
int ret = 0;
+ int i;
struct device_node *np = NULL;
struct device *dev = NULL;
@@ -1023,7 +1209,7 @@ static int spss_probe(struct platform_device *pdev)
if (!iar_nb)
return -ENOMEM;
- iar_nb->notifier_call = spss_utils_iar_callback;
+ iar_nb->notifier_call = spss_utils_pil_callback;
iar_notif_handle = subsys_notif_register_notifier("spss", iar_nb);
if (IS_ERR_OR_NULL(iar_notif_handle)) {
@@ -1031,6 +1217,12 @@ static int spss_probe(struct platform_device *pdev)
kfree(iar_nb);
}
+ for (i = 0 ; i < SPSS_NUM_EVENTS; i++) {
+ init_completion(&spss_events[i]);
+ spss_events_signaled[i] = false;
+ }
+ mutex_init(&event_lock);
+
return 0;
}
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 29bc99c..e49d3c8 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -352,7 +352,10 @@ intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
unsigned int link_id = sdw->instance;
int pdi_conf = 0;
- pdi->intel_alh_id = (link_id * 16) + pdi->num + 5;
+ /* the Bulk and PCM streams are not contiguous */
+ pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
+ if (pdi->num >= 2)
+ pdi->intel_alh_id += 2;
/*
* Program stream parameters to stream SHIM register
@@ -381,7 +384,10 @@ intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
unsigned int link_id = sdw->instance;
unsigned int conf;
- pdi->intel_alh_id = (link_id * 16) + pdi->num + 5;
+ /* the Bulk and PCM streams are not contiguous */
+ pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
+ if (pdi->num >= 2)
+ pdi->intel_alh_id += 2;
/* Program Stream config ALH register */
conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id));
diff --git a/drivers/spi/spi-cavium-thunderx.c b/drivers/spi/spi-cavium-thunderx.c
index 8779377..828fbbe 100644
--- a/drivers/spi/spi-cavium-thunderx.c
+++ b/drivers/spi/spi-cavium-thunderx.c
@@ -81,6 +81,7 @@ static int thunderx_spi_probe(struct pci_dev *pdev,
error:
clk_disable_unprepare(p->clk);
+ pci_release_regions(pdev);
spi_master_put(master);
return ret;
}
@@ -95,6 +96,7 @@ static void thunderx_spi_remove(struct pci_dev *pdev)
return;
clk_disable_unprepare(p->clk);
+ pci_release_regions(pdev);
/* Put everything in a known state. */
writeq(0, p->register_base + OCTEON_SPI_CFG(p));
}
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 8f2e978..8b79e36 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -832,9 +832,9 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
if (ret)
goto err;
- irq = irq_of_parse_and_map(np, 0);
- if (!irq) {
- ret = -EINVAL;
+ irq = platform_get_irq(ofdev, 0);
+ if (irq < 0) {
+ ret = irq;
goto err;
}
@@ -847,7 +847,6 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
return 0;
err:
- irq_dispose_mapping(irq);
if (type == TYPE_FSL)
of_fsl_spi_free_chipselects(dev);
return ret;
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
index e6eb979..e4b31d6 100644
--- a/drivers/spi/spi-img-spfi.c
+++ b/drivers/spi/spi-img-spfi.c
@@ -676,6 +676,8 @@ static int img_spfi_probe(struct platform_device *pdev)
dma_release_channel(spfi->tx_ch);
if (spfi->rx_ch)
dma_release_channel(spfi->rx_ch);
+ spfi->tx_ch = NULL;
+ spfi->rx_ch = NULL;
dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n");
} else {
master->dma_tx = spfi->tx_ch;
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index f413338..5253881 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -1470,7 +1470,13 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
}
ssp->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ssp->clk))
+ return NULL;
+
ssp->irq = platform_get_irq(pdev, 0);
+ if (ssp->irq < 0)
+ return NULL;
+
ssp->type = type;
ssp->pdev = pdev;
ssp->port_id = pxa2xx_spi_get_port_id(adev);
diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c
index df5960b..f1fc2bd 100644
--- a/drivers/spi/spi-sprd-adi.c
+++ b/drivers/spi/spi-sprd-adi.c
@@ -367,6 +367,9 @@ static int sprd_adi_restart_handler(struct notifier_block *this,
val |= BIT_WDG_RUN | BIT_WDG_RST;
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val);
+ /* Lock the watchdog */
+ sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, ~WDG_UNLOCK_KEY);
+
mdelay(1000);
dev_emerg(sadi->dev, "Unable to restart system\n");
diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c
index a4e43fc..5df01ff 100644
--- a/drivers/spi/spi-st-ssc4.c
+++ b/drivers/spi/spi-st-ssc4.c
@@ -385,6 +385,7 @@ static int spi_st_probe(struct platform_device *pdev)
return 0;
clk_disable:
+ pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(spi_st->clk);
put_master:
spi_master_put(master);
@@ -396,6 +397,8 @@ static int spi_st_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct spi_st *spi_st = spi_master_get_devdata(master);
+ pm_runtime_disable(&pdev->dev);
+
clk_disable_unprepare(spi_st->clk);
pinctrl_pm_select_sleep_state(&pdev->dev);
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index 1427f34..d118731 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -1078,7 +1078,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
ret = clk_enable(tspi->clk);
if (ret < 0) {
dev_err(&pdev->dev, "Clock enable failed %d\n", ret);
- goto exit_free_master;
+ goto exit_clk_unprepare;
}
spi_irq = platform_get_irq(pdev, 0);
@@ -1151,6 +1151,8 @@ static int tegra_slink_probe(struct platform_device *pdev)
free_irq(spi_irq, tspi);
exit_clk_disable:
clk_disable(tspi->clk);
+exit_clk_unprepare:
+ clk_unprepare(tspi->clk);
exit_free_master:
spi_master_put(master);
return ret;
@@ -1164,6 +1166,7 @@ static int tegra_slink_remove(struct platform_device *pdev)
free_irq(tspi->irq, tspi);
clk_disable(tspi->clk);
+ clk_unprepare(tspi->clk);
if (tspi->tx_dma_chan)
tegra_slink_deinit_dma_param(tspi, false);
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index b9fb649..95c28ab 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -69,6 +69,7 @@ struct ti_qspi {
u32 dc;
bool mmap_enabled;
+ int current_cs;
};
#define QSPI_PID (0x0)
@@ -494,6 +495,7 @@ static void ti_qspi_enable_memory_map(struct spi_device *spi)
MEM_CS_EN(spi->chip_select));
}
qspi->mmap_enabled = true;
+ qspi->current_cs = spi->chip_select;
}
static void ti_qspi_disable_memory_map(struct spi_device *spi)
@@ -505,6 +507,7 @@ static void ti_qspi_disable_memory_map(struct spi_device *spi)
regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
MEM_CS_MASK, 0);
qspi->mmap_enabled = false;
+ qspi->current_cs = -1;
}
static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
@@ -550,7 +553,7 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
mutex_lock(&qspi->list_lock);
- if (!qspi->mmap_enabled)
+ if (!qspi->mmap_enabled || qspi->current_cs != mem->spi->chip_select)
ti_qspi_enable_memory_map(mem->spi);
ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
op->addr.nbytes, op->dummy.nbytes);
@@ -807,6 +810,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
}
}
qspi->mmap_enabled = false;
+ qspi->current_cs = -1;
ret = devm_spi_register_master(&pdev->dev, master);
if (!ret)
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index c5fe08b..0287255 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -634,6 +634,9 @@ static int spidev_release(struct inode *inode, struct file *filp)
if (dofree)
kfree(spidev);
}
+#ifdef CONFIG_SPI_SLAVE
+ spi_slave_abort(spidev->spi);
+#endif
mutex_unlock(&device_list_lock);
return 0;
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index be81533..e3df4bf 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -350,8 +350,23 @@ static inline vm_flags_t calc_vm_may_flags(unsigned long prot)
_calc_vm_trans(prot, PROT_EXEC, VM_MAYEXEC);
}
+static int ashmem_vmfile_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ /* do not allow to mmap ashmem backing shmem file directly */
+ return -EPERM;
+}
+
+static unsigned long
+ashmem_vmfile_get_unmapped_area(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
+}
+
static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)
{
+ static struct file_operations vmfile_fops;
struct ashmem_area *asma = file->private_data;
int ret = 0;
@@ -392,6 +407,19 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)
}
vmfile->f_mode |= FMODE_LSEEK;
asma->file = vmfile;
+ /*
+ * override mmap operation of the vmfile so that it can't be
+ * remapped which would lead to creation of a new vma with no
+ * asma permission checks. Have to override get_unmapped_area
+ * as well to prevent VM_BUG_ON check for f_ops modification.
+ */
+ if (!vmfile_fops.mmap) {
+ vmfile_fops = *vmfile->f_op;
+ vmfile_fops.mmap = ashmem_vmfile_mmap;
+ vmfile_fops.get_unmapped_area =
+ ashmem_vmfile_get_unmapped_area;
+ }
+ vmfile->f_op = &vmfile_fops;
}
get_file(asma->file);
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index 4bdf44d..dc62db1 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -623,6 +623,11 @@ static int gsc_hpdi_auto_attach(struct comedi_device *dev,
dma_alloc_coherent(&pcidev->dev, DMA_BUFFER_SIZE,
&devpriv->dio_buffer_phys_addr[i],
GFP_KERNEL);
+ if (!devpriv->dio_buffer[i]) {
+ dev_warn(dev->class_dev,
+ "failed to allocate DMA buffer\n");
+ return -ENOMEM;
+ }
}
/* allocate dma descriptors */
devpriv->dma_desc = dma_alloc_coherent(&pcidev->dev,
@@ -630,6 +635,11 @@ static int gsc_hpdi_auto_attach(struct comedi_device *dev,
NUM_DMA_DESCRIPTORS,
&devpriv->dma_desc_phys_addr,
GFP_KERNEL);
+ if (!devpriv->dma_desc) {
+ dev_warn(dev->class_dev,
+ "failed to allocate DMA descriptors\n");
+ return -ENOMEM;
+ }
if (devpriv->dma_desc_phys_addr & 0xf) {
dev_warn(dev->class_dev,
" dma descriptors not quad-word aligned (bug)\n");
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index 16fcf63..3fe4738 100644
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -771,7 +771,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
fbdefio->deferred_io = fbtft_deferred_io;
fb_deferred_io_init(info);
- strncpy(info->fix.id, dev->driver->name, 16);
+ snprintf(info->fix.id, sizeof(info->fix.id), "%s", dev->driver->name);
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_TRUECOLOR;
info->fix.xpanstep = 0;
diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c
index dd9b02d..c6a5b62 100644
--- a/drivers/staging/rtl8188eu/core/rtw_xmit.c
+++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c
@@ -778,7 +778,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN);
memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN);
- if (psta->qos_option)
+ if (psta && psta->qos_option)
qos_option = true;
} else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
@@ -786,7 +786,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN);
- if (psta->qos_option)
+ if (psta && psta->qos_option)
qos_option = true;
} else {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv)));
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index e218b5c..2066a1d 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -1467,7 +1467,7 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb)
(struct tx_fwinfo_819x_usb *)(skb->data + USB_HWDESC_HEADER_LEN);
struct usb_device *udev = priv->udev;
int pend;
- int status;
+ int status, rt = -1;
struct urb *tx_urb = NULL, *tx_urb_zero = NULL;
unsigned int idx_pipe;
@@ -1611,8 +1611,10 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb)
}
if (bSend0Byte) {
tx_urb_zero = usb_alloc_urb(0, GFP_ATOMIC);
- if (!tx_urb_zero)
- return -ENOMEM;
+ if (!tx_urb_zero) {
+ rt = -ENOMEM;
+ goto error;
+ }
usb_fill_bulk_urb(tx_urb_zero, udev,
usb_sndbulkpipe(udev, idx_pipe),
&zero, 0, tx_zero_isr, dev);
@@ -1622,7 +1624,7 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb)
"Error TX URB for zero byte %d, error %d",
atomic_read(&priv->tx_pending[tcb_desc->queue_index]),
status);
- return -1;
+ goto error;
}
}
netif_trans_update(dev);
@@ -1633,7 +1635,12 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb)
RT_TRACE(COMP_ERR, "Error TX URB %d, error %d",
atomic_read(&priv->tx_pending[tcb_desc->queue_index]),
status);
- return -1;
+
+error:
+ dev_kfree_skb_any(skb);
+ usb_free_urb(tx_urb);
+ usb_free_urb(tx_urb_zero);
+ return rt;
}
static short rtl8192_usb_initendpoints(struct net_device *dev)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 03e9cb1..317d0f3 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1157,7 +1157,9 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length,
conn->cid);
- target_get_sess_cmd(&cmd->se_cmd, true);
+ if (target_get_sess_cmd(&cmd->se_cmd, true) < 0)
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_WAITING_FOR_LOGOUT, buf);
cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd,
scsilun_to_int(&hdr->lun));
@@ -1998,7 +2000,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
conn->sess->se_sess, 0, DMA_NONE,
TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
- target_get_sess_cmd(&cmd->se_cmd, true);
+ if (target_get_sess_cmd(&cmd->se_cmd, true) < 0)
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_WAITING_FOR_LOGOUT, buf);
/*
* TASK_REASSIGN for ERL=2 / connection stays inside of
@@ -4204,6 +4208,8 @@ int iscsit_close_connection(
* must wait until they have completed.
*/
iscsit_check_conn_usage_count(conn);
+ target_sess_cmd_list_set_waiting(sess->se_sess);
+ target_wait_for_sess_cmds(sess->se_sess);
ahash_request_free(conn->conn_tx_hash);
if (conn->conn_rx_hash) {
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index e2fa3a3..b6bf605 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -78,7 +78,7 @@ static int chap_check_algorithm(const char *a_str)
if (!token)
goto out;
- if (!strncmp(token, "5", 1)) {
+ if (!strcmp(token, "5")) {
pr_debug("Selected MD5 Algorithm\n");
kfree(orig);
return CHAP_DIGEST_MD5;
diff --git a/drivers/thermal/qcom/adc-tm.c b/drivers/thermal/qcom/adc-tm.c
index 9306105..195d2e9 100644
--- a/drivers/thermal/qcom/adc-tm.c
+++ b/drivers/thermal/qcom/adc-tm.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/err.h>
@@ -198,7 +198,8 @@ static const struct of_device_id adc_tm_match_table[] = {
{
.compatible = "qcom,adc-tm5-iio",
.data = &data_adc_tm5,
-
+ },
+ {
.compatible = "qcom,adc-tm7",
.data = &data_adc_tm7,
},
diff --git a/drivers/thermal/qcom/adc-tm7.c b/drivers/thermal/qcom/adc-tm7.c
index 4e8c87f..2d45ced 100644
--- a/drivers/thermal/qcom/adc-tm7.c
+++ b/drivers/thermal/qcom/adc-tm7.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -206,7 +206,7 @@ static int adc_tm7_configure(struct adc_tm_sensor *sensor)
buf[11] = ADC_TM_LOWER_MASK(mask);
buf[12] = ADC_TM_UPPER_MASK(mask);
- buf[13] |= (sensor->meas_en | sensor->high_thr_en << 1 |
+ buf[13] = (sensor->meas_en | sensor->high_thr_en << 1 |
sensor->low_thr_en);
ret = adc_tm_write_reg(chip, ADC_TM_SID, buf, 14);
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index 59eaa62..80fd06f 100644
--- a/drivers/tty/hvc/hvc_vio.c
+++ b/drivers/tty/hvc/hvc_vio.c
@@ -107,6 +107,14 @@ static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count)
return got;
}
+/**
+ * hvterm_raw_put_chars: send characters to firmware for given vterm adapter
+ * @vtermno: The virtual terminal number.
+ * @buf: The characters to send. Because of the underlying hypercall in
+ * hvc_put_chars(), this buffer must be at least 16 bytes long, even if
+ * you are sending fewer chars.
+ * @count: number of chars to send.
+ */
static int hvterm_raw_put_chars(uint32_t vtermno, const char *buf, int count)
{
struct hvterm_priv *pv = hvterm_privs[vtermno];
@@ -219,6 +227,7 @@ static const struct hv_ops hvterm_hvsi_ops = {
static void udbg_hvc_putc(char c)
{
int count = -1;
+ unsigned char bounce_buffer[16];
if (!hvterm_privs[0])
return;
@@ -229,7 +238,12 @@ static void udbg_hvc_putc(char c)
do {
switch(hvterm_privs[0]->proto) {
case HV_PROTOCOL_RAW:
- count = hvterm_raw_put_chars(0, &c, 1);
+ /*
+ * hvterm_raw_put_chars requires at least a 16-byte
+ * buffer, so go via the bounce buffer
+ */
+ bounce_buffer[0] = c;
+ count = hvterm_raw_put_chars(0, bounce_buffer, 1);
break;
case HV_PROTOCOL_HVSI:
count = hvterm_hvsi_put_chars(0, &c, 1);
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index dd8949e..f34520e 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -2154,27 +2154,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
mode |= ATMEL_US_USMODE_NORMAL;
}
- /* set the mode, clock divisor, parity, stop bits and data size */
- atmel_uart_writel(port, ATMEL_US_MR, mode);
-
- /*
- * when switching the mode, set the RTS line state according to the
- * new mode, otherwise keep the former state
- */
- if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) {
- unsigned int rts_state;
-
- if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
- /* let the hardware control the RTS line */
- rts_state = ATMEL_US_RTSDIS;
- } else {
- /* force RTS line to low level */
- rts_state = ATMEL_US_RTSEN;
- }
-
- atmel_uart_writel(port, ATMEL_US_CR, rts_state);
- }
-
/*
* Set the baud rate:
* Fractional baudrate allows to setup output frequency more
@@ -2200,6 +2179,28 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
quot = cd | fp << ATMEL_US_FP_OFFSET;
atmel_uart_writel(port, ATMEL_US_BRGR, quot);
+
+ /* set the mode, clock divisor, parity, stop bits and data size */
+ atmel_uart_writel(port, ATMEL_US_MR, mode);
+
+ /*
+ * when switching the mode, set the RTS line state according to the
+ * new mode, otherwise keep the former state
+ */
+ if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) {
+ unsigned int rts_state;
+
+ if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
+ /* let the hardware control the RTS line */
+ rts_state = ATMEL_US_RTSDIS;
+ } else {
+ /* force RTS line to low level */
+ rts_state = ATMEL_US_RTSEN;
+ }
+
+ atmel_uart_writel(port, ATMEL_US_CR, rts_state);
+ }
+
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
atmel_port->tx_stopped = false;
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index b707dff..e218a134 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/bitmap.h>
@@ -174,6 +174,8 @@ struct msm_geni_serial_port {
struct msm_geni_serial_ver_info ver_info;
u32 cur_tx_remaining;
bool startup_in_progress;
+ bool is_console;
+ bool rumi_platform;
};
static const struct uart_ops msm_geni_serial_pops;
@@ -1912,30 +1914,6 @@ static int msm_geni_serial_startup(struct uart_port *uport)
return ret;
}
-static int get_clk_cfg(unsigned long clk_freq, unsigned long *ser_clk)
-{
- unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
- 32000000, 48000000, 64000000, 80000000, 96000000, 100000000,
- 102400000, 112000000, 120000000, 128000000};
- int i;
- int match = -1;
-
- for (i = 0; i < ARRAY_SIZE(root_freq); i++) {
- if (clk_freq > root_freq[i])
- continue;
-
- if (!(root_freq[i] % clk_freq)) {
- match = i;
- break;
- }
- }
- if (match != -1)
- *ser_clk = root_freq[match];
- else
- pr_err("clk_freq %ld\n", clk_freq);
- return match;
-}
-
static void geni_serial_write_term_regs(struct uart_port *uport, u32 loopback,
u32 tx_trans_cfg, u32 tx_parity_cfg, u32 rx_trans_cfg,
u32 rx_parity_cfg, u32 bits_per_char, u32 stop_bit_len,
@@ -1961,6 +1939,31 @@ static void geni_serial_write_term_regs(struct uart_port *uport, u32 loopback,
geni_read_reg_nolog(uport->membase, GENI_SER_M_CLK_CFG);
}
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
+static int get_clk_cfg(unsigned long clk_freq, unsigned long *ser_clk)
+{
+ unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
+ 32000000, 48000000, 64000000, 80000000, 96000000, 100000000,
+ 102400000, 112000000, 120000000, 128000000};
+ int i;
+ int match = -1;
+
+ for (i = 0; i < ARRAY_SIZE(root_freq); i++) {
+ if (clk_freq > root_freq[i])
+ continue;
+
+ if (!(root_freq[i] % clk_freq)) {
+ match = i;
+ break;
+ }
+ }
+ if (match != -1)
+ *ser_clk = root_freq[match];
+ else
+ pr_err("clk_freq %ld\n", clk_freq);
+ return match;
+}
+
static int get_clk_div_rate(unsigned int baud, unsigned long *desired_clk_rate)
{
unsigned long ser_clk;
@@ -1981,6 +1984,7 @@ static int get_clk_div_rate(unsigned int baud, unsigned long *desired_clk_rate)
exit_get_clk_div_rate:
return clk_div;
}
+#endif
static void msm_geni_serial_set_termios(struct uart_port *uport,
struct ktermios *termios, struct ktermios *old)
@@ -1992,11 +1996,22 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
unsigned int rx_trans_cfg;
unsigned int rx_parity_cfg;
unsigned int stop_bit_len;
- int clk_div;
+ int clk_div, ret;
unsigned long ser_clk_cfg = 0;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
unsigned long clk_rate;
unsigned long flags;
+ unsigned long desired_rate;
+ unsigned int clk_idx;
+ int uart_sampling;
+ int clk_freq_diff;
+
+ /* QUP_2.5.0 and older RUMI has sampling rate as 32 */
+ if (port->rumi_platform && port->is_console) {
+ geni_write_reg_nolog(0x21, uport->membase, GENI_SER_M_CLK_CFG);
+ geni_write_reg_nolog(0x21, uport->membase, GENI_SER_S_CLK_CFG);
+ geni_read_reg_nolog(uport->membase, GENI_SER_M_CLK_CFG);
+ }
if (!uart_console(uport)) {
int ret = msm_geni_serial_power_on(uport);
@@ -2020,12 +2035,31 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
/* baud rate */
baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
port->cur_baud = baud;
- clk_div = get_clk_div_rate(baud, &clk_rate);
+ uart_sampling = IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING) ?
+ UART_OVERSAMPLING / 2 : UART_OVERSAMPLING;
+ desired_rate = baud * uart_sampling;
+
+ /*
+ * Request for nearest possible required frequency instead of the exact
+ * required frequency.
+ */
+ ret = geni_se_clk_freq_match(&port->serial_rsc, desired_rate,
+ &clk_idx, &clk_rate, false);
+ if (ret) {
+ dev_err(uport->dev, "%s: Failed(%d) to find src clk for 0x%x\n",
+ __func__, ret, baud);
+ goto exit_set_termios;
+ }
+
+ clk_div = DIV_ROUND_UP(clk_rate, desired_rate);
if (clk_div <= 0)
goto exit_set_termios;
- if (IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING))
- clk_div *= 2;
+ clk_freq_diff = (desired_rate - (clk_rate / clk_div));
+ if (clk_freq_diff)
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "src_clk freq_diff:%d baud:%d clk_rate:%d clk_div:%d\n",
+ clk_freq_diff, baud, clk_rate, clk_div);
uport->uartclk = clk_rate;
clk_set_rate(port->serial_rsc.se_clk, clk_rate);
@@ -2337,6 +2371,13 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev,
*/
msm_geni_serial_poll_cancel_tx(uport);
+ /* Only for earlyconsole */
+ if (IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING)) {
+ geni_write_reg_nolog(0x21, uport->membase, GENI_SER_M_CLK_CFG);
+ geni_write_reg_nolog(0x21, uport->membase, GENI_SER_S_CLK_CFG);
+ geni_read_reg_nolog(uport->membase, GENI_SER_M_CLK_CFG);
+ }
+
se_get_packing_config(8, 1, false, &cfg0, &cfg1);
geni_se_init(uport->membase, (DEF_FIFO_DEPTH_WORDS >> 1),
(DEF_FIFO_DEPTH_WORDS - 2));
@@ -2529,7 +2570,13 @@ static int msm_geni_serial_get_ver_info(struct uart_port *uport)
int hw_ver, ret = 0;
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
- se_geni_clks_on(&msm_port->serial_rsc);
+ /*
+ * At this time early console is still active and transfers are
+ * in-coming. Make sure UART doesn't turn on/off clocks for
+ * console usecase.
+ */
+ if (!msm_port->is_console)
+ se_geni_clks_on(&msm_port->serial_rsc);
/* Basic HW and FW info */
if (unlikely(get_se_proto(uport->membase) != UART)) {
dev_err(uport->dev, "%s: Invalid FW %d loaded.\n",
@@ -2557,7 +2604,8 @@ static int msm_geni_serial_get_ver_info(struct uart_port *uport)
msm_port->ver_info.hw_minor_ver,
msm_port->ver_info.hw_step_ver);
exit_ver_info:
- se_geni_clks_off(&msm_port->serial_rsc);
+ if (!msm_port->is_console)
+ se_geni_clks_off(&msm_port->serial_rsc);
return ret;
}
@@ -2609,6 +2657,7 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
line, ret);
goto exit_geni_serial_probe;
}
+ dev_port->is_console = is_console;
uport = &dev_port->uport;
@@ -2649,6 +2698,10 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
dev_port->serial_rsc.ctrl_dev = &pdev->dev;
+ /* RUMI specific */
+ dev_port->rumi_platform = of_property_read_bool(pdev->dev.of_node,
+ "qcom,rumi_platform");
+
if (of_property_read_u32(pdev->dev.of_node, "qcom,wakeup-byte",
&wake_char)) {
dev_dbg(&pdev->dev, "No Wakeup byte specified\n");
@@ -2771,6 +2824,13 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
}
+ if (IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING) &&
+ dev_port->rumi_platform && dev_port->is_console) {
+ geni_write_reg_nolog(0x21, uport->membase, GENI_SER_M_CLK_CFG);
+ geni_write_reg_nolog(0x21, uport->membase, GENI_SER_S_CLK_CFG);
+ geni_read_reg_nolog(uport->membase, GENI_SER_M_CLK_CFG);
+ }
+
dev_info(&pdev->dev, "Serial port%d added.FifoSize %d is_console%d\n",
line, uport->fifosize, is_console);
device_create_file(uport->dev, &dev_attr_loopback);
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index c10d9cc5..4caeca6 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1580,6 +1580,7 @@ static void __msm_console_write(struct uart_port *port, const char *s,
int num_newlines = 0;
bool replaced = false;
void __iomem *tf;
+ int locked = 1;
if (is_uartdm)
tf = port->membase + UARTDM_TF;
@@ -1592,7 +1593,13 @@ static void __msm_console_write(struct uart_port *port, const char *s,
num_newlines++;
count += num_newlines;
- spin_lock(&port->lock);
+ if (port->sysrq)
+ locked = 0;
+ else if (oops_in_progress)
+ locked = spin_trylock(&port->lock);
+ else
+ spin_lock(&port->lock);
+
if (is_uartdm)
msm_reset_dm_count(port, count);
@@ -1628,7 +1635,9 @@ static void __msm_console_write(struct uart_port *port, const char *s,
iowrite32_rep(tf, buf, 1);
i += num_chars;
}
- spin_unlock(&port->lock);
+
+ if (locked)
+ spin_unlock(&port->lock);
}
static void msm_console_write(struct console *co, const char *s,
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 52e2bd5..3d2eb45 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -203,9 +203,58 @@ static const unsigned short super_speed_maxpacket_maxes[4] = {
[USB_ENDPOINT_XFER_INT] = 1024,
};
-static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
- int asnum, struct usb_host_interface *ifp, int num_ep,
- unsigned char *buffer, int size)
+static bool endpoint_is_duplicate(struct usb_endpoint_descriptor *e1,
+ struct usb_endpoint_descriptor *e2)
+{
+ if (e1->bEndpointAddress == e2->bEndpointAddress)
+ return true;
+
+ if (usb_endpoint_xfer_control(e1) || usb_endpoint_xfer_control(e2)) {
+ if (usb_endpoint_num(e1) == usb_endpoint_num(e2))
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Check for duplicate endpoint addresses in other interfaces and in the
+ * altsetting currently being parsed.
+ */
+static bool config_endpoint_is_duplicate(struct usb_host_config *config,
+ int inum, int asnum, struct usb_endpoint_descriptor *d)
+{
+ struct usb_endpoint_descriptor *epd;
+ struct usb_interface_cache *intfc;
+ struct usb_host_interface *alt;
+ int i, j, k;
+
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ intfc = config->intf_cache[i];
+
+ for (j = 0; j < intfc->num_altsetting; ++j) {
+ alt = &intfc->altsetting[j];
+
+ if (alt->desc.bInterfaceNumber == inum &&
+ alt->desc.bAlternateSetting != asnum)
+ continue;
+
+ for (k = 0; k < alt->desc.bNumEndpoints; ++k) {
+ epd = &alt->endpoint[k].desc;
+
+ if (endpoint_is_duplicate(epd, d))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static int usb_parse_endpoint(struct device *ddev, int cfgno,
+ struct usb_host_config *config, int inum, int asnum,
+ struct usb_host_interface *ifp, int num_ep,
+ unsigned char *buffer, int size)
{
unsigned char *buffer0 = buffer;
struct usb_endpoint_descriptor *d;
@@ -242,13 +291,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
goto skip_to_next_endpoint_or_interface_descriptor;
/* Check for duplicate endpoint addresses */
- for (i = 0; i < ifp->desc.bNumEndpoints; ++i) {
- if (ifp->endpoint[i].desc.bEndpointAddress ==
- d->bEndpointAddress) {
- dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
- cfgno, inum, asnum, d->bEndpointAddress);
- goto skip_to_next_endpoint_or_interface_descriptor;
- }
+ if (config_endpoint_is_duplicate(config, inum, asnum, d)) {
+ dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
+ cfgno, inum, asnum, d->bEndpointAddress);
+ goto skip_to_next_endpoint_or_interface_descriptor;
}
endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
@@ -522,8 +568,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
if (((struct usb_descriptor_header *) buffer)->bDescriptorType
== USB_DT_INTERFACE)
break;
- retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt,
- num_ep, buffer, size);
+ retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum,
+ alt, num_ep, buffer, size);
if (retval < 0)
return retval;
++n;
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 29c6414..0020482 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -739,8 +739,15 @@ static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
intf = usb_ifnum_to_if(dev, ifnum);
if (!intf)
err = -ENOENT;
- else
+ else {
+ unsigned int old_suppress;
+
+ /* suppress uevents while claiming interface */
+ old_suppress = dev_get_uevent_suppress(&intf->dev);
+ dev_set_uevent_suppress(&intf->dev, 1);
err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
+ dev_set_uevent_suppress(&intf->dev, old_suppress);
+ }
if (err == 0)
set_bit(ifnum, &ps->ifclaimed);
return err;
@@ -760,7 +767,13 @@ static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum)
if (!intf)
err = -ENOENT;
else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
+ unsigned int old_suppress;
+
+ /* suppress uevents while releasing interface */
+ old_suppress = dev_get_uevent_suppress(&intf->dev);
+ dev_set_uevent_suppress(&intf->dev, 1);
usb_driver_release_interface(&usbfs_driver, intf);
+ dev_set_uevent_suppress(&intf->dev, old_suppress);
err = 0;
}
return err;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 9301706..5c6f1c4 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2668,7 +2668,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
#define SET_ADDRESS_TRIES 2
#define GET_DESCRIPTOR_TRIES 2
#define SET_CONFIG_TRIES (2 * (use_both_schemes + 1))
-#define USE_NEW_SCHEME(i, scheme) ((i) / 2 == (int)scheme)
+#define USE_NEW_SCHEME(i, scheme) ((i) / 2 == (int)(scheme))
#define HUB_ROOT_RESET_TIME 60 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index bfeae6b..e6ae1fe 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -4127,10 +4127,10 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
if (on) {
dev_dbg(mdwc->dev, "%s: turn on host\n", __func__);
+ mdwc->hs_phy->flags |= PHY_HOST_MODE;
pm_runtime_get_sync(mdwc->dev);
dbg_event(0xFF, "StrtHost gync",
atomic_read(&mdwc->dev->power.usage_count));
- mdwc->hs_phy->flags |= PHY_HOST_MODE;
if (dwc->maximum_speed >= USB_SPEED_SUPER) {
mdwc->ss_phy->flags |= PHY_HOST_MODE;
usb_phy_notify_connect(mdwc->ss_phy,
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 8794971..cfe0baa 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2875,6 +2875,13 @@ static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep,
static bool dwc3_gadget_ep_request_completed(struct dwc3_request *req)
{
+ /*
+ * For OUT direction, host may send less than the setup
+ * length. Return true for all OUT requests.
+ */
+ if (!req->direction)
+ return true;
+
return req->request.actual == req->request.length;
}
@@ -2910,7 +2917,7 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
req->request.actual = req->request.length - req->remaining;
- if (!dwc3_gadget_ep_request_completed(req) &&
+ if (!dwc3_gadget_ep_request_completed(req) ||
req->num_pending_sgs) {
__dwc3_gadget_kick_transfer(dep);
goto out;
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 97c39be..9086b64 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1588,6 +1588,9 @@ static int count_ext_prop(struct usb_configuration *c, int interface)
struct usb_function *f;
int j;
+ if (interface >= c->next_interface_id)
+ return -EINVAL;
+
f = c->interface[interface];
for (j = 0; j < f->os_desc_n; ++j) {
struct usb_os_desc *d;
@@ -1607,6 +1610,9 @@ static int len_ext_prop(struct usb_configuration *c, int interface)
struct usb_os_desc *d;
int j, res;
+ if (interface >= c->next_interface_id)
+ return -EINVAL;
+
res = 10; /* header length */
f = c->interface[interface];
for (j = 0; j < f->os_desc_n; ++j) {
@@ -1996,6 +2002,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
buf[6] = w_index;
count = count_ext_prop(os_desc_cfg,
interface);
+ if (count < 0)
+ return count;
put_unaligned_le16(count, buf + 8);
count = len_ext_prop(os_desc_cfg,
interface);
diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c
index 6ce0440..460d5d7 100644
--- a/drivers/usb/gadget/function/f_ecm.c
+++ b/drivers/usb/gadget/function/f_ecm.c
@@ -621,8 +621,12 @@ static void ecm_disable(struct usb_function *f)
DBG(cdev, "ecm deactivated\n");
- if (ecm->port.in_ep->enabled)
+ if (ecm->port.in_ep->enabled) {
gether_disconnect(&ecm->port);
+ } else {
+ ecm->port.in_ep->desc = NULL;
+ ecm->port.out_ep->desc = NULL;
+ }
usb_ep_disable(ecm->notify);
ecm->notify->desc = NULL;
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index 0b3f905..00dc4cb 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -944,6 +944,10 @@ static void receive_file_work(struct work_struct *data)
mtp_log("- count(%lld) not multiple of mtu(%d)\n",
count, dev->ep_out->maxpacket);
mutex_lock(&dev->read_mutex);
+ if (dev->state == STATE_OFFLINE) {
+ r = -EIO;
+ goto fail;
+ }
while (count > 0 || write_req) {
if (count > 0) {
/* queue a request */
@@ -1026,6 +1030,7 @@ static void receive_file_work(struct work_struct *data)
read_req = NULL;
}
}
+fail:
mutex_unlock(&dev->read_mutex);
mtp_log("returning %d\n", r);
/* write the result */
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index 59d0bd1..d5373bc 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -620,6 +620,7 @@ static void rndis_disable(struct usb_function *f)
gether_disconnect(&rndis->port);
usb_ep_disable(rndis->notify);
+ rndis->notify->desc = NULL;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 1505e55..d0248c5 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -1335,7 +1335,7 @@ static int dummy_perform_transfer(struct urb *urb, struct dummy_request *req,
u32 this_sg;
bool next_sg;
- to_host = usb_pipein(urb->pipe);
+ to_host = usb_urb_dir_in(urb);
rbuf = req->req.buf + req->req.actual;
if (!urb->num_sgs) {
@@ -1423,7 +1423,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
/* FIXME update emulated data toggle too */
- to_host = usb_pipein(urb->pipe);
+ to_host = usb_urb_dir_in(urb);
if (unlikely(len == 0))
is_short = 1;
else {
@@ -1844,7 +1844,7 @@ static void dummy_timer(struct timer_list *t)
/* find the gadget's ep for this request (if configured) */
address = usb_pipeendpoint (urb->pipe);
- if (usb_pipein(urb->pipe))
+ if (usb_urb_dir_in(urb))
address |= USB_DIR_IN;
ep = find_endpoint(dum, address);
if (!ep) {
@@ -2399,7 +2399,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)
s = "?";
break;
} s; }),
- ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "",
+ ep, ep ? (usb_urb_dir_in(urb) ? "in" : "out") : "",
({ char *s; \
switch (usb_pipetype(urb->pipe)) { \
case PIPE_CONTROL: \
@@ -2739,7 +2739,7 @@ static struct platform_driver dummy_hcd_driver = {
};
/*-------------------------------------------------------------------------*/
-#define MAX_NUM_UDC 2
+#define MAX_NUM_UDC 32
static struct platform_device *the_udc_pdev[MAX_NUM_UDC];
static struct platform_device *the_hcd_pdev[MAX_NUM_UDC];
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 3276304..f643603 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -27,6 +27,10 @@
/*-------------------------------------------------------------------------*/
+/* PID Codes that are used here, from EHCI specification, Table 3-16. */
+#define PID_CODE_IN 1
+#define PID_CODE_SETUP 2
+
/* fill a qtd, returning how much of the buffer we were able to queue up */
static int
@@ -190,7 +194,7 @@ static int qtd_copy_status (
int status = -EINPROGRESS;
/* count IN/OUT bytes, not SETUP (even short packets) */
- if (likely (QTD_PID (token) != 2))
+ if (likely(QTD_PID(token) != PID_CODE_SETUP))
urb->actual_length += length - QTD_LENGTH (token);
/* don't modify error codes */
@@ -206,6 +210,13 @@ static int qtd_copy_status (
if (token & QTD_STS_BABBLE) {
/* FIXME "must" disable babbling device's port too */
status = -EOVERFLOW;
+ /*
+ * When MMF is active and PID Code is IN, queue is halted.
+ * EHCI Specification, Table 4-13.
+ */
+ } else if ((token & QTD_STS_MMF) &&
+ (QTD_PID(token) == PID_CODE_IN)) {
+ status = -EPROTO;
/* CERR nonzero + halt --> stall */
} else if (QTD_CERR(token)) {
status = -EPIPE;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 74aeaa6..075c49c 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -493,7 +493,6 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
retval = xhci_resume(xhci, hibernated);
return retval;
}
-#endif /* CONFIG_PM */
static void xhci_pci_shutdown(struct usb_hcd *hcd)
{
@@ -506,6 +505,7 @@ static void xhci_pci_shutdown(struct usb_hcd *hcd)
if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
pci_set_power_state(pdev, PCI_D3hot);
}
+#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 4ffcee0..a86bac4 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/completion.h>
@@ -539,6 +539,7 @@ static inline void start_usb_host(struct usbpd *pd, bool ss)
{
enum plug_orientation cc = usbpd_get_plug_orientation(pd);
union extcon_property_value val;
+ int ret = 0;
val.intval = (cc == ORIENTATION_CC2);
extcon_set_property(pd->extcon, EXTCON_USB_HOST,
@@ -549,6 +550,13 @@ static inline void start_usb_host(struct usbpd *pd, bool ss)
EXTCON_PROP_USB_SS, val);
extcon_set_state_sync(pd->extcon, EXTCON_USB_HOST, 1);
+
+ /* blocks until USB host is completely started */
+ ret = extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 1);
+ if (ret) {
+ usbpd_err(&pd->dev, "err(%d) starting host", ret);
+ return;
+ }
}
static inline void stop_usb_peripheral(struct usbpd *pd)
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index f24b20f..fe5504d 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -25,6 +25,6 @@
obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o
obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o
-obj-$(CONFIG_MSM_QUSB_PHY) += phy-msm-qusb.o
+obj-$(CONFIG_MSM_QUSB_PHY) += phy-msm-qusb.o phy-msm-qusb-v2.o
obj-$(CONFIG_USB_MSM_SSPHY_QMP) += phy-msm-ssusb-qmp.o
obj-$(CONFIG_MSM_HSUSB_PHY) += phy-msm-snps-hs.o
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
new file mode 100644
index 0000000..c5d4d82
--- /dev/null
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -0,0 +1,1181 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/usb/phy.h>
+#include <linux/reset.h>
+#include <linux/debugfs.h>
+
+/* QUSB2PHY_PWR_CTRL1 register related bits */
+#define PWR_CTRL1_POWR_DOWN BIT(0)
+
+/* QUSB2PHY_PLL_COMMON_STATUS_ONE register related bits */
+#define CORE_READY_STATUS BIT(0)
+
+/* Get TUNE value from efuse bit-mask */
+#define TUNE_VAL_MASK(val, pos, mask) ((val >> pos) & mask)
+
+/* QUSB2PHY_INTR_CTRL register related bits */
+#define DMSE_INTR_HIGH_SEL BIT(4)
+#define DPSE_INTR_HIGH_SEL BIT(3)
+#define CHG_DET_INTR_EN BIT(2)
+#define DMSE_INTR_EN BIT(1)
+#define DPSE_INTR_EN BIT(0)
+
+/* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE register related bits */
+#define CORE_PLL_RATE BIT(0)
+#define CORE_PLL_RATE_MUX BIT(1)
+#define CORE_PLL_EN BIT(2)
+#define CORE_PLL_EN_MUX BIT(3)
+#define CORE_PLL_EN_FROM_RESET BIT(4)
+#define CORE_RESET BIT(5)
+#define CORE_RESET_MUX BIT(6)
+
+#define QUSB2PHY_1P8_VOL_MIN 1800000 /* uV */
+#define QUSB2PHY_1P8_VOL_MAX 1800000 /* uV */
+#define QUSB2PHY_1P8_HPM_LOAD 30000 /* uA */
+
+#define QUSB2PHY_3P3_VOL_MIN 3075000 /* uV */
+#define QUSB2PHY_3P3_VOL_MAX 3200000 /* uV */
+#define QUSB2PHY_3P3_HPM_LOAD 30000 /* uA */
+
+#define LINESTATE_DP BIT(0)
+#define LINESTATE_DM BIT(1)
+
+#define BIAS_CTRL_2_OVERRIDE_VAL 0x28
+
+#define DEBUG_CTRL1_OVERRIDE_VAL 0x09
+
+/* PERIPH_SS_PHY_REFGEN_NORTH_BG_CTRL register bits */
+#define BANDGAP_BYPASS BIT(0)
+
+/* DEBUG_CTRL2 register value to program VSTATUS MUX for PHY status */
+#define DEBUG_CTRL2_MUX_PLL_LOCK_STATUS 0x4
+
+/* STAT5 register bits */
+#define VSTATUS_PLL_LOCK_STATUS_MASK BIT(0)
+
+enum qusb_phy_reg {
+ PORT_TUNE1,
+ PLL_COMMON_STATUS_ONE,
+ PWR_CTRL1,
+ INTR_CTRL,
+ PLL_CORE_INPUT_OVERRIDE,
+ TEST1,
+ BIAS_CTRL_2,
+ DEBUG_CTRL1,
+ DEBUG_CTRL2,
+ STAT5,
+ USB2_PHY_REG_MAX,
+};
+
+struct qusb_phy {
+ struct usb_phy phy;
+ struct mutex lock;
+ void __iomem *base;
+ void __iomem *efuse_reg;
+ void __iomem *refgen_north_bg_reg;
+
+ struct clk *ref_clk_src;
+ struct clk *ref_clk;
+ struct clk *cfg_ahb_clk;
+ struct reset_control *phy_reset;
+
+ struct regulator *vdd;
+ struct regulator *vdda33;
+ struct regulator *vdda18;
+ int vdd_levels[3]; /* none, low, high */
+ int init_seq_len;
+ int *qusb_phy_init_seq;
+ int host_init_seq_len;
+ int *qusb_phy_host_init_seq;
+
+ unsigned int *phy_reg;
+ int qusb_phy_reg_offset_cnt;
+
+ u32 tune_val;
+ int efuse_bit_pos;
+ int efuse_num_of_bits;
+
+ bool cable_connected;
+ bool suspended;
+ bool dpdm_enable;
+
+ struct regulator_desc dpdm_rdesc;
+ struct regulator_dev *dpdm_rdev;
+
+ /* emulation targets specific */
+ void __iomem *emu_phy_base;
+ bool emulation;
+ int *emu_init_seq;
+ int emu_init_seq_len;
+ int *phy_pll_reset_seq;
+ int phy_pll_reset_seq_len;
+ int *emu_dcm_reset_seq;
+ int emu_dcm_reset_seq_len;
+
+ /* override TUNEX registers value */
+ struct dentry *root;
+ u8 tune[5];
+ u8 bias_ctrl2;
+
+ bool override_bias_ctrl2;
+};
+
+static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
+{
+ dev_dbg(qphy->phy.dev, "%s(): on:%d\n", __func__, on);
+
+ if (on) {
+ clk_prepare_enable(qphy->ref_clk_src);
+ if (qphy->ref_clk)
+ clk_prepare_enable(qphy->ref_clk);
+
+ if (qphy->cfg_ahb_clk)
+ clk_prepare_enable(qphy->cfg_ahb_clk);
+
+ } else {
+ if (qphy->cfg_ahb_clk)
+ clk_disable_unprepare(qphy->cfg_ahb_clk);
+
+ if (qphy->ref_clk)
+ clk_disable_unprepare(qphy->ref_clk);
+
+ clk_disable_unprepare(qphy->ref_clk_src);
+ }
+}
+
+static int qusb_phy_config_vdd(struct qusb_phy *qphy, int high)
+{
+ int min, ret;
+
+ min = high ? 1 : 0; /* low or none? */
+ ret = regulator_set_voltage(qphy->vdd, qphy->vdd_levels[min],
+ qphy->vdd_levels[2]);
+ if (ret) {
+ dev_err(qphy->phy.dev, "unable to set voltage for qusb vdd\n");
+ return ret;
+ }
+
+ dev_dbg(qphy->phy.dev, "min_vol:%d max_vol:%d\n",
+ qphy->vdd_levels[min], qphy->vdd_levels[2]);
+ return ret;
+}
+
+static int qusb_phy_disable_power(struct qusb_phy *qphy)
+{
+ int ret = 0;
+
+ mutex_lock(&qphy->lock);
+
+ dev_dbg(qphy->phy.dev, "%s:req to turn off regulators\n",
+ __func__);
+
+ ret = regulator_disable(qphy->vdda33);
+ if (ret)
+ dev_err(qphy->phy.dev, "Unable to disable vdda33:%d\n", ret);
+
+ if (!regulator_is_enabled(qphy->vdda33)) {
+ ret = regulator_set_voltage(qphy->vdda33, 0,
+ QUSB2PHY_3P3_VOL_MAX);
+ if (ret)
+ dev_err(qphy->phy.dev,
+ "Unable to set (0) voltage for vdda33:%d\n",
+ ret);
+
+ ret = regulator_set_load(qphy->vdda33, 0);
+ if (ret < 0)
+ dev_err(qphy->phy.dev,
+ "Unable to set (0) HPM of vdda33\n");
+
+ }
+
+ ret = regulator_disable(qphy->vdda18);
+ if (ret)
+ dev_err(qphy->phy.dev, "Unable to disable vdda18:%d\n", ret);
+
+ if (!regulator_is_enabled(qphy->vdda18)) {
+ ret = regulator_set_voltage(qphy->vdda18, 0,
+ QUSB2PHY_1P8_VOL_MAX);
+ if (ret)
+ dev_err(qphy->phy.dev,
+ "Unable to set (0) voltage for vdda18:%d\n", ret);
+
+ ret = regulator_set_load(qphy->vdda18, 0);
+ if (ret < 0)
+ dev_err(qphy->phy.dev,
+ "Unable to set LPM of vdda18\n");
+ }
+
+ ret = regulator_disable(qphy->vdd);
+ if (ret)
+ dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n", ret);
+
+ if (!regulator_is_enabled(qphy->vdd)) {
+ ret = qusb_phy_config_vdd(qphy, false);
+ if (ret)
+ dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n",
+ ret);
+ }
+
+ pr_debug("%s(): QUSB PHY's regulators are turned OFF.\n", __func__);
+
+ mutex_unlock(&qphy->lock);
+
+ return ret;
+}
+
+static int qusb_phy_enable_power(struct qusb_phy *qphy)
+{
+ int ret = 0;
+
+ mutex_lock(&qphy->lock);
+
+ dev_dbg(qphy->phy.dev, "%s:req to turn on regulators\n",
+ __func__);
+
+ ret = qusb_phy_config_vdd(qphy, true);
+ if (ret) {
+ dev_err(qphy->phy.dev, "Unable to config VDD:%d\n",
+ ret);
+ goto err_vdd;
+ }
+
+ ret = regulator_enable(qphy->vdd);
+ if (ret) {
+ dev_err(qphy->phy.dev, "Unable to enable VDD\n");
+ goto unconfig_vdd;
+ }
+
+ ret = regulator_set_load(qphy->vdda18, QUSB2PHY_1P8_HPM_LOAD);
+ if (ret < 0) {
+ dev_err(qphy->phy.dev, "Unable to set HPM of vdda18:%d\n", ret);
+ goto disable_vdd;
+ }
+
+ ret = regulator_set_voltage(qphy->vdda18, QUSB2PHY_1P8_VOL_MIN,
+ QUSB2PHY_1P8_VOL_MAX);
+ if (ret) {
+ dev_err(qphy->phy.dev,
+ "Unable to set voltage for vdda18:%d\n", ret);
+ goto put_vdda18_lpm;
+ }
+
+ ret = regulator_enable(qphy->vdda18);
+ if (ret) {
+ dev_err(qphy->phy.dev, "Unable to enable vdda18:%d\n", ret);
+ goto unset_vdda18;
+ }
+
+ ret = regulator_set_load(qphy->vdda33, QUSB2PHY_3P3_HPM_LOAD);
+ if (ret < 0) {
+ dev_err(qphy->phy.dev, "Unable to set HPM of vdda33:%d\n", ret);
+ goto disable_vdda18;
+ }
+
+ ret = regulator_set_voltage(qphy->vdda33, QUSB2PHY_3P3_VOL_MIN,
+ QUSB2PHY_3P3_VOL_MAX);
+ if (ret) {
+ dev_err(qphy->phy.dev,
+ "Unable to set voltage for vdda33:%d\n", ret);
+ goto put_vdda33_lpm;
+ }
+
+ ret = regulator_enable(qphy->vdda33);
+ if (ret) {
+ dev_err(qphy->phy.dev, "Unable to enable vdda33:%d\n", ret);
+ goto unset_vdd33;
+ }
+
+ pr_debug("%s(): QUSB PHY's regulators are turned ON.\n", __func__);
+
+ mutex_unlock(&qphy->lock);
+
+ return ret;
+
+unset_vdd33:
+ ret = regulator_set_voltage(qphy->vdda33, 0, QUSB2PHY_3P3_VOL_MAX);
+ if (ret)
+ dev_err(qphy->phy.dev,
+ "Unable to set (0) voltage for vdda33:%d\n", ret);
+
+put_vdda33_lpm:
+ ret = regulator_set_load(qphy->vdda33, 0);
+ if (ret < 0)
+ dev_err(qphy->phy.dev, "Unable to set (0) HPM of vdda33\n");
+
+disable_vdda18:
+ ret = regulator_disable(qphy->vdda18);
+ if (ret)
+ dev_err(qphy->phy.dev, "Unable to disable vdda18:%d\n", ret);
+
+unset_vdda18:
+ ret = regulator_set_voltage(qphy->vdda18, 0, QUSB2PHY_1P8_VOL_MAX);
+ if (ret)
+ dev_err(qphy->phy.dev,
+ "Unable to set (0) voltage for vdda18:%d\n", ret);
+
+put_vdda18_lpm:
+ ret = regulator_set_load(qphy->vdda18, 0);
+ if (ret < 0)
+ dev_err(qphy->phy.dev, "Unable to set LPM of vdda18\n");
+
+disable_vdd:
+ ret = regulator_disable(qphy->vdd);
+ if (ret)
+ dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n",
+ ret);
+
+unconfig_vdd:
+ ret = qusb_phy_config_vdd(qphy, false);
+ if (ret)
+ dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n",
+ ret);
+err_vdd:
+ mutex_unlock(&qphy->lock);
+
+ return ret;
+}
+
+static void qusb_phy_get_tune1_param(struct qusb_phy *qphy)
+{
+ u8 reg;
+ u32 bit_mask = 1;
+
+ pr_debug("%s(): num_of_bits:%d bit_pos:%d\n", __func__,
+ qphy->efuse_num_of_bits,
+ qphy->efuse_bit_pos);
+
+ /* get bit mask based on number of bits to use with efuse reg */
+ bit_mask = (bit_mask << qphy->efuse_num_of_bits) - 1;
+
+ /*
+ * if efuse reg is updated (i.e non-zero) then use it to program
+ * tune parameters
+ */
+ qphy->tune_val = readl_relaxed(qphy->efuse_reg);
+ pr_debug("%s(): bit_mask:%d efuse based tune1 value:%d\n",
+ __func__, bit_mask, qphy->tune_val);
+
+ qphy->tune_val = TUNE_VAL_MASK(qphy->tune_val,
+ qphy->efuse_bit_pos, bit_mask);
+ reg = readb_relaxed(qphy->base + qphy->phy_reg[PORT_TUNE1]);
+ if (qphy->tune_val) {
+ reg = reg & 0x0f;
+ reg |= (qphy->tune_val << 4);
+ }
+
+ qphy->tune_val = reg;
+}
+
+static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt,
+ unsigned long delay)
+{
+ int i;
+
+ pr_debug("Seq count:%d\n", cnt);
+ for (i = 0; i < cnt; i = i+2) {
+ pr_debug("write 0x%02x to 0x%02x\n", seq[i], seq[i+1]);
+ writel_relaxed(seq[i], base + seq[i+1]);
+ if (delay)
+ usleep_range(delay, (delay + 2000));
+ }
+}
+
+static void qusb_phy_reset(struct qusb_phy *qphy)
+{
+ int ret;
+
+ ret = reset_control_assert(qphy->phy_reset);
+ if (ret)
+ dev_err(qphy->phy.dev, "%s: phy_reset assert failed\n",
+ __func__);
+ usleep_range(100, 150);
+
+ ret = reset_control_deassert(qphy->phy_reset);
+ if (ret)
+ dev_err(qphy->phy.dev, "%s: phy_reset deassert failed\n",
+ __func__);
+}
+
+static bool qusb_phy_pll_locked(struct qusb_phy *qphy)
+{
+ u32 val;
+
+ writel_relaxed(DEBUG_CTRL2_MUX_PLL_LOCK_STATUS,
+ qphy->base + qphy->phy_reg[DEBUG_CTRL2]);
+
+ val = readl_relaxed(qphy->base + qphy->phy_reg[STAT5]);
+
+ return (val & VSTATUS_PLL_LOCK_STATUS_MASK);
+}
+
+static void qusb_phy_host_init(struct usb_phy *phy)
+{
+ u8 reg;
+ int p_index;
+ struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
+
+ dev_dbg(phy->dev, "%s\n", __func__);
+
+ qusb_phy_write_seq(qphy->base, qphy->qusb_phy_host_init_seq,
+ qphy->host_init_seq_len, 0);
+
+ if (qphy->efuse_reg) {
+ if (!qphy->tune_val)
+ qusb_phy_get_tune1_param(qphy);
+ } else {
+ /* For non fused chips we need to write the TUNE1 param as
+ * specified in DT otherwise we will end up writing 0 to
+ * to TUNE1
+ */
+ qphy->tune_val = readb_relaxed(qphy->base +
+ qphy->phy_reg[PORT_TUNE1]);
+ }
+
+ writel_relaxed(qphy->tune_val | BIT(7),
+ qphy->base + qphy->phy_reg[PORT_TUNE1]);
+ pr_debug("%s(): Programming TUNE1 parameter as:%x\n",
+ __func__, readb_relaxed(qphy->base +
+ qphy->phy_reg[PORT_TUNE1]));
+ writel_relaxed(DEBUG_CTRL1_OVERRIDE_VAL,
+ qphy->base + qphy->phy_reg[DEBUG_CTRL1]);
+
+ /* if debugfs based tunex params are set, use that value. */
+ for (p_index = 0; p_index < 5; p_index++) {
+ if (qphy->tune[p_index])
+ writel_relaxed(qphy->tune[p_index],
+ qphy->base + qphy->phy_reg[PORT_TUNE1] +
+ (4 * p_index));
+ }
+
+ if (qphy->refgen_north_bg_reg && qphy->override_bias_ctrl2)
+ if (readl_relaxed(qphy->refgen_north_bg_reg) & BANDGAP_BYPASS)
+ writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL,
+ qphy->base + qphy->phy_reg[BIAS_CTRL_2]);
+
+ if (qphy->bias_ctrl2)
+ writel_relaxed(qphy->bias_ctrl2,
+ qphy->base + qphy->phy_reg[BIAS_CTRL_2]);
+
+ /* Ensure above write is completed before turning ON ref clk */
+ wmb();
+
+ /* Require to get phy pll lock successfully */
+ usleep_range(150, 160);
+
+ reg = readb_relaxed(qphy->base + qphy->phy_reg[PLL_COMMON_STATUS_ONE]);
+ dev_dbg(phy->dev, "QUSB2PHY_PLL_COMMON_STATUS_ONE:%x\n", reg);
+ if (!(reg & CORE_READY_STATUS))
+ dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", reg);
+}
+
+static int qusb_phy_init(struct usb_phy *phy)
+{
+ struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
+ int p_index;
+ u8 reg;
+
+ dev_dbg(phy->dev, "%s\n", __func__);
+
+ qusb_phy_reset(qphy);
+
+ if (qphy->qusb_phy_host_init_seq && qphy->phy.flags & PHY_HOST_MODE) {
+ qusb_phy_host_init(phy);
+ return 0;
+ }
+
+ if (qphy->emulation) {
+ if (qphy->emu_init_seq)
+ qusb_phy_write_seq(qphy->emu_phy_base + 0x8000,
+ qphy->emu_init_seq,
+ qphy->emu_init_seq_len, 10000);
+
+ if (qphy->qusb_phy_init_seq)
+ qusb_phy_write_seq(qphy->base, qphy->qusb_phy_init_seq,
+ qphy->init_seq_len, 0);
+
+ /* Wait for 5ms as per QUSB2 RUMI sequence */
+ usleep_range(5000, 7000);
+
+ if (qphy->phy_pll_reset_seq)
+ qusb_phy_write_seq(qphy->base, qphy->phy_pll_reset_seq,
+ qphy->phy_pll_reset_seq_len, 10000);
+
+ if (qphy->emu_dcm_reset_seq)
+ qusb_phy_write_seq(qphy->emu_phy_base,
+ qphy->emu_dcm_reset_seq,
+ qphy->emu_dcm_reset_seq_len, 10000);
+
+ return 0;
+ }
+
+ /* Disable the PHY */
+ writel_relaxed(readl_relaxed(qphy->base + qphy->phy_reg[PWR_CTRL1]) |
+ PWR_CTRL1_POWR_DOWN,
+ qphy->base + qphy->phy_reg[PWR_CTRL1]);
+
+ if (qphy->qusb_phy_init_seq)
+ qusb_phy_write_seq(qphy->base, qphy->qusb_phy_init_seq,
+ qphy->init_seq_len, 0);
+ if (qphy->efuse_reg) {
+ if (!qphy->tune_val)
+ qusb_phy_get_tune1_param(qphy);
+
+ pr_debug("%s(): Programming TUNE1 parameter as:%x\n", __func__,
+ qphy->tune_val);
+ writel_relaxed(qphy->tune_val,
+ qphy->base + qphy->phy_reg[PORT_TUNE1]);
+ }
+
+ /* if debugfs based tunex params are set, use that value. */
+ for (p_index = 0; p_index < 5; p_index++) {
+ if (qphy->tune[p_index])
+ writel_relaxed(qphy->tune[p_index],
+ qphy->base + qphy->phy_reg[PORT_TUNE1] +
+ (4 * p_index));
+ }
+
+ if (qphy->refgen_north_bg_reg && qphy->override_bias_ctrl2)
+ if (readl_relaxed(qphy->refgen_north_bg_reg) & BANDGAP_BYPASS)
+ writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL,
+ qphy->base + qphy->phy_reg[BIAS_CTRL_2]);
+
+ if (qphy->bias_ctrl2)
+ writel_relaxed(qphy->bias_ctrl2,
+ qphy->base + qphy->phy_reg[BIAS_CTRL_2]);
+
+ /* ensure above writes are completed before re-enabling PHY */
+ wmb();
+
+ /* Enable the PHY */
+ writel_relaxed(readl_relaxed(qphy->base + qphy->phy_reg[PWR_CTRL1]) &
+ ~PWR_CTRL1_POWR_DOWN,
+ qphy->base + qphy->phy_reg[PWR_CTRL1]);
+
+ /* Ensure above write is completed before turning ON ref clk */
+ wmb();
+
+ /* Require to get phy pll lock successfully */
+ usleep_range(150, 160);
+
+ reg = readb_relaxed(qphy->base + qphy->phy_reg[PLL_COMMON_STATUS_ONE]);
+ dev_dbg(phy->dev, "QUSB2PHY_PLL_COMMON_STATUS_ONE:%x\n", reg);
+ if (!(reg & CORE_READY_STATUS)) {
+ dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", reg);
+ WARN_ON(1);
+ }
+ return 0;
+}
+
+static void qusb_phy_shutdown(struct usb_phy *phy)
+{
+ struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
+
+ dev_dbg(phy->dev, "%s\n", __func__);
+
+ qusb_phy_disable_power(qphy);
+
+}
+
+static u32 qusb_phy_get_linestate(struct qusb_phy *qphy)
+{
+ u32 linestate = 0;
+
+ if (qphy->cable_connected) {
+ if (qphy->phy.flags & PHY_HSFS_MODE)
+ linestate |= LINESTATE_DP;
+ else if (qphy->phy.flags & PHY_LS_MODE)
+ linestate |= LINESTATE_DM;
+ }
+ return linestate;
+}
+
+/**
+ * Performs QUSB2 PHY suspend/resume functionality.
+ *
+ * @uphy - usb phy pointer.
+ * @suspend - to enable suspend or not. 1 - suspend, 0 - resume
+ *
+ */
+static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
+{
+ struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
+ u32 linestate = 0, intr_mask = 0;
+
+ if (qphy->suspended == suspend) {
+ dev_dbg(phy->dev, "%s: USB PHY is already suspended\n",
+ __func__);
+ return 0;
+ }
+
+ if (suspend) {
+ /* Bus suspend case */
+ if (qphy->cable_connected) {
+ /* Disable all interrupts */
+ writel_relaxed(0x00,
+ qphy->base + qphy->phy_reg[INTR_CTRL]);
+
+ linestate = qusb_phy_get_linestate(qphy);
+ /*
+ * D+/D- interrupts are level-triggered, but we are
+ * only interested if the line state changes, so enable
+ * the high/low trigger based on current state. In
+ * other words, enable the triggers _opposite_ of what
+ * the current D+/D- levels are.
+ * e.g. if currently D+ high, D- low (HS 'J'/Suspend),
+ * configure the mask to trigger on D+ low OR D- high
+ */
+ intr_mask = DPSE_INTR_EN | DMSE_INTR_EN;
+ if (!(linestate & LINESTATE_DP)) /* D+ low */
+ intr_mask |= DPSE_INTR_HIGH_SEL;
+ if (!(linestate & LINESTATE_DM)) /* D- low */
+ intr_mask |= DMSE_INTR_HIGH_SEL;
+
+ writel_relaxed(intr_mask,
+ qphy->base + qphy->phy_reg[INTR_CTRL]);
+
+ if (linestate & (LINESTATE_DP | LINESTATE_DM)) {
+ /* enable phy auto-resume */
+ writel_relaxed(0x91,
+ qphy->base + qphy->phy_reg[TEST1]);
+ /* Delay recommended between TEST1 writes */
+ usleep_range(10, 20);
+ writel_relaxed(0x90,
+ qphy->base + qphy->phy_reg[TEST1]);
+ }
+
+ dev_dbg(phy->dev, "%s: intr_mask = %x\n",
+ __func__, intr_mask);
+
+ /* Makes sure that above write goes through */
+ wmb();
+ qusb_phy_enable_clocks(qphy, false);
+ } else { /* Cable disconnect case */
+ /* Disable all interrupts */
+ writel_relaxed(0x00,
+ qphy->base + qphy->phy_reg[INTR_CTRL]);
+ qusb_phy_reset(qphy);
+ qusb_phy_enable_clocks(qphy, false);
+ qusb_phy_disable_power(qphy);
+ }
+ qphy->suspended = true;
+ } else {
+ /* Bus resume case */
+ if (qphy->cable_connected) {
+ qusb_phy_enable_clocks(qphy, true);
+ /* Clear all interrupts on resume */
+ writel_relaxed(0x00,
+ qphy->base + qphy->phy_reg[INTR_CTRL]);
+
+ /* Reset PLL if needed */
+ if (!qusb_phy_pll_locked(qphy)) {
+ dev_dbg(phy->dev, "%s: reset PLL\n", __func__);
+ /* hold core PLL into reset */
+ writel_relaxed(CORE_PLL_EN_FROM_RESET |
+ CORE_RESET | CORE_RESET_MUX,
+ qphy->base +
+ qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
+
+ /* Wait for PLL to get reset */
+ usleep_range(10, 20);
+
+ /* bring core PLL out of reset */
+ writel_relaxed(CORE_PLL_EN_FROM_RESET,
+ qphy->base +
+ qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
+
+ /* Makes sure that above write goes through */
+ wmb();
+ }
+ } else { /* Cable connect case */
+ qusb_phy_enable_power(qphy);
+ qusb_phy_enable_clocks(qphy, true);
+ }
+ qphy->suspended = false;
+ }
+
+ return 0;
+}
+
+static int qusb_phy_notify_connect(struct usb_phy *phy,
+ enum usb_device_speed speed)
+{
+ struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
+
+ qphy->cable_connected = true;
+
+ dev_dbg(phy->dev, "QUSB PHY: connect notification cable_connected=%d\n",
+ qphy->cable_connected);
+ return 0;
+}
+
+static int qusb_phy_notify_disconnect(struct usb_phy *phy,
+ enum usb_device_speed speed)
+{
+ struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
+
+ qphy->cable_connected = false;
+
+ dev_dbg(phy->dev, "QUSB PHY: connect notification cable_connected=%d\n",
+ qphy->cable_connected);
+ return 0;
+}
+
+static int qusb_phy_dpdm_regulator_enable(struct regulator_dev *rdev)
+{
+ int ret = 0;
+ struct qusb_phy *qphy = rdev_get_drvdata(rdev);
+
+ dev_dbg(qphy->phy.dev, "%s dpdm_enable:%d\n",
+ __func__, qphy->dpdm_enable);
+
+ if (!qphy->dpdm_enable) {
+ ret = qusb_phy_enable_power(qphy);
+ if (ret < 0) {
+ dev_dbg(qphy->phy.dev,
+ "dpdm regulator enable failed:%d\n", ret);
+ return ret;
+ }
+ qphy->dpdm_enable = true;
+ qusb_phy_reset(qphy);
+ }
+
+ return ret;
+}
+
+static int qusb_phy_dpdm_regulator_disable(struct regulator_dev *rdev)
+{
+ int ret = 0;
+ struct qusb_phy *qphy = rdev_get_drvdata(rdev);
+
+ dev_dbg(qphy->phy.dev, "%s dpdm_enable:%d\n",
+ __func__, qphy->dpdm_enable);
+
+ if (qphy->dpdm_enable) {
+ ret = qusb_phy_disable_power(qphy);
+ if (ret < 0) {
+ dev_dbg(qphy->phy.dev,
+ "dpdm regulator disable failed:%d\n", ret);
+ return ret;
+ }
+ qphy->dpdm_enable = false;
+ }
+
+ return ret;
+}
+
+static int qusb_phy_dpdm_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct qusb_phy *qphy = rdev_get_drvdata(rdev);
+
+ dev_dbg(qphy->phy.dev, "%s qphy->dpdm_enable = %d\n", __func__,
+ qphy->dpdm_enable);
+ return qphy->dpdm_enable;
+}
+
+static struct regulator_ops qusb_phy_dpdm_regulator_ops = {
+ .enable = qusb_phy_dpdm_regulator_enable,
+ .disable = qusb_phy_dpdm_regulator_disable,
+ .is_enabled = qusb_phy_dpdm_regulator_is_enabled,
+};
+
+static int qusb_phy_regulator_init(struct qusb_phy *qphy)
+{
+ struct device *dev = qphy->phy.dev;
+ struct regulator_config cfg = {};
+ struct regulator_init_data *init_data;
+
+ init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
+ if (!init_data)
+ return -ENOMEM;
+
+ init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+ qphy->dpdm_rdesc.owner = THIS_MODULE;
+ qphy->dpdm_rdesc.type = REGULATOR_VOLTAGE;
+ qphy->dpdm_rdesc.ops = &qusb_phy_dpdm_regulator_ops;
+ qphy->dpdm_rdesc.name = kbasename(dev->of_node->full_name);
+
+ cfg.dev = dev;
+ cfg.init_data = init_data;
+ cfg.driver_data = qphy;
+ cfg.of_node = dev->of_node;
+
+ qphy->dpdm_rdev = devm_regulator_register(dev, &qphy->dpdm_rdesc, &cfg);
+
+ return PTR_ERR_OR_ZERO(qphy->dpdm_rdev);
+}
+
+static int qusb_phy_create_debugfs(struct qusb_phy *qphy)
+{
+ struct dentry *file;
+ int ret = 0, i;
+ char name[6];
+
+ qphy->root = debugfs_create_dir(dev_name(qphy->phy.dev), NULL);
+ if (IS_ERR_OR_NULL(qphy->root)) {
+ dev_err(qphy->phy.dev,
+ "can't create debugfs root for %s\n",
+ dev_name(qphy->phy.dev));
+ ret = -ENOMEM;
+ goto create_err;
+ }
+
+ for (i = 0; i < 5; i++) {
+ snprintf(name, sizeof(name), "tune%d", (i + 1));
+ file = debugfs_create_x8(name, 0644, qphy->root,
+ &qphy->tune[i]);
+ if (IS_ERR_OR_NULL(file)) {
+ dev_err(qphy->phy.dev,
+ "can't create debugfs entry for %s\n", name);
+ debugfs_remove_recursive(qphy->root);
+ ret = -ENOMEM;
+ goto create_err;
+ }
+ }
+
+ file = debugfs_create_x8("bias_ctrl2", 0644, qphy->root,
+ &qphy->bias_ctrl2);
+ if (IS_ERR_OR_NULL(file)) {
+ dev_err(qphy->phy.dev,
+ "can't create debugfs entry for bias_ctrl2\n");
+ debugfs_remove_recursive(qphy->root);
+ ret = -ENOMEM;
+ goto create_err;
+ }
+
+create_err:
+ return ret;
+}
+
+static int qusb_phy_probe(struct platform_device *pdev)
+{
+ struct qusb_phy *qphy;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret = 0, size = 0;
+
+ qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
+ if (!qphy)
+ return -ENOMEM;
+
+ qphy->phy.dev = dev;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "qusb_phy_base");
+ qphy->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(qphy->base))
+ return PTR_ERR(qphy->base);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "emu_phy_base");
+ if (res) {
+ qphy->emu_phy_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(qphy->emu_phy_base)) {
+ dev_dbg(dev, "couldn't ioremap emu_phy_base\n");
+ qphy->emu_phy_base = NULL;
+ }
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "efuse_addr");
+ if (res) {
+ qphy->efuse_reg = devm_ioremap_nocache(dev, res->start,
+ resource_size(res));
+ if (!IS_ERR_OR_NULL(qphy->efuse_reg)) {
+ ret = of_property_read_u32(dev->of_node,
+ "qcom,efuse-bit-pos",
+ &qphy->efuse_bit_pos);
+ if (!ret) {
+ ret = of_property_read_u32(dev->of_node,
+ "qcom,efuse-num-bits",
+ &qphy->efuse_num_of_bits);
+ }
+
+ if (ret) {
+ dev_err(dev,
+ "DT Value for efuse is invalid.\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "refgen_north_bg_reg_addr");
+ if (res)
+ qphy->refgen_north_bg_reg = devm_ioremap(dev, res->start,
+ resource_size(res));
+
+ /* ref_clk_src is needed irrespective of SE_CLK or DIFF_CLK usage */
+ qphy->ref_clk_src = devm_clk_get(dev, "ref_clk_src");
+ if (IS_ERR(qphy->ref_clk_src)) {
+ dev_dbg(dev, "clk get failed for ref_clk_src\n");
+ ret = PTR_ERR(qphy->ref_clk_src);
+ return ret;
+ }
+
+ /* ref_clk is needed only for DIFF_CLK case, hence make it optional. */
+ if (of_property_match_string(pdev->dev.of_node,
+ "clock-names", "ref_clk") >= 0) {
+ qphy->ref_clk = devm_clk_get(dev, "ref_clk");
+ if (IS_ERR(qphy->ref_clk)) {
+ ret = PTR_ERR(qphy->ref_clk);
+ if (ret != -EPROBE_DEFER)
+ dev_dbg(dev,
+ "clk get failed for ref_clk\n");
+ return ret;
+ }
+
+ clk_set_rate(qphy->ref_clk, 19200000);
+ }
+
+ if (of_property_match_string(pdev->dev.of_node,
+ "clock-names", "cfg_ahb_clk") >= 0) {
+ qphy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb_clk");
+ if (IS_ERR(qphy->cfg_ahb_clk)) {
+ ret = PTR_ERR(qphy->cfg_ahb_clk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev,
+ "clk get failed for cfg_ahb_clk ret %d\n", ret);
+ return ret;
+ }
+ }
+
+ qphy->phy_reset = devm_reset_control_get(dev, "phy_reset");
+ if (IS_ERR(qphy->phy_reset))
+ return PTR_ERR(qphy->phy_reset);
+
+ qphy->emulation = of_property_read_bool(dev->of_node,
+ "qcom,emulation");
+
+ of_get_property(dev->of_node, "qcom,emu-init-seq", &size);
+ if (size) {
+ qphy->emu_init_seq = devm_kzalloc(dev,
+ size, GFP_KERNEL);
+ if (qphy->emu_init_seq) {
+ qphy->emu_init_seq_len =
+ (size / sizeof(*qphy->emu_init_seq));
+ if (qphy->emu_init_seq_len % 2) {
+ dev_err(dev, "invalid emu_init_seq_len\n");
+ return -EINVAL;
+ }
+
+ of_property_read_u32_array(dev->of_node,
+ "qcom,emu-init-seq",
+ qphy->emu_init_seq,
+ qphy->emu_init_seq_len);
+ } else {
+ dev_dbg(dev,
+ "error allocating memory for emu_init_seq\n");
+ }
+ }
+
+ size = 0;
+ of_get_property(dev->of_node, "qcom,phy-pll-reset-seq", &size);
+ if (size) {
+ qphy->phy_pll_reset_seq = devm_kzalloc(dev,
+ size, GFP_KERNEL);
+ if (qphy->phy_pll_reset_seq) {
+ qphy->phy_pll_reset_seq_len =
+ (size / sizeof(*qphy->phy_pll_reset_seq));
+ if (qphy->phy_pll_reset_seq_len % 2) {
+ dev_err(dev, "invalid phy_pll_reset_seq_len\n");
+ return -EINVAL;
+ }
+
+ of_property_read_u32_array(dev->of_node,
+ "qcom,phy-pll-reset-seq",
+ qphy->phy_pll_reset_seq,
+ qphy->phy_pll_reset_seq_len);
+ } else {
+ dev_dbg(dev,
+ "error allocating memory for phy_pll_reset_seq\n");
+ }
+ }
+
+ size = 0;
+ of_get_property(dev->of_node, "qcom,emu-dcm-reset-seq", &size);
+ if (size) {
+ qphy->emu_dcm_reset_seq = devm_kzalloc(dev,
+ size, GFP_KERNEL);
+ if (qphy->emu_dcm_reset_seq) {
+ qphy->emu_dcm_reset_seq_len =
+ (size / sizeof(*qphy->emu_dcm_reset_seq));
+ if (qphy->emu_dcm_reset_seq_len % 2) {
+ dev_err(dev, "invalid emu_dcm_reset_seq_len\n");
+ return -EINVAL;
+ }
+
+ of_property_read_u32_array(dev->of_node,
+ "qcom,emu-dcm-reset-seq",
+ qphy->emu_dcm_reset_seq,
+ qphy->emu_dcm_reset_seq_len);
+ } else {
+ dev_dbg(dev,
+ "error allocating memory for emu_dcm_reset_seq\n");
+ }
+ }
+
+ size = 0;
+ of_get_property(dev->of_node, "qcom,qusb-phy-reg-offset", &size);
+ if (size) {
+ qphy->phy_reg = devm_kzalloc(dev, size, GFP_KERNEL);
+ if (qphy->phy_reg) {
+ qphy->qusb_phy_reg_offset_cnt =
+ size / sizeof(*qphy->phy_reg);
+ if (qphy->qusb_phy_reg_offset_cnt != USB2_PHY_REG_MAX) {
+ dev_err(dev, "invalid reg offset count\n");
+ return -EINVAL;
+ }
+
+ of_property_read_u32_array(dev->of_node,
+ "qcom,qusb-phy-reg-offset",
+ qphy->phy_reg,
+ qphy->qusb_phy_reg_offset_cnt);
+ } else {
+ dev_err(dev, "err mem alloc for qusb_phy_reg_offset\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_err(dev, "err provide qcom,qmp-phy-reg-offset\n");
+ return -EINVAL;
+ }
+
+ size = 0;
+ of_get_property(dev->of_node, "qcom,qusb-phy-init-seq", &size);
+ if (size) {
+ qphy->qusb_phy_init_seq = devm_kzalloc(dev,
+ size, GFP_KERNEL);
+ if (qphy->qusb_phy_init_seq) {
+ qphy->init_seq_len =
+ (size / sizeof(*qphy->qusb_phy_init_seq));
+ if (qphy->init_seq_len % 2) {
+ dev_err(dev, "invalid init_seq_len\n");
+ return -EINVAL;
+ }
+
+ of_property_read_u32_array(dev->of_node,
+ "qcom,qusb-phy-init-seq",
+ qphy->qusb_phy_init_seq,
+ qphy->init_seq_len);
+ } else {
+ dev_err(dev,
+ "error allocating memory for phy_init_seq\n");
+ }
+ }
+
+ qphy->host_init_seq_len = of_property_count_elems_of_size(dev->of_node,
+ "qcom,qusb-phy-host-init-seq",
+ sizeof(*qphy->qusb_phy_host_init_seq));
+ if (qphy->host_init_seq_len > 0) {
+ qphy->qusb_phy_host_init_seq = devm_kcalloc(dev,
+ qphy->host_init_seq_len,
+ sizeof(*qphy->qusb_phy_host_init_seq),
+ GFP_KERNEL);
+ if (qphy->qusb_phy_host_init_seq)
+ of_property_read_u32_array(dev->of_node,
+ "qcom,qusb-phy-host-init-seq",
+ qphy->qusb_phy_host_init_seq,
+ qphy->host_init_seq_len);
+ else
+ return -ENOMEM;
+ }
+
+ qphy->override_bias_ctrl2 = of_property_read_bool(dev->of_node,
+ "qcom,override-bias-ctrl2");
+
+ ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level",
+ (u32 *) qphy->vdd_levels,
+ ARRAY_SIZE(qphy->vdd_levels));
+ if (ret) {
+ dev_err(dev, "error reading qcom,vdd-voltage-level property\n");
+ return ret;
+ }
+
+ qphy->vdd = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(qphy->vdd)) {
+ dev_err(dev, "unable to get vdd supply\n");
+ return PTR_ERR(qphy->vdd);
+ }
+
+ qphy->vdda33 = devm_regulator_get(dev, "vdda33");
+ if (IS_ERR(qphy->vdda33)) {
+ dev_err(dev, "unable to get vdda33 supply\n");
+ return PTR_ERR(qphy->vdda33);
+ }
+
+ qphy->vdda18 = devm_regulator_get(dev, "vdda18");
+ if (IS_ERR(qphy->vdda18)) {
+ dev_err(dev, "unable to get vdda18 supply\n");
+ return PTR_ERR(qphy->vdda18);
+ }
+
+ mutex_init(&qphy->lock);
+ platform_set_drvdata(pdev, qphy);
+
+ qphy->phy.label = "msm-qusb-phy-v2";
+ qphy->phy.init = qusb_phy_init;
+ qphy->phy.set_suspend = qusb_phy_set_suspend;
+ qphy->phy.shutdown = qusb_phy_shutdown;
+ qphy->phy.type = USB_PHY_TYPE_USB2;
+ qphy->phy.notify_connect = qusb_phy_notify_connect;
+ qphy->phy.notify_disconnect = qusb_phy_notify_disconnect;
+
+ ret = usb_add_phy_dev(&qphy->phy);
+ if (ret)
+ return ret;
+
+ ret = qusb_phy_regulator_init(qphy);
+ if (ret)
+ usb_remove_phy(&qphy->phy);
+
+ qphy->suspended = true;
+ qusb_phy_create_debugfs(qphy);
+
+ return ret;
+}
+
+static int qusb_phy_remove(struct platform_device *pdev)
+{
+ struct qusb_phy *qphy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&qphy->phy);
+ qphy->cable_connected = false;
+ qusb_phy_set_suspend(&qphy->phy, true);
+ debugfs_remove_recursive(qphy->root);
+
+ return 0;
+}
+
+static const struct of_device_id qusb_phy_id_table[] = {
+ { .compatible = "qcom,qusb2phy-v2", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qusb_phy_id_table);
+
+static struct platform_driver qusb_phy_driver = {
+ .probe = qusb_phy_probe,
+ .remove = qusb_phy_remove,
+ .driver = {
+ .name = "msm-qusb-phy-v2",
+ .of_match_table = of_match_ptr(qusb_phy_id_table),
+ },
+};
+
+module_platform_driver(qusb_phy_driver);
+
+MODULE_DESCRIPTION("MSM QUSB2 PHY v2 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c
index 974231c..818c5a0 100644
--- a/drivers/usb/phy/phy-msm-snps-hs.c
+++ b/drivers/usb/phy/phy-msm-snps-hs.c
@@ -615,6 +615,7 @@ static int msm_hsphy_dpdm_regulator_enable(struct regulator_dev *rdev)
UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN,
UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN);
+ msm_hsphy_enable_clocks(phy, false);
phy->dpdm_enable = true;
}
mutex_unlock(&phy->phy_lock);
@@ -633,7 +634,6 @@ static int msm_hsphy_dpdm_regulator_disable(struct regulator_dev *rdev)
mutex_lock(&phy->phy_lock);
if (phy->dpdm_enable) {
if (!phy->cable_connected) {
- msm_hsphy_enable_clocks(phy, false);
ret = msm_hsphy_enable_power(phy, false);
if (ret < 0) {
mutex_unlock(&phy->phy_lock);
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index c47b721..63a75fd 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -157,11 +157,12 @@ struct usbhs_priv;
#define VBSTS (1 << 7) /* VBUS_0 and VBUSIN_0 Input Status */
#define VALID (1 << 3) /* USB Request Receive */
-#define DVSQ_MASK (0x3 << 4) /* Device State */
+#define DVSQ_MASK (0x7 << 4) /* Device State */
#define POWER_STATE (0 << 4)
#define DEFAULT_STATE (1 << 4)
#define ADDRESS_STATE (2 << 4)
#define CONFIGURATION_STATE (3 << 4)
+#define SUSPENDED_STATE (4 << 4)
#define CTSQ_MASK (0x7) /* Control Transfer Stage */
#define IDLE_SETUP_STAGE 0 /* Idle stage or setup stage */
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 7feac41..f36248e 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -456,12 +456,18 @@ static int usbhsg_irq_dev_state(struct usbhs_priv *priv,
{
struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
struct device *dev = usbhsg_gpriv_to_dev(gpriv);
+ int state = usbhs_status_get_device_state(irq_state);
gpriv->gadget.speed = usbhs_bus_get_speed(priv);
- dev_dbg(dev, "state = %x : speed : %d\n",
- usbhs_status_get_device_state(irq_state),
- gpriv->gadget.speed);
+ dev_dbg(dev, "state = %x : speed : %d\n", state, gpriv->gadget.speed);
+
+ if (gpriv->gadget.speed != USB_SPEED_UNKNOWN &&
+ (state & SUSPENDED_STATE)) {
+ if (gpriv->driver && gpriv->driver->suspend)
+ gpriv->driver->suspend(&gpriv->gadget);
+ usb_gadget_set_state(&gpriv->gadget, USB_STATE_SUSPENDED);
+ }
return 0;
}
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 2905274..553adab 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1172,6 +1172,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = NCTRL(0) | RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */
.driver_info = NCTRL(0) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x110a, 0xff), /* Telit ME910G1 */
+ .driver_info = NCTRL(0) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),
diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c
index d88a5b1..88eaf3c 100644
--- a/drivers/usb/usbip/usbip_common.c
+++ b/drivers/usb/usbip/usbip_common.c
@@ -727,6 +727,9 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
copy -= recv;
ret += recv;
+
+ if (!copy)
+ break;
}
if (ret != size)
diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c
index 33f8972..00fc987 100644
--- a/drivers/usb/usbip/vhci_rx.c
+++ b/drivers/usb/usbip/vhci_rx.c
@@ -77,16 +77,21 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
usbip_pack_pdu(pdu, urb, USBIP_RET_SUBMIT, 0);
/* recv transfer buffer */
- if (usbip_recv_xbuff(ud, urb) < 0)
- return;
+ if (usbip_recv_xbuff(ud, urb) < 0) {
+ urb->status = -EPROTO;
+ goto error;
+ }
/* recv iso_packet_descriptor */
- if (usbip_recv_iso(ud, urb) < 0)
- return;
+ if (usbip_recv_iso(ud, urb) < 0) {
+ urb->status = -EPROTO;
+ goto error;
+ }
/* restore the padding in iso packets */
usbip_pad_iso(ud, urb);
+error:
if (usbip_dbg_flag_vhci_rx)
usbip_dump_urb(urb);
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 8dcee4f..5f5c5de 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -436,7 +436,9 @@ static void vhost_vsock_handle_tx_kick(struct vhost_work *work)
virtio_transport_deliver_tap_pkt(pkt);
/* Only accept correctly addressed packets */
- if (le64_to_cpu(pkt->hdr.src_cid) == vsock->guest_cid)
+ if (le64_to_cpu(pkt->hdr.src_cid) == vsock->guest_cid &&
+ le64_to_cpu(pkt->hdr.dst_cid) ==
+ vhost_transport_get_local_cid())
virtio_transport_recv_pkt(pkt);
else
virtio_transport_free_pkt(pkt);
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index f6c24b2..4b89333 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -38,7 +38,6 @@
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/hrtimer.h> /* For hrtimers */
#include <linux/kernel.h> /* For printk/panic/... */
-#include <linux/kref.h> /* For data references */
#include <linux/kthread.h> /* For kthread_work */
#include <linux/miscdevice.h> /* For handling misc devices */
#include <linux/module.h> /* For module stuff/... */
@@ -56,14 +55,14 @@
/*
* struct watchdog_core_data - watchdog core internal data
- * @kref: Reference count.
+ * @dev: The watchdog's internal device
* @cdev: The watchdog's Character device.
* @wdd: Pointer to watchdog device.
* @lock: Lock for watchdog core.
* @status: Watchdog core internal status bits.
*/
struct watchdog_core_data {
- struct kref kref;
+ struct device dev;
struct cdev cdev;
struct watchdog_device *wdd;
struct mutex lock;
@@ -822,7 +821,7 @@ static int watchdog_open(struct inode *inode, struct file *file)
file->private_data = wd_data;
if (!hw_running)
- kref_get(&wd_data->kref);
+ get_device(&wd_data->dev);
/* dev/watchdog is a virtual (and thus non-seekable) filesystem */
return nonseekable_open(inode, file);
@@ -834,11 +833,11 @@ static int watchdog_open(struct inode *inode, struct file *file)
return err;
}
-static void watchdog_core_data_release(struct kref *kref)
+static void watchdog_core_data_release(struct device *dev)
{
struct watchdog_core_data *wd_data;
- wd_data = container_of(kref, struct watchdog_core_data, kref);
+ wd_data = container_of(dev, struct watchdog_core_data, dev);
kfree(wd_data);
}
@@ -898,7 +897,7 @@ static int watchdog_release(struct inode *inode, struct file *file)
*/
if (!running) {
module_put(wd_data->cdev.owner);
- kref_put(&wd_data->kref, watchdog_core_data_release);
+ put_device(&wd_data->dev);
}
return 0;
}
@@ -917,17 +916,22 @@ static struct miscdevice watchdog_miscdev = {
.fops = &watchdog_fops,
};
+static struct class watchdog_class = {
+ .name = "watchdog",
+ .owner = THIS_MODULE,
+ .dev_groups = wdt_groups,
+};
+
/*
* watchdog_cdev_register: register watchdog character device
* @wdd: watchdog device
- * @devno: character device number
*
* Register a watchdog character device including handling the legacy
* /dev/watchdog node. /dev/watchdog is actually a miscdevice and
* thus we set it up like that.
*/
-static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
+static int watchdog_cdev_register(struct watchdog_device *wdd)
{
struct watchdog_core_data *wd_data;
int err;
@@ -935,7 +939,6 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
wd_data = kzalloc(sizeof(struct watchdog_core_data), GFP_KERNEL);
if (!wd_data)
return -ENOMEM;
- kref_init(&wd_data->kref);
mutex_init(&wd_data->lock);
wd_data->wdd = wdd;
@@ -964,23 +967,33 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
}
}
+ device_initialize(&wd_data->dev);
+ wd_data->dev.devt = MKDEV(MAJOR(watchdog_devt), wdd->id);
+ wd_data->dev.class = &watchdog_class;
+ wd_data->dev.parent = wdd->parent;
+ wd_data->dev.groups = wdd->groups;
+ wd_data->dev.release = watchdog_core_data_release;
+ dev_set_drvdata(&wd_data->dev, wdd);
+ dev_set_name(&wd_data->dev, "watchdog%d", wdd->id);
+
/* Fill in the data structures */
cdev_init(&wd_data->cdev, &watchdog_fops);
- wd_data->cdev.owner = wdd->ops->owner;
/* Add the device */
- err = cdev_add(&wd_data->cdev, devno, 1);
+ err = cdev_device_add(&wd_data->cdev, &wd_data->dev);
if (err) {
pr_err("watchdog%d unable to add device %d:%d\n",
wdd->id, MAJOR(watchdog_devt), wdd->id);
if (wdd->id == 0) {
misc_deregister(&watchdog_miscdev);
old_wd_data = NULL;
- kref_put(&wd_data->kref, watchdog_core_data_release);
+ put_device(&wd_data->dev);
}
return err;
}
+ wd_data->cdev.owner = wdd->ops->owner;
+
/* Record time of most recent heartbeat as 'just before now'. */
wd_data->last_hw_keepalive = ktime_sub(ktime_get(), 1);
@@ -990,7 +1003,7 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
*/
if (watchdog_hw_running(wdd)) {
__module_get(wdd->ops->owner);
- kref_get(&wd_data->kref);
+ get_device(&wd_data->dev);
if (handle_boot_enabled)
hrtimer_start(&wd_data->timer, 0, HRTIMER_MODE_REL);
else
@@ -1013,7 +1026,7 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
{
struct watchdog_core_data *wd_data = wdd->wd_data;
- cdev_del(&wd_data->cdev);
+ cdev_device_del(&wd_data->cdev, &wd_data->dev);
if (wdd->id == 0) {
misc_deregister(&watchdog_miscdev);
old_wd_data = NULL;
@@ -1032,15 +1045,9 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
hrtimer_cancel(&wd_data->timer);
kthread_cancel_work_sync(&wd_data->work);
- kref_put(&wd_data->kref, watchdog_core_data_release);
+ put_device(&wd_data->dev);
}
-static struct class watchdog_class = {
- .name = "watchdog",
- .owner = THIS_MODULE,
- .dev_groups = wdt_groups,
-};
-
static int watchdog_reboot_notifier(struct notifier_block *nb,
unsigned long code, void *data)
{
@@ -1071,27 +1078,14 @@ static int watchdog_reboot_notifier(struct notifier_block *nb,
int watchdog_dev_register(struct watchdog_device *wdd)
{
- struct device *dev;
- dev_t devno;
int ret;
- devno = MKDEV(MAJOR(watchdog_devt), wdd->id);
-
- ret = watchdog_cdev_register(wdd, devno);
+ ret = watchdog_cdev_register(wdd);
if (ret)
return ret;
- dev = device_create_with_groups(&watchdog_class, wdd->parent,
- devno, wdd, wdd->groups,
- "watchdog%d", wdd->id);
- if (IS_ERR(dev)) {
- watchdog_cdev_unregister(wdd);
- return PTR_ERR(dev);
- }
-
ret = watchdog_register_pretimeout(wdd);
if (ret) {
- device_destroy(&watchdog_class, devno);
watchdog_cdev_unregister(wdd);
return ret;
}
@@ -1099,7 +1093,8 @@ int watchdog_dev_register(struct watchdog_device *wdd)
if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) {
wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
- ret = devm_register_reboot_notifier(dev, &wdd->reboot_nb);
+ ret = devm_register_reboot_notifier(&wdd->wd_data->dev,
+ &wdd->reboot_nb);
if (ret) {
pr_err("watchdog%d: Cannot register reboot notifier (%d)\n",
wdd->id, ret);
@@ -1121,7 +1116,6 @@ int watchdog_dev_register(struct watchdog_device *wdd)
void watchdog_dev_unregister(struct watchdog_device *wdd)
{
watchdog_unregister_pretimeout(wdd);
- device_destroy(&watchdog_class, wdd->wd_data->cdev.dev);
watchdog_cdev_unregister(wdd);
}
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 90d387b..0505eeb 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -158,7 +158,8 @@
config XEN_GNTDEV_DMABUF
bool "Add support for dma-buf grant access device driver extension"
- depends on XEN_GNTDEV && XEN_GRANT_DMA_ALLOC && DMA_SHARED_BUFFER
+ depends on XEN_GNTDEV && XEN_GRANT_DMA_ALLOC
+ select DMA_SHARED_BUFFER
help
Allows userspace processes and kernel modules to use Xen backed
dma-buf implementation. With this extension grant references to
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 747a15a..6fa7209 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -395,7 +395,8 @@ static struct notifier_block xen_memory_nb = {
#else
static enum bp_state reserve_additional_memory(void)
{
- balloon_stats.target_pages = balloon_stats.current_pages;
+ balloon_stats.target_pages = balloon_stats.current_pages +
+ balloon_stats.target_unpopulated;
return BP_ECANCELED;
}
#endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */
diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c
index f29c6da..069273a 100644
--- a/fs/afs/dynroot.c
+++ b/fs/afs/dynroot.c
@@ -145,6 +145,9 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr
ASSERTCMP(d_inode(dentry), ==, NULL);
+ if (flags & LOOKUP_CREATE)
+ return ERR_PTR(-EOPNOTSUPP);
+
if (dentry->d_name.len >= AFSNAMEMAX) {
_leave(" = -ENAMETOOLONG");
return ERR_PTR(-ENAMETOOLONG);
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 1d329e6..2c7f621 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -34,18 +34,11 @@ static void afs_dec_servers_outstanding(struct afs_net *net)
struct afs_server *afs_find_server(struct afs_net *net,
const struct sockaddr_rxrpc *srx)
{
- const struct sockaddr_in6 *a = &srx->transport.sin6, *b;
const struct afs_addr_list *alist;
struct afs_server *server = NULL;
unsigned int i;
- bool ipv6 = true;
int seq = 0, diff;
- if (srx->transport.sin6.sin6_addr.s6_addr32[0] == 0 ||
- srx->transport.sin6.sin6_addr.s6_addr32[1] == 0 ||
- srx->transport.sin6.sin6_addr.s6_addr32[2] == htonl(0xffff))
- ipv6 = false;
-
rcu_read_lock();
do {
@@ -54,7 +47,8 @@ struct afs_server *afs_find_server(struct afs_net *net,
server = NULL;
read_seqbegin_or_lock(&net->fs_addr_lock, &seq);
- if (ipv6) {
+ if (srx->transport.family == AF_INET6) {
+ const struct sockaddr_in6 *a = &srx->transport.sin6, *b;
hlist_for_each_entry_rcu(server, &net->fs_addresses6, addr6_link) {
alist = rcu_dereference(server->addresses);
for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
@@ -70,15 +64,16 @@ struct afs_server *afs_find_server(struct afs_net *net,
}
}
} else {
+ const struct sockaddr_in *a = &srx->transport.sin, *b;
hlist_for_each_entry_rcu(server, &net->fs_addresses4, addr4_link) {
alist = rcu_dereference(server->addresses);
for (i = 0; i < alist->nr_ipv4; i++) {
- b = &alist->addrs[i].transport.sin6;
- diff = ((u16 __force)a->sin6_port -
- (u16 __force)b->sin6_port);
+ b = &alist->addrs[i].transport.sin;
+ diff = ((u16 __force)a->sin_port -
+ (u16 __force)b->sin_port);
if (diff == 0)
- diff = ((u32 __force)a->sin6_addr.s6_addr32[3] -
- (u32 __force)b->sin6_addr.s6_addr32[3]);
+ diff = ((u32 __force)a->sin_addr.s_addr -
+ (u32 __force)b->sin_addr.s_addr);
if (diff == 0)
goto found;
}
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 4d3e274..bd26082 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -404,7 +404,6 @@ static int afs_fill_super(struct super_block *sb,
/* allocate the root inode and dentry */
if (as->dyn_root) {
inode = afs_iget_pseudo_dir(sb, true);
- sb->s_flags |= SB_RDONLY;
} else {
sprintf(sb->s_id, "%u", as->volume->vid);
afs_activate_volume(as->volume);
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 1c25dae..c158bad 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1328,11 +1328,7 @@ static void flush_disk(struct block_device *bdev, bool kill_dirty)
"resized disk %s\n",
bdev->bd_disk ? bdev->bd_disk->disk_name : "");
}
-
- if (!bdev->bd_disk)
- return;
- if (disk_part_scan_enabled(bdev->bd_disk))
- bdev->bd_invalidated = 1;
+ bdev->bd_invalidated = 1;
}
/**
@@ -1430,6 +1426,19 @@ EXPORT_SYMBOL(bd_set_size);
static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part);
+static void bdev_disk_changed(struct block_device *bdev, bool invalidate)
+{
+ if (disk_part_scan_enabled(bdev->bd_disk)) {
+ if (invalidate)
+ invalidate_partitions(bdev->bd_disk, bdev);
+ else
+ rescan_partitions(bdev->bd_disk, bdev);
+ } else {
+ check_disk_size_change(bdev->bd_disk, bdev, !invalidate);
+ bdev->bd_invalidated = 0;
+ }
+}
+
/*
* bd_mutex locking:
*
@@ -1512,12 +1521,9 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
* The latter is necessary to prevent ghost
* partitions on a removed medium.
*/
- if (bdev->bd_invalidated) {
- if (!ret)
- rescan_partitions(disk, bdev);
- else if (ret == -ENOMEDIUM)
- invalidate_partitions(disk, bdev);
- }
+ if (bdev->bd_invalidated &&
+ (!ret || ret == -ENOMEDIUM))
+ bdev_disk_changed(bdev, ret == -ENOMEDIUM);
if (ret)
goto out_clear;
@@ -1550,12 +1556,9 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
if (bdev->bd_disk->fops->open)
ret = bdev->bd_disk->fops->open(bdev, mode);
/* the same as first opener case, read comment there */
- if (bdev->bd_invalidated) {
- if (!ret)
- rescan_partitions(bdev->bd_disk, bdev);
- else if (ret == -ENOMEDIUM)
- invalidate_partitions(bdev->bd_disk, bdev);
- }
+ if (bdev->bd_invalidated &&
+ (!ret || ret == -ENOMEDIUM))
+ bdev_disk_changed(bdev, ret == -ENOMEDIUM);
if (ret)
goto out_unlock_bdev;
}
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c
index d522494..02e4e903 100644
--- a/fs/btrfs/async-thread.c
+++ b/fs/btrfs/async-thread.c
@@ -252,16 +252,17 @@ static inline void thresh_exec_hook(struct __btrfs_workqueue *wq)
}
}
-static void run_ordered_work(struct __btrfs_workqueue *wq)
+static void run_ordered_work(struct __btrfs_workqueue *wq,
+ struct btrfs_work *self)
{
struct list_head *list = &wq->ordered_list;
struct btrfs_work *work;
spinlock_t *lock = &wq->list_lock;
unsigned long flags;
+ void *wtag;
+ bool free_self = false;
while (1) {
- void *wtag;
-
spin_lock_irqsave(lock, flags);
if (list_empty(list))
break;
@@ -287,16 +288,47 @@ static void run_ordered_work(struct __btrfs_workqueue *wq)
list_del(&work->ordered_list);
spin_unlock_irqrestore(lock, flags);
- /*
- * We don't want to call the ordered free functions with the
- * lock held though. Save the work as tag for the trace event,
- * because the callback could free the structure.
- */
- wtag = work;
- work->ordered_free(work);
- trace_btrfs_all_work_done(wq->fs_info, wtag);
+ if (work == self) {
+ /*
+ * This is the work item that the worker is currently
+ * executing.
+ *
+ * The kernel workqueue code guarantees non-reentrancy
+ * of work items. I.e., if a work item with the same
+ * address and work function is queued twice, the second
+ * execution is blocked until the first one finishes. A
+ * work item may be freed and recycled with the same
+ * work function; the workqueue code assumes that the
+ * original work item cannot depend on the recycled work
+ * item in that case (see find_worker_executing_work()).
+ *
+ * Note that the work of one Btrfs filesystem may depend
+ * on the work of another Btrfs filesystem via, e.g., a
+ * loop device. Therefore, we must not allow the current
+ * work item to be recycled until we are really done,
+ * otherwise we break the above assumption and can
+ * deadlock.
+ */
+ free_self = true;
+ } else {
+ /*
+ * We don't want to call the ordered free functions with
+ * the lock held though. Save the work as tag for the
+ * trace event, because the callback could free the
+ * structure.
+ */
+ wtag = work;
+ work->ordered_free(work);
+ trace_btrfs_all_work_done(wq->fs_info, wtag);
+ }
}
spin_unlock_irqrestore(lock, flags);
+
+ if (free_self) {
+ wtag = self;
+ self->ordered_free(self);
+ trace_btrfs_all_work_done(wq->fs_info, wtag);
+ }
}
static void normal_work_helper(struct btrfs_work *work)
@@ -324,7 +356,7 @@ static void normal_work_helper(struct btrfs_work *work)
work->func(work);
if (need_order) {
set_bit(WORK_DONE_BIT, &work->flags);
- run_ordered_work(wq);
+ run_ordered_work(wq, work);
}
if (!need_order)
trace_btrfs_all_work_done(wq->fs_info, wtag);
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index fc764f3..84ff398 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -390,7 +390,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,
for (node = rb_first(tm_root); node; node = next) {
next = rb_next(node);
tm = rb_entry(node, struct tree_mod_elem, node);
- if (tm->seq > min_seq)
+ if (tm->seq >= min_seq)
continue;
rb_erase(node, tm_root);
kfree(tm);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index cc2d268..d24ecbf 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3101,7 +3101,7 @@ int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,
/* file-item.c */
struct btrfs_dio_private;
int btrfs_del_csums(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 bytenr, u64 len);
+ struct btrfs_root *root, u64 bytenr, u64 len);
blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u32 *dst);
blk_status_t btrfs_lookup_bio_sums_dio(struct inode *inode, struct bio *bio,
u64 logical_offset);
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 96296dc..e12c37f 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1660,8 +1660,8 @@ static void end_workqueue_fn(struct btrfs_work *work)
bio->bi_status = end_io_wq->status;
bio->bi_private = end_io_wq->private;
bio->bi_end_io = end_io_wq->end_io;
- kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq);
bio_endio(bio);
+ kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq);
}
static int cleaner_kthread(void *arg)
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 4bda5c0..47ca1eb 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2492,8 +2492,8 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans,
btrfs_pin_extent(fs_info, head->bytenr,
head->num_bytes, 1);
if (head->is_data) {
- ret = btrfs_del_csums(trans, fs_info, head->bytenr,
- head->num_bytes);
+ ret = btrfs_del_csums(trans, fs_info->csum_root,
+ head->bytenr, head->num_bytes);
}
}
@@ -6880,7 +6880,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
btrfs_release_path(path);
if (is_data) {
- ret = btrfs_del_csums(trans, info, bytenr, num_bytes);
+ ret = btrfs_del_csums(trans, info->csum_root, bytenr,
+ num_bytes);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto out;
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 88fc5a0..fed4439 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -4888,12 +4888,14 @@ struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info,
return eb;
eb = alloc_dummy_extent_buffer(fs_info, start);
if (!eb)
- return NULL;
+ return ERR_PTR(-ENOMEM);
eb->fs_info = fs_info;
again:
ret = radix_tree_preload(GFP_NOFS);
- if (ret)
+ if (ret) {
+ exists = ERR_PTR(ret);
goto free_eb;
+ }
spin_lock(&fs_info->buffer_lock);
ret = radix_tree_insert(&fs_info->buffer_radix,
start >> PAGE_SHIFT, eb);
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index ba74827..4cf2817 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -577,9 +577,9 @@ static noinline void truncate_one_csum(struct btrfs_fs_info *fs_info,
* range of bytes.
*/
int btrfs_del_csums(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 bytenr, u64 len)
+ struct btrfs_root *root, u64 bytenr, u64 len)
{
- struct btrfs_root *root = fs_info->csum_root;
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_path *path;
struct btrfs_key key;
u64 end_byte = bytenr + len;
@@ -589,6 +589,9 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
int blocksize_bits = fs_info->sb->s_blocksize_bits;
+ ASSERT(root == fs_info->csum_root ||
+ root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID);
+
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 7fd4458..70085e9 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5665,7 +5665,6 @@ static void inode_tree_add(struct inode *inode)
static void inode_tree_del(struct inode *inode)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
struct btrfs_root *root = BTRFS_I(inode)->root;
int empty = 0;
@@ -5678,7 +5677,6 @@ static void inode_tree_del(struct inode *inode)
spin_unlock(&root->inode_lock);
if (empty && btrfs_root_refs(&root->root_item) == 0) {
- synchronize_srcu(&fs_info->subvol_srcu);
spin_lock(&root->inode_lock);
empty = RB_EMPTY_ROOT(&root->inode_tree);
spin_unlock(&root->inode_lock);
@@ -9491,9 +9489,8 @@ static int btrfs_rename_exchange(struct inode *old_dir,
btrfs_init_log_ctx(&ctx_dest, new_inode);
/* close the race window with snapshot create/destroy ioctl */
- if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
- down_read(&fs_info->subvol_sem);
- if (new_ino == BTRFS_FIRST_FREE_OBJECTID)
+ if (old_ino == BTRFS_FIRST_FREE_OBJECTID ||
+ new_ino == BTRFS_FIRST_FREE_OBJECTID)
down_read(&fs_info->subvol_sem);
/*
@@ -9727,9 +9724,8 @@ static int btrfs_rename_exchange(struct inode *old_dir,
ret = ret ? ret : ret2;
}
out_notrans:
- if (new_ino == BTRFS_FIRST_FREE_OBJECTID)
- up_read(&fs_info->subvol_sem);
- if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
+ if (new_ino == BTRFS_FIRST_FREE_OBJECTID ||
+ old_ino == BTRFS_FIRST_FREE_OBJECTID)
up_read(&fs_info->subvol_sem);
ASSERT(list_empty(&ctx_root.list));
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 00ff434..199c70b 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -709,11 +709,17 @@ static noinline int create_subvol(struct inode *dir,
btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
ret = btrfs_update_inode(trans, root, dir);
- BUG_ON(ret);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ goto fail;
+ }
ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
btrfs_ino(BTRFS_I(dir)), index, name, namelen);
- BUG_ON(ret);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ goto fail;
+ }
ret = btrfs_uuid_tree_add(trans, root_item->uuid,
BTRFS_UUID_KEY_SUBVOL, objectid);
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index cdd6d50..7916f71 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -2862,12 +2862,12 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
if (!(fs_info->qgroup_flags &
BTRFS_QGROUP_STATUS_FLAG_RESCAN)) {
btrfs_warn(fs_info,
- "qgroup rescan init failed, qgroup is not enabled");
+ "qgroup rescan init failed, qgroup rescan is not queued");
ret = -EINVAL;
} else if (!(fs_info->qgroup_flags &
BTRFS_QGROUP_STATUS_FLAG_ON)) {
btrfs_warn(fs_info,
- "qgroup rescan init failed, qgroup rescan is not queued");
+ "qgroup rescan init failed, qgroup is not enabled");
ret = -EINVAL;
}
diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c
index 859274e..4c81ffe 100644
--- a/fs/btrfs/reada.c
+++ b/fs/btrfs/reada.c
@@ -720,21 +720,19 @@ static int reada_start_machine_dev(struct btrfs_device *dev)
static void reada_start_machine_worker(struct btrfs_work *work)
{
struct reada_machine_work *rmw;
- struct btrfs_fs_info *fs_info;
int old_ioprio;
rmw = container_of(work, struct reada_machine_work, work);
- fs_info = rmw->fs_info;
-
- kfree(rmw);
old_ioprio = IOPRIO_PRIO_VALUE(task_nice_ioclass(current),
task_nice_ioprio(current));
set_task_ioprio(current, BTRFS_IOPRIO_READA);
- __reada_start_machine(fs_info);
+ __reada_start_machine(rmw->fs_info);
set_task_ioprio(current, old_ioprio);
- atomic_dec(&fs_info->reada_works_cnt);
+ atomic_dec(&rmw->fs_info->reada_works_cnt);
+
+ kfree(rmw);
}
static void __reada_start_machine(struct btrfs_fs_info *fs_info)
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index b4958f72..f989130 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -4474,6 +4474,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
fs_root = read_fs_root(fs_info, reloc_root->root_key.offset);
if (IS_ERR(fs_root)) {
err = PTR_ERR(fs_root);
+ list_add_tail(&reloc_root->root_list, &reloc_roots);
goto out_free;
}
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 916c397..6b6008d 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -2145,14 +2145,13 @@ static void scrub_missing_raid56_worker(struct btrfs_work *work)
scrub_write_block_to_dev_replace(sblock);
}
- scrub_block_put(sblock);
-
if (sctx->is_dev_replace && sctx->flush_all_writes) {
mutex_lock(&sctx->wr_lock);
scrub_wr_submit(sctx);
mutex_unlock(&sctx->wr_lock);
}
+ scrub_block_put(sblock);
scrub_pending_bio_dec(sctx);
}
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 1053246..931a7d1 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -6639,12 +6639,6 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg)
spin_unlock(&send_root->root_item_lock);
/*
- * This is done when we lookup the root, it should already be complete
- * by the time we get here.
- */
- WARN_ON(send_root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE);
-
- /*
* Userspace tools do the checks and warn the user if it's
* not RO.
*/
diff --git a/fs/btrfs/tests/free-space-tree-tests.c b/fs/btrfs/tests/free-space-tree-tests.c
index 89346da..de8fef9 100644
--- a/fs/btrfs/tests/free-space-tree-tests.c
+++ b/fs/btrfs/tests/free-space-tree-tests.c
@@ -462,9 +462,9 @@ static int run_test(test_func_t test_func, int bitmaps, u32 sectorsize,
root->fs_info->tree_root = root;
root->node = alloc_test_extent_buffer(root->fs_info, nodesize);
- if (!root->node) {
+ if (IS_ERR(root->node)) {
test_err("couldn't allocate dummy buffer");
- ret = -ENOMEM;
+ ret = PTR_ERR(root->node);
goto out;
}
btrfs_set_header_level(root->node, 0);
diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c
index 412b910..d07dd26 100644
--- a/fs/btrfs/tests/qgroup-tests.c
+++ b/fs/btrfs/tests/qgroup-tests.c
@@ -484,9 +484,9 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
* *cough*backref walking code*cough*
*/
root->node = alloc_test_extent_buffer(root->fs_info, nodesize);
- if (!root->node) {
+ if (IS_ERR(root->node)) {
test_err("couldn't allocate dummy buffer");
- ret = -ENOMEM;
+ ret = PTR_ERR(root->node);
goto out;
}
btrfs_set_header_level(root->node, 0);
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 4d4f57f..fe7165c 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -795,7 +795,8 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
struct btrfs_ordered_sum,
list);
if (!ret)
- ret = btrfs_del_csums(trans, fs_info,
+ ret = btrfs_del_csums(trans,
+ fs_info->csum_root,
sums->bytenr,
sums->len);
if (!ret)
@@ -3866,6 +3867,28 @@ static int log_inode_item(struct btrfs_trans_handle *trans,
return 0;
}
+static int log_csums(struct btrfs_trans_handle *trans,
+ struct btrfs_root *log_root,
+ struct btrfs_ordered_sum *sums)
+{
+ int ret;
+
+ /*
+ * Due to extent cloning, we might have logged a csum item that covers a
+ * subrange of a cloned extent, and later we can end up logging a csum
+ * item for a larger subrange of the same extent or the entire range.
+ * This would leave csum items in the log tree that cover the same range
+ * and break the searches for checksums in the log tree, resulting in
+ * some checksums missing in the fs/subvolume tree. So just delete (or
+ * trim and adjust) any existing csum items in the log for this range.
+ */
+ ret = btrfs_del_csums(trans, log_root, sums->bytenr, sums->len);
+ if (ret)
+ return ret;
+
+ return btrfs_csum_file_blocks(trans, log_root, sums);
+}
+
static noinline int copy_items(struct btrfs_trans_handle *trans,
struct btrfs_inode *inode,
struct btrfs_path *dst_path,
@@ -4011,7 +4034,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
struct btrfs_ordered_sum,
list);
if (!ret)
- ret = btrfs_csum_file_blocks(trans, log, sums);
+ ret = log_csums(trans, log, sums);
list_del(&sums->list);
kfree(sums);
}
@@ -4231,7 +4254,7 @@ static int log_extent_csums(struct btrfs_trans_handle *trans,
struct btrfs_ordered_sum,
list);
if (!ret)
- ret = btrfs_csum_file_blocks(trans, log_root, sums);
+ ret = log_csums(trans, log_root, sums);
list_del(&sums->list);
kfree(sums);
}
@@ -5997,9 +6020,28 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key);
if (IS_ERR(wc.replay_dest)) {
ret = PTR_ERR(wc.replay_dest);
+
+ /*
+ * We didn't find the subvol, likely because it was
+ * deleted. This is ok, simply skip this log and go to
+ * the next one.
+ *
+ * We need to exclude the root because we can't have
+ * other log replays overwriting this log as we'll read
+ * it back in a few more times. This will keep our
+ * block from being modified, and we'll just bail for
+ * each subsequent pass.
+ */
+ if (ret == -ENOENT)
+ ret = btrfs_pin_extent_for_log_replay(fs_info,
+ log->node->start,
+ log->node->len);
free_extent_buffer(log->node);
free_extent_buffer(log->commit_root);
kfree(log);
+
+ if (!ret)
+ goto next;
btrfs_handle_fs_error(fs_info, ret,
"Couldn't read target root for tree log recovery.");
goto error;
@@ -6031,7 +6073,6 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
&root->highest_objectid);
}
- key.offset = found_key.offset - 1;
wc.replay_dest->log_root = NULL;
free_extent_buffer(log->node);
free_extent_buffer(log->commit_root);
@@ -6039,9 +6080,10 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
if (ret)
goto error;
-
+next:
if (found_key.offset == 0)
break;
+ key.offset = found_key.offset - 1;
}
btrfs_release_path(path);
diff --git a/fs/btrfs/uuid-tree.c b/fs/btrfs/uuid-tree.c
index 3b2ae34..5bbb977 100644
--- a/fs/btrfs/uuid-tree.c
+++ b/fs/btrfs/uuid-tree.c
@@ -324,6 +324,8 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
}
if (ret < 0 && ret != -ENOENT)
goto out;
+ key.offset++;
+ goto again_search_slot;
}
item_size -= sizeof(subid_le);
offset += sizeof(subid_le);
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 3a03f74..c6fe991 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1401,10 +1401,11 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
#endif
case FICLONE:
+ goto do_ioctl;
case FICLONERANGE:
case FIDEDUPERANGE:
case FS_IOC_FIEMAP:
- goto do_ioctl;
+ goto found_handler;
case FIBMAP:
case FIGETBSZ:
diff --git a/fs/drop_caches.c b/fs/drop_caches.c
index d31b6c7..dc1a1d5 100644
--- a/fs/drop_caches.c
+++ b/fs/drop_caches.c
@@ -35,11 +35,11 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
spin_unlock(&inode->i_lock);
spin_unlock(&sb->s_inode_list_lock);
- cond_resched();
invalidate_mapping_pages(inode->i_mapping, 0, -1);
iput(toput_inode);
toput_inode = inode;
+ cond_resched();
spin_lock(&sb->s_inode_list_lock);
}
spin_unlock(&sb->s_inode_list_lock);
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 44c2fff..17a75fc 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -77,6 +77,11 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,
error_msg = "rec_len is too small for name_len";
else if (unlikely(((char *) de - buf) + rlen > size))
error_msg = "directory entry overrun";
+ else if (unlikely(((char *) de - buf) + rlen >
+ size - EXT4_DIR_REC_LEN(1) &&
+ ((char *) de - buf) + rlen != size)) {
+ error_msg = "directory entry too close to block end";
+ }
else if (unlikely(le32_to_cpu(de->inode) >
le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count)))
error_msg = "inode out of bounds";
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 0a92012..25dea6a 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3570,8 +3570,14 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
return ret;
}
+ /*
+ * Writes that span EOF might trigger an I/O size update on completion,
+ * so consider them to be dirty for the purposes of O_DSYNC, even if
+ * there is no other metadata changes being made or are pending here.
+ */
iomap->flags = 0;
- if (ext4_inode_datasync_dirty(inode))
+ if (ext4_inode_datasync_dirty(inode) ||
+ offset + length > i_size_read(inode))
iomap->flags |= IOMAP_F_DIRTY;
iomap->bdev = inode->i_sb->s_bdev;
iomap->dax_dev = sbi->s_daxdev;
@@ -3879,7 +3885,13 @@ static ssize_t ext4_direct_IO_read(struct kiocb *iocb, struct iov_iter *iter)
* writes & truncates and since we take care of writing back page cache,
* we are protected against page writeback as well.
*/
- inode_lock_shared(inode);
+ if (iocb->ki_flags & IOCB_NOWAIT) {
+ if (!inode_trylock_shared(inode))
+ return -EAGAIN;
+ } else {
+ inode_lock_shared(inode);
+ }
+
ret = filemap_write_and_wait_range(mapping, iocb->ki_pos,
iocb->ki_pos + count - 1);
if (ret)
@@ -6099,7 +6111,7 @@ int ext4_expand_extra_isize(struct inode *inode,
error = ext4_journal_get_write_access(handle, iloc->bh);
if (error) {
brelse(iloc->bh);
- goto out_stop;
+ goto out_unlock;
}
error = __ext4_expand_extra_isize(inode, new_extra_isize, iloc,
@@ -6109,8 +6121,8 @@ int ext4_expand_extra_isize(struct inode *inode,
if (!error)
error = rc;
+out_unlock:
ext4_write_unlock_xattr(inode, &no_expand);
-out_stop:
ext4_journal_stop(handle);
return error;
}
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 8d221b3..f941208 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2693,7 +2693,7 @@ bool ext4_empty_dir(struct inode *inode)
{
unsigned int offset;
struct buffer_head *bh;
- struct ext4_dir_entry_2 *de, *de1;
+ struct ext4_dir_entry_2 *de;
struct super_block *sb;
if (ext4_has_inline_data(inode)) {
@@ -2718,19 +2718,25 @@ bool ext4_empty_dir(struct inode *inode)
return true;
de = (struct ext4_dir_entry_2 *) bh->b_data;
- de1 = ext4_next_entry(de, sb->s_blocksize);
- if (le32_to_cpu(de->inode) != inode->i_ino ||
- le32_to_cpu(de1->inode) == 0 ||
- strcmp(".", de->name) || strcmp("..", de1->name)) {
- ext4_warning_inode(inode, "directory missing '.' and/or '..'");
+ if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size,
+ 0) ||
+ le32_to_cpu(de->inode) != inode->i_ino || strcmp(".", de->name)) {
+ ext4_warning_inode(inode, "directory missing '.'");
brelse(bh);
return true;
}
- offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) +
- ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize);
- de = ext4_next_entry(de1, sb->s_blocksize);
+ offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
+ de = ext4_next_entry(de, sb->s_blocksize);
+ if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size,
+ offset) ||
+ le32_to_cpu(de->inode) == 0 || strcmp("..", de->name)) {
+ ext4_warning_inode(inode, "directory missing '..'");
+ brelse(bh);
+ return true;
+ }
+ offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
while (offset < inode->i_size) {
- if ((void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
+ if (!(offset & (sb->s_blocksize - 1))) {
unsigned int lblock;
brelse(bh);
lblock = offset >> EXT4_BLOCK_SIZE_BITS(sb);
@@ -2741,12 +2747,11 @@ bool ext4_empty_dir(struct inode *inode)
}
if (IS_ERR(bh))
return true;
- de = (struct ext4_dir_entry_2 *) bh->b_data;
}
+ de = (struct ext4_dir_entry_2 *) (bh->b_data +
+ (offset & (sb->s_blocksize - 1)));
if (ext4_check_dir_entry(inode, NULL, de, bh,
bh->b_data, bh->b_size, offset)) {
- de = (struct ext4_dir_entry_2 *)(bh->b_data +
- sb->s_blocksize);
offset = (offset | (sb->s_blocksize - 1)) + 1;
continue;
}
@@ -2755,7 +2760,6 @@ bool ext4_empty_dir(struct inode *inode)
return false;
}
offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
- de = ext4_next_entry(de, sb->s_blocksize);
}
brelse(bh);
return true;
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 548a747..e1354c3 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -1401,8 +1401,10 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* Flush all the NAT/SIT pages */
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
- f2fs_bug_on(sbi, get_pages(sbi, F2FS_DIRTY_META) &&
- !f2fs_cp_error(sbi));
+ if (get_pages(sbi, F2FS_DIRTY_META) && !f2fs_cp_error(sbi)) {
+ WARN_ON(1);
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ }
/*
* modify checkpoint
@@ -1510,8 +1512,10 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* Here, we have one bio having CP pack except cp pack 2 page */
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
- f2fs_bug_on(sbi, get_pages(sbi, F2FS_DIRTY_META) &&
- !f2fs_cp_error(sbi));
+ if (get_pages(sbi, F2FS_DIRTY_META) && !f2fs_cp_error(sbi)) {
+ WARN_ON(1);
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ }
/* wait for previous submitted meta pages writeback */
f2fs_wait_on_all_pages_writeback(sbi);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 20ac8ea..5d18cf2 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -2685,6 +2685,20 @@ static inline void clear_file(struct inode *inode, int type)
f2fs_mark_inode_dirty_sync(inode, true);
}
+static inline bool f2fs_is_time_consistent(struct inode *inode)
+{
+ if (!timespec64_equal(F2FS_I(inode)->i_disk_time, &inode->i_atime))
+ return false;
+ if (!timespec64_equal(F2FS_I(inode)->i_disk_time + 1, &inode->i_ctime))
+ return false;
+ if (!timespec64_equal(F2FS_I(inode)->i_disk_time + 2, &inode->i_mtime))
+ return false;
+ if (!timespec64_equal(F2FS_I(inode)->i_disk_time + 3,
+ &F2FS_I(inode)->i_crtime))
+ return false;
+ return true;
+}
+
static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync)
{
bool ret;
@@ -2702,14 +2716,7 @@ static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync)
i_size_read(inode) & ~PAGE_MASK)
return false;
- if (!timespec64_equal(F2FS_I(inode)->i_disk_time, &inode->i_atime))
- return false;
- if (!timespec64_equal(F2FS_I(inode)->i_disk_time + 1, &inode->i_ctime))
- return false;
- if (!timespec64_equal(F2FS_I(inode)->i_disk_time + 2, &inode->i_mtime))
- return false;
- if (!timespec64_equal(F2FS_I(inode)->i_disk_time + 3,
- &F2FS_I(inode)->i_crtime))
+ if (!f2fs_is_time_consistent(inode))
return false;
down_read(&F2FS_I(inode)->i_sem);
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index e269959..15d0923 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -627,7 +627,11 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
inode->i_ino == F2FS_META_INO(sbi))
return 0;
- if (!is_inode_flag_set(inode, FI_DIRTY_INODE))
+ /*
+ * atime could be updated without dirtying f2fs inode in lazytime mode
+ */
+ if (f2fs_is_time_consistent(inode) &&
+ !is_inode_flag_set(inode, FI_DIRTY_INODE))
return 0;
if (f2fs_is_checkpoint_ready(sbi))
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 2fdcbe9..dddd245 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -962,7 +962,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (!old_dir_entry || whiteout)
file_lost_pino(old_inode);
else
- F2FS_I(old_inode)->i_pino = new_dir->i_ino;
+ /* adjust dir's i_pino to pass fsck check */
+ f2fs_i_pino_write(old_inode, new_dir->i_ino);
up_write(&F2FS_I(old_inode)->i_sem);
old_inode->i_ctime = current_time(old_inode);
@@ -1123,7 +1124,11 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
f2fs_set_link(old_dir, old_entry, old_page, new_inode);
down_write(&F2FS_I(old_inode)->i_sem);
- file_lost_pino(old_inode);
+ if (!old_dir_entry)
+ file_lost_pino(old_inode);
+ else
+ /* adjust dir's i_pino to pass fsck check */
+ f2fs_i_pino_write(old_inode, new_dir->i_ino);
up_write(&F2FS_I(old_inode)->i_sem);
old_dir->i_ctime = current_time(old_dir);
@@ -1138,7 +1143,11 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
f2fs_set_link(new_dir, new_entry, new_page, old_inode);
down_write(&F2FS_I(new_inode)->i_sem);
- file_lost_pino(new_inode);
+ if (!new_dir_entry)
+ file_lost_pino(new_inode);
+ else
+ /* adjust dir's i_pino to pass fsck check */
+ f2fs_i_pino_write(new_inode, old_dir->i_ino);
up_write(&F2FS_I(new_inode)->i_sem);
new_dir->i_ctime = current_time(new_dir);
diff --git a/fs/inode.c b/fs/inode.c
index 88e78f8..7c19642 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -660,6 +660,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
struct inode *inode, *next;
LIST_HEAD(dispose);
+again:
spin_lock(&sb->s_inode_list_lock);
list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
spin_lock(&inode->i_lock);
@@ -682,6 +683,12 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
inode_lru_list_del(inode);
spin_unlock(&inode->i_lock);
list_add(&inode->i_lru, &dispose);
+ if (need_resched()) {
+ spin_unlock(&sb->s_inode_list_lock);
+ cond_resched();
+ dispose_list(&dispose);
+ goto again;
+ }
}
spin_unlock(&sb->s_inode_list_lock);
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 24f86ff..020bd7a 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -724,7 +724,6 @@ void jbd2_journal_commit_transaction(journal_t *journal)
submit_bh(REQ_OP_WRITE, REQ_SYNC, bh);
}
cond_resched();
- stats.run.rs_blocks_logged += bufs;
/* Force a new descriptor to be generated next
time round the loop. */
@@ -811,6 +810,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
if (unlikely(!buffer_uptodate(bh)))
err = -EIO;
jbd2_unfile_log_bh(bh);
+ stats.run.rs_blocks_logged++;
/*
* The list contains temporary buffer heads created by
@@ -856,6 +856,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile");
clear_buffer_jwrite(bh);
jbd2_unfile_log_bh(bh);
+ stats.run.rs_blocks_logged++;
__brelse(bh); /* One for getblk */
/* AKPM: bforget here */
}
@@ -877,6 +878,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
}
if (cbh)
err = journal_wait_on_commit_record(journal, cbh);
+ stats.run.rs_blocks_logged++;
if (jbd2_has_feature_async_commit(journal) &&
journal->j_flags & JBD2_BARRIER) {
blkdev_issue_flush(journal->j_dev, GFP_NOFS, NULL);
diff --git a/fs/locks.c b/fs/locks.c
index 2ecb4db..28270e7 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2678,7 +2678,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
}
if (inode) {
/* userspace relies on this representation of dev_t */
- seq_printf(f, "%d %02x:%02x:%ld ", fl_pid,
+ seq_printf(f, "%d %02x:%02x:%lu ", fl_pid,
MAJOR(inode->i_sb->s_dev),
MINOR(inode->i_sb->s_dev), inode->i_ino);
} else {
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 5f62007..c8ce128 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3072,12 +3072,17 @@ static bool replay_matches_cache(struct svc_rqst *rqstp,
(bool)seq->cachethis)
return false;
/*
- * If there's an error than the reply can have fewer ops than
- * the call. But if we cached a reply with *more* ops than the
- * call you're sending us now, then this new call is clearly not
- * really a replay of the old one:
+ * If there's an error then the reply can have fewer ops than
+ * the call.
*/
- if (slot->sl_opcnt < argp->opcnt)
+ if (slot->sl_opcnt < argp->opcnt && !slot->sl_status)
+ return false;
+ /*
+ * But if we cached a reply with *more* ops than the call you're
+ * sending us now, then this new call is clearly not really a
+ * replay of the old one:
+ */
+ if (slot->sl_opcnt > argp->opcnt)
return false;
/* This is the only check explicitly called by spec: */
if (!same_creds(&rqstp->rq_cred, &slot->sl_cred))
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 170a733..e8ee426 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -90,6 +90,7 @@ void fsnotify_unmount_inodes(struct super_block *sb)
iput_inode = inode;
+ cond_resched();
spin_lock(&sb->s_inode_list_lock);
}
spin_unlock(&sb->s_inode_list_lock);
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
index 917fadca..b73b787 100644
--- a/fs/ocfs2/acl.c
+++ b/fs/ocfs2/acl.c
@@ -335,8 +335,8 @@ int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)
down_read(&OCFS2_I(inode)->ip_xattr_sem);
acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh);
up_read(&OCFS2_I(inode)->ip_xattr_sem);
- if (IS_ERR(acl) || !acl)
- return PTR_ERR(acl);
+ if (IS_ERR_OR_NULL(acl))
+ return PTR_ERR_OR_ZERO(acl);
ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
if (ret)
return ret;
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 631ae05..bafbab2 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -437,6 +437,17 @@ static int notrace ramoops_pstore_write(struct pstore_record *record)
prz = cxt->dprzs[cxt->dump_write_cnt];
+ /*
+ * Since this is a new crash dump, we need to reset the buffer in
+ * case it still has an old dump present. Without this, the new dump
+ * will get appended, which would seriously confuse anything trying
+ * to check dump file contents. Specifically, ramoops_read_kmsg_hdr()
+ * expects to find a dump header in the beginning of buffer data, so
+ * we must to reset the buffer values, in order to ensure that the
+ * header will be written to the beginning of the buffer.
+ */
+ persistent_ram_zap(prz);
+
/* Build header and append record contents. */
hlen = ramoops_write_kmsg_hdr(prz, record);
size = record->size;
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 59b00d8..1d1d393 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -980,6 +980,7 @@ static int add_dquot_ref(struct super_block *sb, int type)
* later.
*/
old_inode = inode;
+ cond_resched();
spin_lock(&sb->s_inode_list_lock);
}
spin_unlock(&sb->s_inode_list_lock);
@@ -2853,68 +2854,73 @@ EXPORT_SYMBOL(dquot_quotactl_sysfile_ops);
static int do_proc_dqstats(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
- unsigned int type = (int *)table->data - dqstats.stat;
+ unsigned int type = (unsigned long *)table->data - dqstats.stat;
+ s64 value = percpu_counter_sum(&dqstats.counter[type]);
+
+ /* Filter negative values for non-monotonic counters */
+ if (value < 0 && (type == DQST_ALLOC_DQUOTS ||
+ type == DQST_FREE_DQUOTS))
+ value = 0;
/* Update global table */
- dqstats.stat[type] =
- percpu_counter_sum_positive(&dqstats.counter[type]);
- return proc_dointvec(table, write, buffer, lenp, ppos);
+ dqstats.stat[type] = value;
+ return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
}
static struct ctl_table fs_dqstats_table[] = {
{
.procname = "lookups",
.data = &dqstats.stat[DQST_LOOKUPS],
- .maxlen = sizeof(int),
+ .maxlen = sizeof(unsigned long),
.mode = 0444,
.proc_handler = do_proc_dqstats,
},
{
.procname = "drops",
.data = &dqstats.stat[DQST_DROPS],
- .maxlen = sizeof(int),
+ .maxlen = sizeof(unsigned long),
.mode = 0444,
.proc_handler = do_proc_dqstats,
},
{
.procname = "reads",
.data = &dqstats.stat[DQST_READS],
- .maxlen = sizeof(int),
+ .maxlen = sizeof(unsigned long),
.mode = 0444,
.proc_handler = do_proc_dqstats,
},
{
.procname = "writes",
.data = &dqstats.stat[DQST_WRITES],
- .maxlen = sizeof(int),
+ .maxlen = sizeof(unsigned long),
.mode = 0444,
.proc_handler = do_proc_dqstats,
},
{
.procname = "cache_hits",
.data = &dqstats.stat[DQST_CACHE_HITS],
- .maxlen = sizeof(int),
+ .maxlen = sizeof(unsigned long),
.mode = 0444,
.proc_handler = do_proc_dqstats,
},
{
.procname = "allocated_dquots",
.data = &dqstats.stat[DQST_ALLOC_DQUOTS],
- .maxlen = sizeof(int),
+ .maxlen = sizeof(unsigned long),
.mode = 0444,
.proc_handler = do_proc_dqstats,
},
{
.procname = "free_dquots",
.data = &dqstats.stat[DQST_FREE_DQUOTS],
- .maxlen = sizeof(int),
+ .maxlen = sizeof(unsigned long),
.mode = 0444,
.proc_handler = do_proc_dqstats,
},
{
.procname = "syncs",
.data = &dqstats.stat[DQST_SYNCS],
- .maxlen = sizeof(int),
+ .maxlen = sizeof(unsigned long),
.mode = 0444,
.proc_handler = do_proc_dqstats,
},
diff --git a/fs/readdir.c b/fs/readdir.c
index d97f548..443270f 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -65,6 +65,40 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
EXPORT_SYMBOL(iterate_dir);
/*
+ * POSIX says that a dirent name cannot contain NULL or a '/'.
+ *
+ * It's not 100% clear what we should really do in this case.
+ * The filesystem is clearly corrupted, but returning a hard
+ * error means that you now don't see any of the other names
+ * either, so that isn't a perfect alternative.
+ *
+ * And if you return an error, what error do you use? Several
+ * filesystems seem to have decided on EUCLEAN being the error
+ * code for EFSCORRUPTED, and that may be the error to use. Or
+ * just EIO, which is perhaps more obvious to users.
+ *
+ * In order to see the other file names in the directory, the
+ * caller might want to make this a "soft" error: skip the
+ * entry, and return the error at the end instead.
+ *
+ * Note that this should likely do a "memchr(name, 0, len)"
+ * check too, since that would be filesystem corruption as
+ * well. However, that case can't actually confuse user space,
+ * which has to do a strlen() on the name anyway to find the
+ * filename length, and the above "soft error" worry means
+ * that it's probably better left alone until we have that
+ * issue clarified.
+ */
+static int verify_dirent_name(const char *name, int len)
+{
+ if (!len)
+ return -EIO;
+ if (memchr(name, '/', len))
+ return -EIO;
+ return 0;
+}
+
+/*
* Traditional linux readdir() handling..
*
* "count=1" is a special case, meaning that the buffer is one
@@ -173,6 +207,9 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen,
int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
sizeof(long));
+ buf->error = verify_dirent_name(name, namlen);
+ if (unlikely(buf->error))
+ return buf->error;
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
@@ -259,6 +296,9 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
sizeof(u64));
+ buf->error = verify_dirent_name(name, namlen);
+ if (unlikely(buf->error))
+ return buf->error;
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c
index dba87d0..95630f9 100644
--- a/fs/ubifs/tnc_commit.c
+++ b/fs/ubifs/tnc_commit.c
@@ -219,7 +219,7 @@ static int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key,
/**
* layout_leb_in_gaps - layout index nodes using in-the-gaps method.
* @c: UBIFS file-system description object
- * @p: return LEB number here
+ * @p: return LEB number in @c->gap_lebs[p]
*
* This function lays out new index nodes for dirty znodes using in-the-gaps
* method of TNC commit.
@@ -228,7 +228,7 @@ static int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key,
* This function returns the number of index nodes written into the gaps, or a
* negative error code on failure.
*/
-static int layout_leb_in_gaps(struct ubifs_info *c, int *p)
+static int layout_leb_in_gaps(struct ubifs_info *c, int p)
{
struct ubifs_scan_leb *sleb;
struct ubifs_scan_node *snod;
@@ -243,7 +243,7 @@ static int layout_leb_in_gaps(struct ubifs_info *c, int *p)
* filled, however we do not check there at present.
*/
return lnum; /* Error code */
- *p = lnum;
+ c->gap_lebs[p] = lnum;
dbg_gc("LEB %d", lnum);
/*
* Scan the index LEB. We use the generic scan for this even though
@@ -362,7 +362,7 @@ static int get_leb_cnt(struct ubifs_info *c, int cnt)
*/
static int layout_in_gaps(struct ubifs_info *c, int cnt)
{
- int err, leb_needed_cnt, written, *p;
+ int err, leb_needed_cnt, written, p = 0, old_idx_lebs, *gap_lebs;
dbg_gc("%d znodes to write", cnt);
@@ -371,9 +371,9 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
if (!c->gap_lebs)
return -ENOMEM;
- p = c->gap_lebs;
+ old_idx_lebs = c->lst.idx_lebs;
do {
- ubifs_assert(c, p < c->gap_lebs + c->lst.idx_lebs);
+ ubifs_assert(c, p < c->lst.idx_lebs);
written = layout_leb_in_gaps(c, p);
if (written < 0) {
err = written;
@@ -399,9 +399,29 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
leb_needed_cnt = get_leb_cnt(c, cnt);
dbg_gc("%d znodes remaining, need %d LEBs, have %d", cnt,
leb_needed_cnt, c->ileb_cnt);
+ /*
+ * Dynamically change the size of @c->gap_lebs to prevent
+ * oob, because @c->lst.idx_lebs could be increased by
+ * function @get_idx_gc_leb (called by layout_leb_in_gaps->
+ * ubifs_find_dirty_idx_leb) during loop. Only enlarge
+ * @c->gap_lebs when needed.
+ *
+ */
+ if (leb_needed_cnt > c->ileb_cnt && p >= old_idx_lebs &&
+ old_idx_lebs < c->lst.idx_lebs) {
+ old_idx_lebs = c->lst.idx_lebs;
+ gap_lebs = krealloc(c->gap_lebs, sizeof(int) *
+ (old_idx_lebs + 1), GFP_NOFS);
+ if (!gap_lebs) {
+ kfree(c->gap_lebs);
+ c->gap_lebs = NULL;
+ return -ENOMEM;
+ }
+ c->gap_lebs = gap_lebs;
+ }
} while (leb_needed_cnt > c->ileb_cnt);
- *p = -1;
+ c->gap_lebs[p] = -1;
return 0;
}
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 5a519bc..feb109a 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -1845,13 +1845,12 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx,
if (copy_from_user(&uffdio_api, buf, sizeof(uffdio_api)))
goto out;
features = uffdio_api.features;
- if (uffdio_api.api != UFFD_API || (features & ~UFFD_API_FEATURES)) {
- memset(&uffdio_api, 0, sizeof(uffdio_api));
- if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api)))
- goto out;
- ret = -EINVAL;
- goto out;
- }
+ ret = -EINVAL;
+ if (uffdio_api.api != UFFD_API || (features & ~UFFD_API_FEATURES))
+ goto err_out;
+ ret = -EPERM;
+ if ((features & UFFD_FEATURE_EVENT_FORK) && !capable(CAP_SYS_PTRACE))
+ goto err_out;
/* report all available features and ioctls to userland */
uffdio_api.features = UFFD_API_FEATURES;
uffdio_api.ioctls = UFFD_API_IOCTLS;
@@ -1864,6 +1863,11 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx,
ret = 0;
out:
return ret;
+err_out:
+ memset(&uffdio_api, 0, sizeof(uffdio_api));
+ if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api)))
+ ret = -EFAULT;
+ goto out;
}
static long userfaultfd_ioctl(struct file *file, unsigned cmd,
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 38dc0b4..0b7145f 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -5239,7 +5239,7 @@ __xfs_bunmapi(
* Make sure we don't touch multiple AGF headers out of order
* in a single transaction, as that could cause AB-BA deadlocks.
*/
- if (!wasdel) {
+ if (!wasdel && !isrt) {
agno = XFS_FSB_TO_AGNO(mp, del.br_startblock);
if (prev_agno != NULLAGNUMBER && prev_agno > agno)
break;
diff --git a/fs/xfs/scrub/common.h b/fs/xfs/scrub/common.h
index 2d4324d..51ea2ab 100644
--- a/fs/xfs/scrub/common.h
+++ b/fs/xfs/scrub/common.h
@@ -14,8 +14,15 @@
static inline bool
xchk_should_terminate(
struct xfs_scrub *sc,
- int *error)
+ int *error)
{
+ /*
+ * If preemption is disabled, we need to yield to the scheduler every
+ * few seconds so that we don't run afoul of the soft lockup watchdog
+ * or RCU stall detector.
+ */
+ cond_resched();
+
if (fatal_signal_pending(current)) {
if (*error == 0)
*error = -EAGAIN;
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index c3b610b..7bba551cb 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -1578,6 +1578,8 @@ xlog_alloc_log(
if (iclog->ic_bp)
xfs_buf_free(iclog->ic_bp);
kmem_free(iclog);
+ if (prev_iclog == log->l_iclog)
+ break;
}
spinlock_destroy(&log->l_icloglock);
xfs_buf_free(log->l_xbuf);
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
index a0fa620..5e7a4f1 100644
--- a/include/drm/drm_dp_mst_helper.h
+++ b/include/drm/drm_dp_mst_helper.h
@@ -339,7 +339,7 @@ struct drm_dp_resource_status_notify {
struct drm_dp_query_payload_ack_reply {
u8 port_number;
- u8 allocated_pbn;
+ u16 allocated_pbn;
};
struct drm_dp_sideband_msg_req_body {
diff --git a/include/dt-bindings/phy/qcom,lagoon-qmp-usb3.h b/include/dt-bindings/phy/qcom,lagoon-qmp-usb3.h
new file mode 100644
index 0000000..107ee57
--- /dev/null
+++ b/include/dt-bindings/phy/qcom,lagoon-qmp-usb3.h
@@ -0,0 +1,638 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_PHY_QCOM_LAGOON_QMP_USB_H
+#define _DT_BINDINGS_PHY_QCOM_LAGOON_QMP_USB_H
+
+/* USB3-DP Combo PHY register offsets */
+
+#define USB3_DP_COM_PHY_MODE_CTRL 0x0000
+#define USB3_DP_COM_SW_RESET 0x0004
+#define USB3_DP_COM_POWER_DOWN_CTRL 0x0008
+#define USB3_DP_COM_SWI_CTRL 0x000c
+#define USB3_DP_COM_TYPEC_CTRL 0x0010
+#define USB3_DP_COM_TYPEC_PWRDN_CTRL 0x0014
+#define USB3_DP_COM_DP_BIST_CFG_0 0x0018
+#define USB3_DP_COM_RESET_OVRD_CTRL 0x001c
+#define USB3_DP_COM_TYPEC_STATUS 0x0020
+#define USB3_DP_COM_PLACEHOLDER_STATUS 0x0024
+#define USB3_DP_COM_REVISION_ID0 0x0028
+#define USB3_DP_COM_REVISION_ID1 0x002c
+#define USB3_DP_COM_REVISION_ID2 0x0030
+#define USB3_DP_COM_REVISION_ID3 0x0034
+#define USB3_DP_QSERDES_COM_ATB_SEL1 0x1000
+#define USB3_DP_QSERDES_COM_ATB_SEL2 0x1004
+#define USB3_DP_QSERDES_COM_FREQ_UPDATE 0x1008
+#define USB3_DP_QSERDES_COM_BG_TIMER 0x100c
+#define USB3_DP_QSERDES_COM_SSC_EN_CENTER 0x1010
+#define USB3_DP_QSERDES_COM_SSC_ADJ_PER1 0x1014
+#define USB3_DP_QSERDES_COM_SSC_ADJ_PER2 0x1018
+#define USB3_DP_QSERDES_COM_SSC_PER1 0x101c
+#define USB3_DP_QSERDES_COM_SSC_PER2 0x1020
+#define USB3_DP_QSERDES_COM_SSC_STEP_SIZE1 0x1024
+#define USB3_DP_QSERDES_COM_SSC_STEP_SIZE2 0x1028
+#define USB3_DP_QSERDES_COM_POST_DIV 0x102c
+#define USB3_DP_QSERDES_COM_POST_DIV_MUX 0x1030
+#define USB3_DP_QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x1034
+#define USB3_DP_QSERDES_COM_CLK_ENABLE1 0x1038
+#define USB3_DP_QSERDES_COM_SYS_CLK_CTRL 0x103c
+#define USB3_DP_QSERDES_COM_SYSCLK_BUF_ENABLE 0x1040
+#define USB3_DP_QSERDES_COM_PLL_EN 0x1044
+#define USB3_DP_QSERDES_COM_PLL_IVCO 0x1048
+#define USB3_DP_QSERDES_COM_CMN_IETRIM 0x104c
+#define USB3_DP_QSERDES_COM_CMN_IPTRIM 0x1050
+#define USB3_DP_QSERDES_COM_EP_CLOCK_DETECT_CTRL 0x1054
+#define USB3_DP_QSERDES_COM_SYSCLK_DET_COMP_STATUS 0x1058
+#define USB3_DP_QSERDES_COM_CLK_EP_DIV 0x105c
+#define USB3_DP_QSERDES_COM_CP_CTRL_MODE0 0x1060
+#define USB3_DP_QSERDES_COM_CP_CTRL_MODE1 0x1064
+#define USB3_DP_QSERDES_COM_PLL_RCTRL_MODE0 0x1068
+#define USB3_DP_QSERDES_COM_PLL_RCTRL_MODE1 0x106c
+#define USB3_DP_QSERDES_COM_PLL_CCTRL_MODE0 0x1070
+#define USB3_DP_QSERDES_COM_PLL_CCTRL_MODE1 0x1074
+#define USB3_DP_QSERDES_COM_PLL_CNTRL 0x1078
+#define USB3_DP_QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x107c
+#define USB3_DP_QSERDES_COM_SYSCLK_EN_SEL 0x1080
+#define USB3_DP_QSERDES_COM_CML_SYSCLK_SEL 0x1084
+#define USB3_DP_QSERDES_COM_RESETSM_CNTRL 0x1088
+#define USB3_DP_QSERDES_COM_RESETSM_CNTRL2 0x108c
+#define USB3_DP_QSERDES_COM_LOCK_CMP_EN 0x1090
+#define USB3_DP_QSERDES_COM_LOCK_CMP_CFG 0x1094
+#define USB3_DP_QSERDES_COM_LOCK_CMP1_MODE0 0x1098
+#define USB3_DP_QSERDES_COM_LOCK_CMP2_MODE0 0x109c
+#define USB3_DP_QSERDES_COM_LOCK_CMP3_MODE0 0x10a0
+#define USB3_DP_QSERDES_COM_LOCK_CMP1_MODE1 0x10a4
+#define USB3_DP_QSERDES_COM_LOCK_CMP2_MODE1 0x10a8
+#define USB3_DP_QSERDES_COM_LOCK_CMP3_MODE1 0x10ac
+#define USB3_DP_QSERDES_COM_DEC_START_MODE0 0x10b0
+#define USB3_DP_QSERDES_COM_DEC_START_MODE1 0x10b4
+#define USB3_DP_QSERDES_COM_DIV_FRAC_START1_MODE0 0x10b8
+#define USB3_DP_QSERDES_COM_DIV_FRAC_START2_MODE0 0x10bc
+#define USB3_DP_QSERDES_COM_DIV_FRAC_START3_MODE0 0x10c0
+#define USB3_DP_QSERDES_COM_DIV_FRAC_START1_MODE1 0x10c4
+#define USB3_DP_QSERDES_COM_DIV_FRAC_START2_MODE1 0x10c8
+#define USB3_DP_QSERDES_COM_DIV_FRAC_START3_MODE1 0x10cc
+#define USB3_DP_QSERDES_COM_INTEGLOOP_INITVAL 0x10d0
+#define USB3_DP_QSERDES_COM_INTEGLOOP_EN 0x10d4
+#define USB3_DP_QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x10d8
+#define USB3_DP_QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x10dc
+#define USB3_DP_QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x10e0
+#define USB3_DP_QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x10e4
+#define USB3_DP_QSERDES_COM_VCOCAL_DEADMAN_CTRL 0x10e8
+#define USB3_DP_QSERDES_COM_VCO_TUNE_CTRL 0x10ec
+#define USB3_DP_QSERDES_COM_VCO_TUNE_MAP 0x10f0
+#define USB3_DP_QSERDES_COM_VCO_TUNE1_MODE0 0x10f4
+#define USB3_DP_QSERDES_COM_VCO_TUNE2_MODE0 0x10f8
+#define USB3_DP_QSERDES_COM_VCO_TUNE1_MODE1 0x10fc
+#define USB3_DP_QSERDES_COM_VCO_TUNE2_MODE1 0x1100
+#define USB3_DP_QSERDES_COM_VCO_TUNE_INITVAL1 0x1104
+#define USB3_DP_QSERDES_COM_VCO_TUNE_INITVAL2 0x1108
+#define USB3_DP_QSERDES_COM_VCO_TUNE_MINVAL1 0x110c
+#define USB3_DP_QSERDES_COM_VCO_TUNE_MINVAL2 0x1110
+#define USB3_DP_QSERDES_COM_VCO_TUNE_MAXVAL1 0x1114
+#define USB3_DP_QSERDES_COM_VCO_TUNE_MAXVAL2 0x1118
+#define USB3_DP_QSERDES_COM_VCO_TUNE_TIMER1 0x111c
+#define USB3_DP_QSERDES_COM_VCO_TUNE_TIMER2 0x1120
+#define USB3_DP_QSERDES_COM_CMN_STATUS 0x1124
+#define USB3_DP_QSERDES_COM_RESET_SM_STATUS 0x1128
+#define USB3_DP_QSERDES_COM_RESTRIM_CODE_STATUS 0x112c
+#define USB3_DP_QSERDES_COM_PLLCAL_CODE1_STATUS 0x1130
+#define USB3_DP_QSERDES_COM_PLLCAL_CODE2_STATUS 0x1134
+#define USB3_DP_QSERDES_COM_CLK_SELECT 0x1138
+#define USB3_DP_QSERDES_COM_HSCLK_SEL 0x113c
+#define USB3_DP_QSERDES_COM_INTEGLOOP_BINCODE_STATUS 0x1140
+#define USB3_DP_QSERDES_COM_PLL_ANALOG 0x1144
+#define USB3_DP_QSERDES_COM_CORECLK_DIV_MODE0 0x1148
+#define USB3_DP_QSERDES_COM_CORECLK_DIV_MODE1 0x114c
+#define USB3_DP_QSERDES_COM_SW_RESET 0x1150
+#define USB3_DP_QSERDES_COM_CORE_CLK_EN 0x1154
+#define USB3_DP_QSERDES_COM_C_READY_STATUS 0x1158
+#define USB3_DP_QSERDES_COM_CMN_CONFIG 0x115c
+#define USB3_DP_QSERDES_COM_CMN_RATE_OVERRIDE 0x1160
+#define USB3_DP_QSERDES_COM_SVS_MODE_CLK_SEL 0x1164
+#define USB3_DP_QSERDES_COM_DEBUG_BUS0 0x1168
+#define USB3_DP_QSERDES_COM_DEBUG_BUS1 0x116c
+#define USB3_DP_QSERDES_COM_DEBUG_BUS2 0x1170
+#define USB3_DP_QSERDES_COM_DEBUG_BUS3 0x1174
+#define USB3_DP_QSERDES_COM_DEBUG_BUS_SEL 0x1178
+#define USB3_DP_QSERDES_COM_CMN_MISC1 0x117c
+#define USB3_DP_QSERDES_COM_CMN_MISC2 0x1180
+#define USB3_DP_QSERDES_COM_CMN_MODE 0x1184
+#define USB3_DP_QSERDES_COM_CMN_VREG_SEL 0x1188
+#define USB3_DP_QSERDES_TXA_BIST_MODE_LANENO 0x1200
+#define USB3_DP_QSERDES_TXA_BIST_INVERT 0x1204
+#define USB3_DP_QSERDES_TXA_CLKBUF_ENABLE 0x1208
+#define USB3_DP_QSERDES_TXA_TX_EMP_POST1_LVL 0x120c
+#define USB3_DP_QSERDES_TXA_TX_POST2_EMPH 0x1210
+#define USB3_DP_QSERDES_TXA_TX_BOOST_LVL_UP_DN 0x1214
+#define USB3_DP_QSERDES_TXA_TX_IDLE_LVL_LARGE_AMP 0x1218
+#define USB3_DP_QSERDES_TXA_TX_DRV_LVL 0x121c
+#define USB3_DP_QSERDES_TXA_TX_DRV_LVL_OFFSET 0x1220
+#define USB3_DP_QSERDES_TXA_RESET_TSYNC_EN 0x1224
+#define USB3_DP_QSERDES_TXA_PRE_STALL_LDO_BOOST_EN 0x1228
+#define USB3_DP_QSERDES_TXA_TX_BAND 0x122c
+#define USB3_DP_QSERDES_TXA_SLEW_CNTL 0x1230
+#define USB3_DP_QSERDES_TXA_INTERFACE_SELECT 0x1234
+#define USB3_DP_QSERDES_TXA_LPB_EN 0x1238
+#define USB3_DP_QSERDES_TXA_RES_CODE_LANE_TX 0x123c
+#define USB3_DP_QSERDES_TXA_RES_CODE_LANE_RX 0x1240
+#define USB3_DP_QSERDES_TXA_RES_CODE_LANE_OFFSET_TX 0x1244
+#define USB3_DP_QSERDES_TXA_RES_CODE_LANE_OFFSET_RX 0x1248
+#define USB3_DP_QSERDES_TXA_PERL_LENGTH1 0x124c
+#define USB3_DP_QSERDES_TXA_PERL_LENGTH2 0x1250
+#define USB3_DP_QSERDES_TXA_SERDES_BYP_EN_OUT 0x1254
+#define USB3_DP_QSERDES_TXA_DEBUG_BUS_SEL 0x1258
+#define USB3_DP_QSERDES_TXA_TRANSCEIVER_BIAS_EN 0x125c
+#define USB3_DP_QSERDES_TXA_HIGHZ_DRVR_EN 0x1260
+#define USB3_DP_QSERDES_TXA_TX_POL_INV 0x1264
+#define USB3_DP_QSERDES_TXA_PARRATE_REC_DETECT_IDLE_EN 0x1268
+#define USB3_DP_QSERDES_TXA_BIST_PATTERN1 0x126c
+#define USB3_DP_QSERDES_TXA_BIST_PATTERN2 0x1270
+#define USB3_DP_QSERDES_TXA_BIST_PATTERN3 0x1274
+#define USB3_DP_QSERDES_TXA_BIST_PATTERN4 0x1278
+#define USB3_DP_QSERDES_TXA_BIST_PATTERN5 0x127c
+#define USB3_DP_QSERDES_TXA_BIST_PATTERN6 0x1280
+#define USB3_DP_QSERDES_TXA_BIST_PATTERN7 0x1284
+#define USB3_DP_QSERDES_TXA_BIST_PATTERN8 0x1288
+#define USB3_DP_QSERDES_TXA_LANE_MODE_1 0x128c
+#define USB3_DP_QSERDES_TXA_LANE_MODE_2 0x1290
+#define USB3_DP_QSERDES_TXA_LANE_MODE_3 0x1294
+#define USB3_DP_QSERDES_TXA_ATB_SEL1 0x1298
+#define USB3_DP_QSERDES_TXA_ATB_SEL2 0x129c
+#define USB3_DP_QSERDES_TXA_RCV_DETECT_LVL 0x12a0
+#define USB3_DP_QSERDES_TXA_RCV_DETECT_LVL_2 0x12a4
+#define USB3_DP_QSERDES_TXA_PRBS_SEED1 0x12a8
+#define USB3_DP_QSERDES_TXA_PRBS_SEED2 0x12ac
+#define USB3_DP_QSERDES_TXA_PRBS_SEED3 0x12b0
+#define USB3_DP_QSERDES_TXA_PRBS_SEED4 0x12b4
+#define USB3_DP_QSERDES_TXA_RESET_GEN 0x12b8
+#define USB3_DP_QSERDES_TXA_RESET_GEN_MUXES 0x12bc
+#define USB3_DP_QSERDES_TXA_TRAN_DRVR_EMP_EN 0x12c0
+#define USB3_DP_QSERDES_TXA_TX_INTERFACE_MODE 0x12c4
+#define USB3_DP_QSERDES_TXA_PWM_CTRL 0x12c8
+#define USB3_DP_QSERDES_TXA_PWM_ENCODED_OR_DATA 0x12cc
+#define USB3_DP_QSERDES_TXA_PWM_GEAR_1_DIVIDER_BAND2 0x12d0
+#define USB3_DP_QSERDES_TXA_PWM_GEAR_2_DIVIDER_BAND2 0x12d4
+#define USB3_DP_QSERDES_TXA_PWM_GEAR_3_DIVIDER_BAND2 0x12d8
+#define USB3_DP_QSERDES_TXA_PWM_GEAR_4_DIVIDER_BAND2 0x12dc
+#define USB3_DP_QSERDES_TXA_PWM_GEAR_1_DIVIDER_BAND0_1 0x12e0
+#define USB3_DP_QSERDES_TXA_PWM_GEAR_2_DIVIDER_BAND0_1 0x12e4
+#define USB3_DP_QSERDES_TXA_PWM_GEAR_3_DIVIDER_BAND0_1 0x12e8
+#define USB3_DP_QSERDES_TXA_PWM_GEAR_4_DIVIDER_BAND0_1 0x12ec
+#define USB3_DP_QSERDES_TXA_VMODE_CTRL1 0x12f0
+#define USB3_DP_QSERDES_TXA_ALOG_OBSV_BUS_CTRL_1 0x12f4
+#define USB3_DP_QSERDES_TXA_BIST_STATUS 0x12f8
+#define USB3_DP_QSERDES_TXA_BIST_ERROR_COUNT1 0x12fc
+#define USB3_DP_QSERDES_TXA_BIST_ERROR_COUNT2 0x1300
+#define USB3_DP_QSERDES_TXA_ALOG_OBSV_BUS_STATUS_1 0x1304
+#define USB3_DP_QSERDES_RXA_UCDR_FO_GAIN_HALF 0x1400
+#define USB3_DP_QSERDES_RXA_UCDR_FO_GAIN_QUARTER 0x1404
+#define USB3_DP_QSERDES_RXA_UCDR_FO_GAIN 0x1408
+#define USB3_DP_QSERDES_RXA_UCDR_SO_GAIN_HALF 0x140c
+#define USB3_DP_QSERDES_RXA_UCDR_SO_GAIN_QUARTER 0x1410
+#define USB3_DP_QSERDES_RXA_UCDR_SO_GAIN 0x1414
+#define USB3_DP_QSERDES_RXA_UCDR_SVS_FO_GAIN_HALF 0x1418
+#define USB3_DP_QSERDES_RXA_UCDR_SVS_FO_GAIN_QUARTER 0x141c
+#define USB3_DP_QSERDES_RXA_UCDR_SVS_FO_GAIN 0x1420
+#define USB3_DP_QSERDES_RXA_UCDR_SVS_SO_GAIN_HALF 0x1424
+#define USB3_DP_QSERDES_RXA_UCDR_SVS_SO_GAIN_QUARTER 0x1428
+#define USB3_DP_QSERDES_RXA_UCDR_SVS_SO_GAIN 0x142c
+#define USB3_DP_QSERDES_RXA_UCDR_FASTLOCK_FO_GAIN 0x1430
+#define USB3_DP_QSERDES_RXA_UCDR_SO_SATURATION_AND_ENABLE 0x1434
+#define USB3_DP_QSERDES_RXA_UCDR_FO_TO_SO_DELAY 0x1438
+#define USB3_DP_QSERDES_RXA_UCDR_FASTLOCK_COUNT_LOW 0x143c
+#define USB3_DP_QSERDES_RXA_UCDR_FASTLOCK_COUNT_HIGH 0x1440
+#define USB3_DP_QSERDES_RXA_UCDR_PI_CONTROLS 0x1444
+#define USB3_DP_QSERDES_RXA_UCDR_SB2_THRESH1 0x1448
+#define USB3_DP_QSERDES_RXA_UCDR_SB2_THRESH2 0x144c
+#define USB3_DP_QSERDES_RXA_UCDR_SB2_GAIN1 0x1450
+#define USB3_DP_QSERDES_RXA_UCDR_SB2_GAIN2 0x1454
+#define USB3_DP_QSERDES_RXA_AUX_CONTROL 0x1458
+#define USB3_DP_QSERDES_RXA_AUX_DATA_TCOARSE_TFINE 0x145c
+#define USB3_DP_QSERDES_RXA_RCLK_AUXDATA_SEL 0x1460
+#define USB3_DP_QSERDES_RXA_AC_JTAG_ENABLE 0x1464
+#define USB3_DP_QSERDES_RXA_AC_JTAG_INITP 0x1468
+#define USB3_DP_QSERDES_RXA_AC_JTAG_INITN 0x146c
+#define USB3_DP_QSERDES_RXA_AC_JTAG_LVL 0x1470
+#define USB3_DP_QSERDES_RXA_AC_JTAG_MODE 0x1474
+#define USB3_DP_QSERDES_RXA_AC_JTAG_RESET 0x1478
+#define USB3_DP_QSERDES_RXA_RX_TERM_BW 0x147c
+#define USB3_DP_QSERDES_RXA_RX_RCVR_IQ_EN 0x1480
+#define USB3_DP_QSERDES_RXA_RX_IDAC_I_DC_OFFSETS 0x1484
+#define USB3_DP_QSERDES_RXA_RX_IDAC_IBAR_DC_OFFSETS 0x1488
+#define USB3_DP_QSERDES_RXA_RX_IDAC_Q_DC_OFFSETS 0x148c
+#define USB3_DP_QSERDES_RXA_RX_IDAC_QBAR_DC_OFFSETS 0x1490
+#define USB3_DP_QSERDES_RXA_RX_IDAC_A_DC_OFFSETS 0x1494
+#define USB3_DP_QSERDES_RXA_RX_IDAC_ABAR_DC_OFFSETS 0x1498
+#define USB3_DP_QSERDES_RXA_RX_IDAC_EN 0x149c
+#define USB3_DP_QSERDES_RXA_RX_IDAC_ENABLES 0x14a0
+#define USB3_DP_QSERDES_RXA_RX_IDAC_SIGN 0x14a4
+#define USB3_DP_QSERDES_RXA_RX_HIGHZ_HIGHRATE 0x14a8
+#define USB3_DP_QSERDES_RXA_RX_TERM_AC_BYPASS_DC_COUPLE_OFFSET 0x14ac
+#define USB3_DP_QSERDES_RXA_DFE_1 0x14b0
+#define USB3_DP_QSERDES_RXA_DFE_2 0x14b4
+#define USB3_DP_QSERDES_RXA_DFE_3 0x14b8
+#define USB3_DP_QSERDES_RXA_VGA_CAL_CNTRL1 0x14bc
+#define USB3_DP_QSERDES_RXA_VGA_CAL_CNTRL2 0x14c0
+#define USB3_DP_QSERDES_RXA_GM_CAL 0x14c4
+#define USB3_DP_QSERDES_RXA_RX_EQ_GAIN2_LSB 0x14c8
+#define USB3_DP_QSERDES_RXA_RX_EQ_GAIN2_MSB 0x14cc
+#define USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL1 0x14d0
+#define USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL2 0x14d4
+#define USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL3 0x14d8
+#define USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL4 0x14dc
+#define USB3_DP_QSERDES_RXA_RX_IDAC_TSETTLE_LOW 0x14e0
+#define USB3_DP_QSERDES_RXA_RX_IDAC_TSETTLE_HIGH 0x14e4
+#define USB3_DP_QSERDES_RXA_RX_IDAC_MEASURE_TIME 0x14e8
+#define USB3_DP_QSERDES_RXA_RX_IDAC_ACCUMULATOR 0x14ec
+#define USB3_DP_QSERDES_RXA_RX_EQ_OFFSET_LSB 0x14f0
+#define USB3_DP_QSERDES_RXA_RX_EQ_OFFSET_MSB 0x14f4
+#define USB3_DP_QSERDES_RXA_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x14f8
+#define USB3_DP_QSERDES_RXA_RX_OFFSET_ADAPTOR_CNTRL2 0x14fc
+#define USB3_DP_QSERDES_RXA_SIGDET_ENABLES 0x1500
+#define USB3_DP_QSERDES_RXA_SIGDET_CNTRL 0x1504
+#define USB3_DP_QSERDES_RXA_SIGDET_LVL 0x1508
+#define USB3_DP_QSERDES_RXA_SIGDET_DEGLITCH_CNTRL 0x150c
+#define USB3_DP_QSERDES_RXA_RX_BAND 0x1510
+#define USB3_DP_QSERDES_RXA_CDR_FREEZE_UP_DN 0x1514
+#define USB3_DP_QSERDES_RXA_CDR_RESET_OVERRIDE 0x1518
+#define USB3_DP_QSERDES_RXA_RX_INTERFACE_MODE 0x151c
+#define USB3_DP_QSERDES_RXA_JITTER_GEN_MODE 0x1520
+#define USB3_DP_QSERDES_RXA_BUJ_AMP 0x1524
+#define USB3_DP_QSERDES_RXA_SJ_AMP1 0x1528
+#define USB3_DP_QSERDES_RXA_SJ_AMP2 0x152c
+#define USB3_DP_QSERDES_RXA_SJ_PER1 0x1530
+#define USB3_DP_QSERDES_RXA_SJ_PER2 0x1534
+#define USB3_DP_QSERDES_RXA_BUJ_STEP_FREQ1 0x1538
+#define USB3_DP_QSERDES_RXA_BUJ_STEP_FREQ2 0x153c
+#define USB3_DP_QSERDES_RXA_PPM_OFFSET1 0x1540
+#define USB3_DP_QSERDES_RXA_PPM_OFFSET2 0x1544
+#define USB3_DP_QSERDES_RXA_SIGN_PPM_PERIOD1 0x1548
+#define USB3_DP_QSERDES_RXA_SIGN_PPM_PERIOD2 0x154c
+#define USB3_DP_QSERDES_RXA_RX_PWM_ENABLE_AND_DATA 0x1550
+#define USB3_DP_QSERDES_RXA_RX_PWM_GEAR1_TIMEOUT_COUNT 0x1554
+#define USB3_DP_QSERDES_RXA_RX_PWM_GEAR2_TIMEOUT_COUNT 0x1558
+#define USB3_DP_QSERDES_RXA_RX_PWM_GEAR3_TIMEOUT_COUNT 0x155c
+#define USB3_DP_QSERDES_RXA_RX_PWM_GEAR4_TIMEOUT_COUNT 0x1560
+#define USB3_DP_QSERDES_RXA_RX_MODE_00 0x1564
+#define USB3_DP_QSERDES_RXA_RX_MODE_01 0x1568
+#define USB3_DP_QSERDES_RXA_RX_MODE_10 0x156c
+#define USB3_DP_QSERDES_RXA_ALOG_OBSV_BUS_CTRL_1 0x1570
+#define USB3_DP_QSERDES_RXA_PI_CTRL1 0x1574
+#define USB3_DP_QSERDES_RXA_PI_CTRL2 0x1578
+#define USB3_DP_QSERDES_RXA_PI_QUAD 0x157c
+#define USB3_DP_QSERDES_RXA_IDATA1 0x1580
+#define USB3_DP_QSERDES_RXA_IDATA2 0x1584
+#define USB3_DP_QSERDES_RXA_AUX_DATA1 0x1588
+#define USB3_DP_QSERDES_RXA_AUX_DATA2 0x158c
+#define USB3_DP_QSERDES_RXA_AC_JTAG_OUTP 0x1590
+#define USB3_DP_QSERDES_RXA_AC_JTAG_OUTN 0x1594
+#define USB3_DP_QSERDES_RXA_RX_SIGDET 0x1598
+#define USB3_DP_QSERDES_RXA_IDAC_STATUS_I 0x159c
+#define USB3_DP_QSERDES_RXA_IDAC_STATUS_IBAR 0x15a0
+#define USB3_DP_QSERDES_RXA_IDAC_STATUS_Q 0x15a4
+#define USB3_DP_QSERDES_RXA_IDAC_STATUS_QBAR 0x15a8
+#define USB3_DP_QSERDES_RXA_IDAC_STATUS_A 0x15ac
+#define USB3_DP_QSERDES_RXA_IDAC_STATUS_ABAR 0x15b0
+#define USB3_DP_QSERDES_RXA_IDAC_STATUS_SM_ON 0x15b4
+#define USB3_DP_QSERDES_RXA_IDAC_STATUS_CAL_DONE 0x15b8
+#define USB3_DP_QSERDES_RXA_IDAC_STATUS_SIGNERROR 0x15bc
+#define USB3_DP_QSERDES_RXA_READ_EQCODE 0x15c0
+#define USB3_DP_QSERDES_RXA_READ_OFFSETCODE 0x15c4
+#define USB3_DP_QSERDES_RXA_IA_ERROR_COUNTER_LOW 0x15c8
+#define USB3_DP_QSERDES_RXA_IA_ERROR_COUNTER_HIGH 0x15cc
+#define USB3_DP_QSERDES_RXA_VGA_READ_CODE 0x15d0
+#define USB3_DP_QSERDES_RXA_DFE_TAP1_READ_CODE 0x15d4
+#define USB3_DP_QSERDES_RXA_DFE_TAP2_READ_CODE 0x15d8
+#define USB3_DP_QSERDES_RXA_ALOG_OBSV_BUS_STATUS_1 0x15dc
+#define USB3_DP_QSERDES_TXB_BIST_MODE_LANENO 0x1600
+#define USB3_DP_QSERDES_TXB_BIST_INVERT 0x1604
+#define USB3_DP_QSERDES_TXB_CLKBUF_ENABLE 0x1608
+#define USB3_DP_QSERDES_TXB_TX_EMP_POST1_LVL 0x160c
+#define USB3_DP_QSERDES_TXB_TX_POST2_EMPH 0x1610
+#define USB3_DP_QSERDES_TXB_TX_BOOST_LVL_UP_DN 0x1614
+#define USB3_DP_QSERDES_TXB_TX_IDLE_LVL_LARGE_AMP 0x1618
+#define USB3_DP_QSERDES_TXB_TX_DRV_LVL 0x161c
+#define USB3_DP_QSERDES_TXB_TX_DRV_LVL_OFFSET 0x1620
+#define USB3_DP_QSERDES_TXB_RESET_TSYNC_EN 0x1624
+#define USB3_DP_QSERDES_TXB_PRE_STALL_LDO_BOOST_EN 0x1628
+#define USB3_DP_QSERDES_TXB_TX_BAND 0x162c
+#define USB3_DP_QSERDES_TXB_SLEW_CNTL 0x1630
+#define USB3_DP_QSERDES_TXB_INTERFACE_SELECT 0x1634
+#define USB3_DP_QSERDES_TXB_LPB_EN 0x1638
+#define USB3_DP_QSERDES_TXB_RES_CODE_LANE_TX 0x163c
+#define USB3_DP_QSERDES_TXB_RES_CODE_LANE_RX 0x1640
+#define USB3_DP_QSERDES_TXB_RES_CODE_LANE_OFFSET_TX 0x1644
+#define USB3_DP_QSERDES_TXB_RES_CODE_LANE_OFFSET_RX 0x1648
+#define USB3_DP_QSERDES_TXB_PERL_LENGTH1 0x164c
+#define USB3_DP_QSERDES_TXB_PERL_LENGTH2 0x1650
+#define USB3_DP_QSERDES_TXB_SERDES_BYP_EN_OUT 0x1654
+#define USB3_DP_QSERDES_TXB_DEBUG_BUS_SEL 0x1658
+#define USB3_DP_QSERDES_TXB_TRANSCEIVER_BIAS_EN 0x165c
+#define USB3_DP_QSERDES_TXB_HIGHZ_DRVR_EN 0x1660
+#define USB3_DP_QSERDES_TXB_TX_POL_INV 0x1664
+#define USB3_DP_QSERDES_TXB_PARRATE_REC_DETECT_IDLE_EN 0x1668
+#define USB3_DP_QSERDES_TXB_BIST_PATTERN1 0x166c
+#define USB3_DP_QSERDES_TXB_BIST_PATTERN2 0x1670
+#define USB3_DP_QSERDES_TXB_BIST_PATTERN3 0x1674
+#define USB3_DP_QSERDES_TXB_BIST_PATTERN4 0x1678
+#define USB3_DP_QSERDES_TXB_BIST_PATTERN5 0x167c
+#define USB3_DP_QSERDES_TXB_BIST_PATTERN6 0x1680
+#define USB3_DP_QSERDES_TXB_BIST_PATTERN7 0x1684
+#define USB3_DP_QSERDES_TXB_BIST_PATTERN8 0x1688
+#define USB3_DP_QSERDES_TXB_LANE_MODE_1 0x168c
+#define USB3_DP_QSERDES_TXB_LANE_MODE_2 0x1690
+#define USB3_DP_QSERDES_TXB_LANE_MODE_3 0x1694
+#define USB3_DP_QSERDES_TXB_ATB_SEL1 0x1698
+#define USB3_DP_QSERDES_TXB_ATB_SEL2 0x169c
+#define USB3_DP_QSERDES_TXB_RCV_DETECT_LVL 0x16a0
+#define USB3_DP_QSERDES_TXB_RCV_DETECT_LVL_2 0x16a4
+#define USB3_DP_QSERDES_TXB_PRBS_SEED1 0x16a8
+#define USB3_DP_QSERDES_TXB_PRBS_SEED2 0x16ac
+#define USB3_DP_QSERDES_TXB_PRBS_SEED3 0x16b0
+#define USB3_DP_QSERDES_TXB_PRBS_SEED4 0x16b4
+#define USB3_DP_QSERDES_TXB_RESET_GEN 0x16b8
+#define USB3_DP_QSERDES_TXB_RESET_GEN_MUXES 0x16bc
+#define USB3_DP_QSERDES_TXB_TRAN_DRVR_EMP_EN 0x16c0
+#define USB3_DP_QSERDES_TXB_TX_INTERFACE_MODE 0x16c4
+#define USB3_DP_QSERDES_TXB_PWM_CTRL 0x16c8
+#define USB3_DP_QSERDES_TXB_PWM_ENCODED_OR_DATA 0x16cc
+#define USB3_DP_QSERDES_TXB_PWM_GEAR_1_DIVIDER_BAND2 0x16d0
+#define USB3_DP_QSERDES_TXB_PWM_GEAR_2_DIVIDER_BAND2 0x16d4
+#define USB3_DP_QSERDES_TXB_PWM_GEAR_3_DIVIDER_BAND2 0x16d8
+#define USB3_DP_QSERDES_TXB_PWM_GEAR_4_DIVIDER_BAND2 0x16dc
+#define USB3_DP_QSERDES_TXB_PWM_GEAR_1_DIVIDER_BAND0_1 0x16e0
+#define USB3_DP_QSERDES_TXB_PWM_GEAR_2_DIVIDER_BAND0_1 0x16e4
+#define USB3_DP_QSERDES_TXB_PWM_GEAR_3_DIVIDER_BAND0_1 0x16e8
+#define USB3_DP_QSERDES_TXB_PWM_GEAR_4_DIVIDER_BAND0_1 0x16ec
+#define USB3_DP_QSERDES_TXB_VMODE_CTRL1 0x16f0
+#define USB3_DP_QSERDES_TXB_ALOG_OBSV_BUS_CTRL_1 0x16f4
+#define USB3_DP_QSERDES_TXB_BIST_STATUS 0x16f8
+#define USB3_DP_QSERDES_TXB_BIST_ERROR_COUNT1 0x16fc
+#define USB3_DP_QSERDES_TXB_BIST_ERROR_COUNT2 0x1700
+#define USB3_DP_QSERDES_TXB_ALOG_OBSV_BUS_STATUS_1 0x1704
+#define USB3_DP_QSERDES_RXB_UCDR_FO_GAIN_HALF 0x1800
+#define USB3_DP_QSERDES_RXB_UCDR_FO_GAIN_QUARTER 0x1804
+#define USB3_DP_QSERDES_RXB_UCDR_FO_GAIN 0x1808
+#define USB3_DP_QSERDES_RXB_UCDR_SO_GAIN_HALF 0x180c
+#define USB3_DP_QSERDES_RXB_UCDR_SO_GAIN_QUARTER 0x1810
+#define USB3_DP_QSERDES_RXB_UCDR_SO_GAIN 0x1814
+#define USB3_DP_QSERDES_RXB_UCDR_SVS_FO_GAIN_HALF 0x1818
+#define USB3_DP_QSERDES_RXB_UCDR_SVS_FO_GAIN_QUARTER 0x181c
+#define USB3_DP_QSERDES_RXB_UCDR_SVS_FO_GAIN 0x1820
+#define USB3_DP_QSERDES_RXB_UCDR_SVS_SO_GAIN_HALF 0x1824
+#define USB3_DP_QSERDES_RXB_UCDR_SVS_SO_GAIN_QUARTER 0x1828
+#define USB3_DP_QSERDES_RXB_UCDR_SVS_SO_GAIN 0x182c
+#define USB3_DP_QSERDES_RXB_UCDR_FASTLOCK_FO_GAIN 0x1830
+#define USB3_DP_QSERDES_RXB_UCDR_SO_SATURATION_AND_ENABLE 0x1834
+#define USB3_DP_QSERDES_RXB_UCDR_FO_TO_SO_DELAY 0x1838
+#define USB3_DP_QSERDES_RXB_UCDR_FASTLOCK_COUNT_LOW 0x183c
+#define USB3_DP_QSERDES_RXB_UCDR_FASTLOCK_COUNT_HIGH 0x1840
+#define USB3_DP_QSERDES_RXB_UCDR_PI_CONTROLS 0x1844
+#define USB3_DP_QSERDES_RXB_UCDR_SB2_THRESH1 0x1848
+#define USB3_DP_QSERDES_RXB_UCDR_SB2_THRESH2 0x184c
+#define USB3_DP_QSERDES_RXB_UCDR_SB2_GAIN1 0x1850
+#define USB3_DP_QSERDES_RXB_UCDR_SB2_GAIN2 0x1854
+#define USB3_DP_QSERDES_RXB_AUX_CONTROL 0x1858
+#define USB3_DP_QSERDES_RXB_AUX_DATA_TCOARSE_TFINE 0x185c
+#define USB3_DP_QSERDES_RXB_RCLK_AUXDATA_SEL 0x1860
+#define USB3_DP_QSERDES_RXB_AC_JTAG_ENABLE 0x1864
+#define USB3_DP_QSERDES_RXB_AC_JTAG_INITP 0x1868
+#define USB3_DP_QSERDES_RXB_AC_JTAG_INITN 0x186c
+#define USB3_DP_QSERDES_RXB_AC_JTAG_LVL 0x1870
+#define USB3_DP_QSERDES_RXB_AC_JTAG_MODE 0x1874
+#define USB3_DP_QSERDES_RXB_AC_JTAG_RESET 0x1878
+#define USB3_DP_QSERDES_RXB_RX_TERM_BW 0x187c
+#define USB3_DP_QSERDES_RXB_RX_RCVR_IQ_EN 0x1880
+#define USB3_DP_QSERDES_RXB_RX_IDAC_I_DC_OFFSETS 0x1884
+#define USB3_DP_QSERDES_RXB_RX_IDAC_IBAR_DC_OFFSETS 0x1888
+#define USB3_DP_QSERDES_RXB_RX_IDAC_Q_DC_OFFSETS 0x188c
+#define USB3_DP_QSERDES_RXB_RX_IDAC_QBAR_DC_OFFSETS 0x1890
+#define USB3_DP_QSERDES_RXB_RX_IDAC_A_DC_OFFSETS 0x1894
+#define USB3_DP_QSERDES_RXB_RX_IDAC_ABAR_DC_OFFSETS 0x1898
+#define USB3_DP_QSERDES_RXB_RX_IDAC_EN 0x189c
+#define USB3_DP_QSERDES_RXB_RX_IDAC_ENABLES 0x18a0
+#define USB3_DP_QSERDES_RXB_RX_IDAC_SIGN 0x18a4
+#define USB3_DP_QSERDES_RXB_RX_HIGHZ_HIGHRATE 0x18a8
+#define USB3_DP_QSERDES_RXB_RX_TERM_AC_BYPASS_DC_COUPLE_OFFSET 0x18ac
+#define USB3_DP_QSERDES_RXB_DFE_1 0x18b0
+#define USB3_DP_QSERDES_RXB_DFE_2 0x18b4
+#define USB3_DP_QSERDES_RXB_DFE_3 0x18b8
+#define USB3_DP_QSERDES_RXB_VGA_CAL_CNTRL1 0x18bc
+#define USB3_DP_QSERDES_RXB_VGA_CAL_CNTRL2 0x18c0
+#define USB3_DP_QSERDES_RXB_GM_CAL 0x18c4
+#define USB3_DP_QSERDES_RXB_RX_EQ_GAIN2_LSB 0x18c8
+#define USB3_DP_QSERDES_RXB_RX_EQ_GAIN2_MSB 0x18cc
+#define USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL1 0x18d0
+#define USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL2 0x18d4
+#define USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL3 0x18d8
+#define USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL4 0x18dc
+#define USB3_DP_QSERDES_RXB_RX_IDAC_TSETTLE_LOW 0x18e0
+#define USB3_DP_QSERDES_RXB_RX_IDAC_TSETTLE_HIGH 0x18e4
+#define USB3_DP_QSERDES_RXB_RX_IDAC_MEASURE_TIME 0x18e8
+#define USB3_DP_QSERDES_RXB_RX_IDAC_ACCUMULATOR 0x18ec
+#define USB3_DP_QSERDES_RXB_RX_EQ_OFFSET_LSB 0x18f0
+#define USB3_DP_QSERDES_RXB_RX_EQ_OFFSET_MSB 0x18f4
+#define USB3_DP_QSERDES_RXB_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x18f8
+#define USB3_DP_QSERDES_RXB_RX_OFFSET_ADAPTOR_CNTRL2 0x18fc
+#define USB3_DP_QSERDES_RXB_SIGDET_ENABLES 0x1900
+#define USB3_DP_QSERDES_RXB_SIGDET_CNTRL 0x1904
+#define USB3_DP_QSERDES_RXB_SIGDET_LVL 0x1908
+#define USB3_DP_QSERDES_RXB_SIGDET_DEGLITCH_CNTRL 0x190c
+#define USB3_DP_QSERDES_RXB_RX_BAND 0x1910
+#define USB3_DP_QSERDES_RXB_CDR_FREEZE_UP_DN 0x1914
+#define USB3_DP_QSERDES_RXB_CDR_RESET_OVERRIDE 0x1918
+#define USB3_DP_QSERDES_RXB_RX_INTERFACE_MODE 0x191c
+#define USB3_DP_QSERDES_RXB_JITTER_GEN_MODE 0x1920
+#define USB3_DP_QSERDES_RXB_BUJ_AMP 0x1924
+#define USB3_DP_QSERDES_RXB_SJ_AMP1 0x1928
+#define USB3_DP_QSERDES_RXB_SJ_AMP2 0x192c
+#define USB3_DP_QSERDES_RXB_SJ_PER1 0x1930
+#define USB3_DP_QSERDES_RXB_SJ_PER2 0x1934
+#define USB3_DP_QSERDES_RXB_BUJ_STEP_FREQ1 0x1938
+#define USB3_DP_QSERDES_RXB_BUJ_STEP_FREQ2 0x193c
+#define USB3_DP_QSERDES_RXB_PPM_OFFSET1 0x1940
+#define USB3_DP_QSERDES_RXB_PPM_OFFSET2 0x1944
+#define USB3_DP_QSERDES_RXB_SIGN_PPM_PERIOD1 0x1948
+#define USB3_DP_QSERDES_RXB_SIGN_PPM_PERIOD2 0x194c
+#define USB3_DP_QSERDES_RXB_RX_PWM_ENABLE_AND_DATA 0x1950
+#define USB3_DP_QSERDES_RXB_RX_PWM_GEAR1_TIMEOUT_COUNT 0x1954
+#define USB3_DP_QSERDES_RXB_RX_PWM_GEAR2_TIMEOUT_COUNT 0x1958
+#define USB3_DP_QSERDES_RXB_RX_PWM_GEAR3_TIMEOUT_COUNT 0x195c
+#define USB3_DP_QSERDES_RXB_RX_PWM_GEAR4_TIMEOUT_COUNT 0x1960
+#define USB3_DP_QSERDES_RXB_RX_MODE_00 0x1964
+#define USB3_DP_QSERDES_RXB_RX_MODE_01 0x1968
+#define USB3_DP_QSERDES_RXB_RX_MODE_10 0x196c
+#define USB3_DP_QSERDES_RXB_ALOG_OBSV_BUS_CTRL_1 0x1970
+#define USB3_DP_QSERDES_RXB_PI_CTRL1 0x1974
+#define USB3_DP_QSERDES_RXB_PI_CTRL2 0x1978
+#define USB3_DP_QSERDES_RXB_PI_QUAD 0x197c
+#define USB3_DP_QSERDES_RXB_IDATA1 0x1980
+#define USB3_DP_QSERDES_RXB_IDATA2 0x1984
+#define USB3_DP_QSERDES_RXB_AUX_DATA1 0x1988
+#define USB3_DP_QSERDES_RXB_AUX_DATA2 0x198c
+#define USB3_DP_QSERDES_RXB_AC_JTAG_OUTP 0x1990
+#define USB3_DP_QSERDES_RXB_AC_JTAG_OUTN 0x1994
+#define USB3_DP_QSERDES_RXB_RX_SIGDET 0x1998
+#define USB3_DP_QSERDES_RXB_IDAC_STATUS_I 0x199c
+#define USB3_DP_QSERDES_RXB_IDAC_STATUS_IBAR 0x19a0
+#define USB3_DP_QSERDES_RXB_IDAC_STATUS_Q 0x19a4
+#define USB3_DP_QSERDES_RXB_IDAC_STATUS_QBAR 0x19a8
+#define USB3_DP_QSERDES_RXB_IDAC_STATUS_A 0x19ac
+#define USB3_DP_QSERDES_RXB_IDAC_STATUS_ABAR 0x19b0
+#define USB3_DP_QSERDES_RXB_IDAC_STATUS_SM_ON 0x19b4
+#define USB3_DP_QSERDES_RXB_IDAC_STATUS_CAL_DONE 0x19b8
+#define USB3_DP_QSERDES_RXB_IDAC_STATUS_SIGNERROR 0x19bc
+#define USB3_DP_QSERDES_RXB_READ_EQCODE 0x19c0
+#define USB3_DP_QSERDES_RXB_READ_OFFSETCODE 0x19c4
+#define USB3_DP_QSERDES_RXB_IA_ERROR_COUNTER_LOW 0x19c8
+#define USB3_DP_QSERDES_RXB_IA_ERROR_COUNTER_HIGH 0x19cc
+#define USB3_DP_QSERDES_RXB_VGA_READ_CODE 0x19d0
+#define USB3_DP_QSERDES_RXB_DFE_TAP1_READ_CODE 0x19d4
+#define USB3_DP_QSERDES_RXB_DFE_TAP2_READ_CODE 0x19d8
+#define USB3_DP_QSERDES_RXB_ALOG_OBSV_BUS_STATUS_1 0x19dc
+#define USB3_DP_PCS_MISC_TYPEC_CTRL 0x1a00
+#define USB3_DP_PCS_MISC_TYPEC_PWRDN_CTRL 0x1a04
+#define USB3_DP_PCS_MISC_PCS_MISC_CONFIG1 0x1a08
+#define USB3_DP_PCS_MISC_CLAMP_ENABLE 0x1a0c
+#define USB3_DP_PCS_MISC_TYPEC_STATUS 0x1a10
+#define USB3_DP_PCS_MISC_PLACEHOLDER_STATUS 0x1a14
+#define USB3_DP_PCS_SW_RESET 0x1c00
+#define USB3_DP_PCS_POWER_DOWN_CONTROL 0x1c04
+#define USB3_DP_PCS_START_CONTROL 0x1c08
+#define USB3_DP_PCS_TXMGN_V0 0x1c0c
+#define USB3_DP_PCS_TXMGN_V1 0x1c10
+#define USB3_DP_PCS_TXMGN_V2 0x1c14
+#define USB3_DP_PCS_TXMGN_V3 0x1c18
+#define USB3_DP_PCS_TXMGN_V4 0x1c1c
+#define USB3_DP_PCS_TXMGN_LS 0x1c20
+#define USB3_DP_PCS_TXDEEMPH_M6DB_V0 0x1c24
+#define USB3_DP_PCS_TXDEEMPH_M3P5DB_V0 0x1c28
+#define USB3_DP_PCS_TXDEEMPH_M6DB_V1 0x1c2c
+#define USB3_DP_PCS_TXDEEMPH_M3P5DB_V1 0x1c30
+#define USB3_DP_PCS_TXDEEMPH_M6DB_V2 0x1c34
+#define USB3_DP_PCS_TXDEEMPH_M3P5DB_V2 0x1c38
+#define USB3_DP_PCS_TXDEEMPH_M6DB_V3 0x1c3c
+#define USB3_DP_PCS_TXDEEMPH_M3P5DB_V3 0x1c40
+#define USB3_DP_PCS_TXDEEMPH_M6DB_V4 0x1c44
+#define USB3_DP_PCS_TXDEEMPH_M3P5DB_V4 0x1c48
+#define USB3_DP_PCS_TXDEEMPH_M6DB_LS 0x1c4c
+#define USB3_DP_PCS_TXDEEMPH_M3P5DB_LS 0x1c50
+#define USB3_DP_PCS_ENDPOINT_REFCLK_DRIVE 0x1c54
+#define USB3_DP_PCS_RX_IDLE_DTCT_CNTRL 0x1c58
+#define USB3_DP_PCS_RATE_SLEW_CNTRL 0x1c5c
+#define USB3_DP_PCS_POWER_STATE_CONFIG1 0x1c60
+#define USB3_DP_PCS_POWER_STATE_CONFIG2 0x1c64
+#define USB3_DP_PCS_POWER_STATE_CONFIG3 0x1c68
+#define USB3_DP_PCS_POWER_STATE_CONFIG4 0x1c6c
+#define USB3_DP_PCS_RCVR_DTCT_DLY_P1U2_L 0x1c70
+#define USB3_DP_PCS_RCVR_DTCT_DLY_P1U2_H 0x1c74
+#define USB3_DP_PCS_RCVR_DTCT_DLY_U3_L 0x1c78
+#define USB3_DP_PCS_RCVR_DTCT_DLY_U3_H 0x1c7c
+#define USB3_DP_PCS_LOCK_DETECT_CONFIG1 0x1c80
+#define USB3_DP_PCS_LOCK_DETECT_CONFIG2 0x1c84
+#define USB3_DP_PCS_LOCK_DETECT_CONFIG3 0x1c88
+#define USB3_DP_PCS_TSYNC_RSYNC_TIME 0x1c8c
+#define USB3_DP_PCS_SIGDET_LOW_2_IDLE_TIME 0x1c90
+#define USB3_DP_PCS_BEACON_2_IDLE_TIME_L 0x1c94
+#define USB3_DP_PCS_BEACON_2_IDLE_TIME_H 0x1c98
+#define USB3_DP_PCS_PWRUP_RESET_DLY_TIME_SYSCLK 0x1c9c
+#define USB3_DP_PCS_PWRUP_RESET_DLY_TIME_AUXCLK 0x1ca0
+#define USB3_DP_PCS_LP_WAKEUP_DLY_TIME_AUXCLK 0x1ca4
+#define USB3_DP_PCS_PLL_LOCK_CHK_DLY_TIME 0x1ca8
+#define USB3_DP_PCS_LFPS_DET_HIGH_COUNT_VAL 0x1cac
+#define USB3_DP_PCS_LFPS_TX_ECSTART_EQTLOCK 0x1cb0
+#define USB3_DP_PCS_LFPS_TX_END_CNT_P2U3_START 0x1cb4
+#define USB3_DP_PCS_RXEQTRAINING_WAIT_TIME 0x1cb8
+#define USB3_DP_PCS_RXEQTRAINING_RUN_TIME 0x1cbc
+#define USB3_DP_PCS_TXONESZEROS_RUN_LENGTH 0x1cc0
+#define USB3_DP_PCS_FLL_CNTRL1 0x1cc4
+#define USB3_DP_PCS_FLL_CNTRL2 0x1cc8
+#define USB3_DP_PCS_FLL_CNT_VAL_L 0x1ccc
+#define USB3_DP_PCS_FLL_CNT_VAL_H_TOL 0x1cd0
+#define USB3_DP_PCS_FLL_MAN_CODE 0x1cd4
+#define USB3_DP_PCS_AUTONOMOUS_MODE_CTRL 0x1cd8
+#define USB3_DP_PCS_LFPS_RXTERM_IRQ_CLEAR 0x1cdc
+#define USB3_DP_PCS_ARCVR_DTCT_EN_PERIOD 0x1ce0
+#define USB3_DP_PCS_ARCVR_DTCT_CM_DLY 0x1ce4
+#define USB3_DP_PCS_ALFPS_DEGLITCH_VAL 0x1ce8
+#define USB3_DP_PCS_INSIG_SW_CTRL1 0x1cec
+#define USB3_DP_PCS_INSIG_SW_CTRL2 0x1cf0
+#define USB3_DP_PCS_INSIG_SW_CTRL3 0x1cf4
+#define USB3_DP_PCS_INSIG_MX_CTRL1 0x1cf8
+#define USB3_DP_PCS_INSIG_MX_CTRL2 0x1cfc
+#define USB3_DP_PCS_INSIG_MX_CTRL3 0x1d00
+#define USB3_DP_PCS_OUTSIG_SW_CTRL1 0x1d04
+#define USB3_DP_PCS_OUTSIG_MX_CTRL1 0x1d08
+#define USB3_DP_PCS_CLK_DEBUG_BYPASS_CTRL 0x1d0c
+#define USB3_DP_PCS_TEST_CONTROL 0x1d10
+#define USB3_DP_PCS_TEST_CONTROL2 0x1d14
+#define USB3_DP_PCS_TEST_CONTROL3 0x1d18
+#define USB3_DP_PCS_TEST_CONTROL4 0x1d1c
+#define USB3_DP_PCS_TEST_CONTROL5 0x1d20
+#define USB3_DP_PCS_TEST_CONTROL6 0x1d24
+#define USB3_DP_PCS_TEST_CONTROL7 0x1d28
+#define USB3_DP_PCS_COM_RESET_CONTROL 0x1d2c
+#define USB3_DP_PCS_BIST_CTRL 0x1d30
+#define USB3_DP_PCS_PRBS_POLY0 0x1d34
+#define USB3_DP_PCS_PRBS_POLY1 0x1d38
+#define USB3_DP_PCS_PRBS_SEED0 0x1d3c
+#define USB3_DP_PCS_PRBS_SEED1 0x1d40
+#define USB3_DP_PCS_FIXED_PAT_CTRL 0x1d44
+#define USB3_DP_PCS_FIXED_PAT0 0x1d48
+#define USB3_DP_PCS_FIXED_PAT1 0x1d4c
+#define USB3_DP_PCS_FIXED_PAT2 0x1d50
+#define USB3_DP_PCS_FIXED_PAT3 0x1d54
+#define USB3_DP_PCS_COM_CLK_SWITCH_CTRL 0x1d58
+#define USB3_DP_PCS_ELECIDLE_DLY_SEL 0x1d5c
+#define USB3_DP_PCS_SPARE1 0x1d60
+#define USB3_DP_PCS_BIST_CHK_ERR_CNT_L_STATUS 0x1d64
+#define USB3_DP_PCS_BIST_CHK_ERR_CNT_H_STATUS 0x1d68
+#define USB3_DP_PCS_BIST_CHK_STATUS 0x1d6c
+#define USB3_DP_PCS_LFPS_RXTERM_IRQ_SOURCE_STATUS 0x1d70
+#define USB3_DP_PCS_PCS_STATUS 0x1d74
+#define USB3_DP_PCS_PCS_STATUS2 0x1d78
+#define USB3_DP_PCS_PCS_STATUS3 0x1d7c
+#define USB3_DP_PCS_COM_RESET_STATUS 0x1d80
+#define USB3_DP_PCS_OSC_DTCT_STATUS 0x1d84
+#define USB3_DP_PCS_REVISION_ID0 0x1d88
+#define USB3_DP_PCS_REVISION_ID1 0x1d8c
+#define USB3_DP_PCS_REVISION_ID2 0x1d90
+#define USB3_DP_PCS_REVISION_ID3 0x1d94
+#define USB3_DP_PCS_DEBUG_BUS_0_STATUS 0x1d98
+#define USB3_DP_PCS_DEBUG_BUS_1_STATUS 0x1d9c
+#define USB3_DP_PCS_DEBUG_BUS_2_STATUS 0x1da0
+#define USB3_DP_PCS_DEBUG_BUS_3_STATUS 0x1da4
+#define USB3_DP_PCS_LP_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1da8
+#define USB3_DP_PCS_OSC_DTCT_ACTIONS 0x1dac
+#define USB3_DP_PCS_SIGDET_CNTRL 0x1db0
+#define USB3_DP_PCS_IDAC_CAL_CNTRL 0x1db4
+#define USB3_DP_PCS_CMN_ACK_OUT_SEL 0x1db8
+#define USB3_DP_PCS_PLL_LOCK_CHK_DLY_TIME_SYSCLK 0x1dbc
+#define USB3_DP_PCS_AUTONOMOUS_MODE_STATUS 0x1dc0
+#define USB3_DP_PCS_ENDPOINT_REFCLK_CNTRL 0x1dc4
+#define USB3_DP_PCS_EPCLK_PRE_PLL_LOCK_DLY_SYSCLK 0x1dc8
+#define USB3_DP_PCS_EPCLK_PRE_PLL_LOCK_DLY_AUXCLK 0x1dcc
+#define USB3_DP_PCS_EPCLK_DLY_COUNT_VAL_L 0x1dd0
+#define USB3_DP_PCS_EPCLK_DLY_COUNT_VAL_H 0x1dd4
+#define USB3_DP_PCS_RX_SIGDET_LVL 0x1dd8
+#define USB3_DP_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB 0x1ddc
+#define USB3_DP_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1de0
+#define USB3_DP_PCS_AUTONOMOUS_MODE_CTRL2 0x1de4
+#define USB3_DP_PCS_RXTERMINATION_DLY_SEL 0x1de8
+#define USB3_DP_PCS_LFPS_PER_TIMER_VAL 0x1dec
+#define USB3_DP_PCS_SIGDET_STARTUP_TIMER_VAL 0x1df0
+#define USB3_DP_PCS_LOCK_DETECT_CONFIG4 0x1df4
+#define USB3_DP_PCS_RX_SIGDET_DTCT_CNTRL 0x1df8
+#define USB3_DP_PCS_PCS_STATUS4 0x1dfc
+#define USB3_DP_PCS_PCS_STATUS4_CLEAR 0x1e00
+#define USB3_DP_PCS_DEC_ERROR_COUNT_STATUS 0x1e04
+#define USB3_DP_PCS_COMMA_POS_STATUS 0x1e08
+#define USB3_DP_PCS_REFGEN_REQ_CONFIG1 0x1e0c
+#define USB3_DP_PCS_REFGEN_REQ_CONFIG2 0x1e10
+#define USB3_DP_PCS_REFGEN_REQ_CONFIG3 0x1e14
+#define USB3_DP_PHY_DP_DP_PHY_PD_CTL 0x2a18
+
+#endif /* _DT_BINDINGS_PHY_QCOM_LAGOON_QMP_USB_H */
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index eaedca5f..345c3b5 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -23,6 +23,8 @@ struct ahci_host_priv;
struct platform_device;
struct scsi_host_template;
+int ahci_platform_enable_phys(struct ahci_host_priv *hpriv);
+void ahci_platform_disable_phys(struct ahci_host_priv *hpriv);
int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 6e44890..12cec9c 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -564,17 +564,6 @@ struct governor_attr {
size_t count);
};
-static inline bool cpufreq_this_cpu_can_update(struct cpufreq_policy *policy)
-{
- /*
- * Allow remote callbacks if:
- * - dvfs_possible_from_any_cpu flag is set
- * - the local and remote CPUs share cpufreq policy
- */
- return policy->dvfs_possible_from_any_cpu ||
- cpumask_test_cpu(smp_processor_id(), policy->cpus);
-}
-
/*********************************************************************
* FREQUENCY TABLE HELPERS *
*********************************************************************/
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index 934633a..7f1478c 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -40,14 +40,14 @@ static inline bool cpusets_enabled(void)
static inline void cpuset_inc(void)
{
- static_branch_inc(&cpusets_pre_enable_key);
- static_branch_inc(&cpusets_enabled_key);
+ static_branch_inc_cpuslocked(&cpusets_pre_enable_key);
+ static_branch_inc_cpuslocked(&cpusets_enabled_key);
}
static inline void cpuset_dec(void)
{
- static_branch_dec(&cpusets_enabled_key);
- static_branch_dec(&cpusets_pre_enable_key);
+ static_branch_dec_cpuslocked(&cpusets_enabled_key);
+ static_branch_dec_cpuslocked(&cpusets_pre_enable_key);
}
extern int cpuset_init(void);
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index d49ec5c..0647f43 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -1373,8 +1373,11 @@ static inline int dma_get_slave_caps(struct dma_chan *chan,
static inline int dmaengine_desc_set_reuse(struct dma_async_tx_descriptor *tx)
{
struct dma_slave_caps caps;
+ int ret;
- dma_get_slave_caps(tx->chan, &caps);
+ ret = dma_get_slave_caps(tx->chan, &caps);
+ if (ret)
+ return ret;
if (caps.descriptor_reuse) {
tx->flags |= DMA_CTRL_REUSE;
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 781c5b7..8bd9403 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -436,12 +436,18 @@ extern u64 hrtimer_next_event_without(const struct hrtimer *exclude);
extern bool hrtimer_active(const struct hrtimer *timer);
-/*
- * Helper function to check, whether the timer is on one of the queues
+/**
+ * hrtimer_is_queued = check, whether the timer is on one of the queues
+ * @timer: Timer to check
+ *
+ * Returns: True if the timer is queued, false otherwise
+ *
+ * The function can be used lockless, but it gives only a current snapshot.
*/
-static inline int hrtimer_is_queued(struct hrtimer *timer)
+static inline bool hrtimer_is_queued(struct hrtimer *timer)
{
- return timer->state & HRTIMER_STATE_ENQUEUED;
+ /* The READ_ONCE pairs with the update functions of timer->state */
+ return !!(READ_ONCE(timer->state) & HRTIMER_STATE_ENQUEUED);
}
/*
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 548fd53..d433f5e 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -28,6 +28,14 @@ static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
return (struct ethhdr *)skb_mac_header(skb);
}
+/* Prefer this version in TX path, instead of
+ * skb_reset_mac_header() + eth_hdr()
+ */
+static inline struct ethhdr *skb_eth_hdr(const struct sk_buff *skb)
+{
+ return (struct ethhdr *)skb->data;
+}
+
static inline struct ethhdr *inner_eth_hdr(const struct sk_buff *skb)
{
return (struct ethhdr *)skb_inner_mac_header(skb);
diff --git a/include/linux/io-pgtable-fast.h b/include/linux/io-pgtable-fast.h
index a77b1fc..3eeef26 100644
--- a/include/linux/io-pgtable-fast.h
+++ b/include/linux/io-pgtable-fast.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
*/
#ifndef __LINUX_IO_PGTABLE_FAST_H
@@ -79,7 +79,8 @@ av8l_fast_iova_to_phys_public(struct io_pgtable_ops *ops,
*/
#define AV8L_FAST_PTE_UNMAPPED_NEED_TLBI 0xa
-void av8l_fast_clear_stale_ptes(struct io_pgtable_ops *ops, bool skip_sync);
+void av8l_fast_clear_stale_ptes(struct io_pgtable_ops *ops, u64 base,
+ u64 start, u64 end, bool skip_sync);
void av8l_register_notify(struct notifier_block *nb);
#else /* !CONFIG_IOMMU_IO_PGTABLE_FAST_PROVE_TLB */
@@ -87,6 +88,9 @@ void av8l_register_notify(struct notifier_block *nb);
#define AV8L_FAST_PTE_UNMAPPED_NEED_TLBI 0
static inline void av8l_fast_clear_stale_ptes(struct io_pgtable_ops *ops,
+ u64 base,
+ u64 start,
+ u64 end,
bool skip_sync)
{
}
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h
index 7d5fd38..1995ce14 100644
--- a/include/linux/ipmi_smi.h
+++ b/include/linux/ipmi_smi.h
@@ -211,10 +211,14 @@ static inline int ipmi_demangle_device_id(uint8_t netfn, uint8_t cmd,
* is called, and the lower layer must get the interface from that
* call.
*/
-int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
- void *send_info,
- struct device *dev,
- unsigned char slave_addr);
+int ipmi_add_smi(struct module *owner,
+ const struct ipmi_smi_handlers *handlers,
+ void *send_info,
+ struct device *dev,
+ unsigned char slave_addr);
+
+#define ipmi_register_smi(handlers, send_info, dev, slave_addr) \
+ ipmi_add_smi(THIS_MODULE, handlers, send_info, dev, slave_addr)
/*
* Remove a low-level interface from the IPMI driver. This will
diff --git a/include/linux/leds-qti-flash.h b/include/linux/leds-qti-flash.h
new file mode 100644
index 0000000..f313d79
--- /dev/null
+++ b/include/linux/leds-qti-flash.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __LEDS_QTI_FLASH_H
+#define __LEDS_QTI_FLASH_H
+
+#include <linux/leds.h>
+
+#define QUERY_MAX_AVAIL_CURRENT BIT(0)
+
+#if IS_ENABLED(CONFIG_LEDS_QTI_FLASH)
+int qti_flash_led_prepare(struct led_trigger *trig,
+ int options, int *max_current);
+#else
+static inline int qti_flash_led_prepare(struct led_trigger *trig,
+ int options, int *max_current)
+{
+ return -EINVAL;
+}
+#endif
+#endif
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 38c95d6..aff09d0 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1190,6 +1190,7 @@ extern unsigned int ata_do_dev_read_id(struct ata_device *dev,
struct ata_taskfile *tf, u16 *id);
extern void ata_qc_complete(struct ata_queued_cmd *qc);
extern int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active);
+extern u64 ata_qc_get_active(struct ata_port *ap);
extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd);
extern int ata_std_bios_param(struct scsi_device *sdev,
struct block_device *bdev,
diff --git a/include/linux/libfdt_env.h b/include/linux/libfdt_env.h
index edb0f0c..1adf54a 100644
--- a/include/linux/libfdt_env.h
+++ b/include/linux/libfdt_env.h
@@ -7,6 +7,9 @@
#include <asm/byteorder.h>
+#define INT32_MAX S32_MAX
+#define UINT32_MAX U32_MAX
+
typedef __be16 fdt16_t;
typedef __be32 fdt32_t;
typedef __be64 fdt64_t;
diff --git a/include/linux/mhi.h b/include/linux/mhi.h
index cf7404a..1683035 100644
--- a/include/linux/mhi.h
+++ b/include/linux/mhi.h
@@ -263,6 +263,7 @@ struct mhi_controller {
void __iomem *bhi;
void __iomem *bhie;
void __iomem *wake_db;
+ void __iomem *tsync_db;
void __iomem *bw_scale_db;
/* device topology */
@@ -382,7 +383,6 @@ struct mhi_controller {
/* supports time sync feature */
struct mhi_timesync *mhi_tsync;
- struct mhi_device *tsync_dev;
u64 local_timer_freq;
u64 remote_timer_freq;
@@ -399,8 +399,7 @@ struct mhi_controller {
/* controller specific data */
const char *name;
bool power_down;
- bool need_force_m3;
- bool force_m3_done;
+ bool initiate_mhi_reset;
void *priv_data;
void *log_buf;
struct dentry *dentry;
@@ -777,6 +776,23 @@ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl);
void mhi_dump_sfr(struct mhi_controller *mhi_cntrl);
/**
+ * mhi_get_remote_time - Get external modem time relative to host time
+ * Trigger event to capture modem time, also capture host time so client
+ * can do a relative drift comparision.
+ * Recommended only tsync device calls this method and do not call this
+ * from atomic context
+ * @mhi_dev: Device associated with the channels
+ * @sequence:unique sequence id track event
+ * @cb_func: callback function to call back
+ */
+int mhi_get_remote_time(struct mhi_device *mhi_dev,
+ u32 sequence,
+ void (*cb_func)(struct mhi_device *mhi_dev,
+ u32 sequence,
+ u64 local_time,
+ u64 remote_time));
+
+/**
* mhi_get_remote_time_sync - Get external soc time relative to local soc time
* using MMIO method.
* @mhi_dev: Device associated with the channels
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 3247a3d..b06b757 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -57,6 +57,7 @@
#define UHID_MINOR 239
#define USERIO_MINOR 240
#define VHOST_VSOCK_MINOR 241
+#define RFKILL_MINOR 242
#define MISC_DYNAMIC_MINOR 255
struct device;
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 12b42dd..526e4d7 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -575,9 +575,9 @@ struct platform_device_id {
#define MDIO_NAME_SIZE 32
#define MDIO_MODULE_PREFIX "mdio:"
-#define MDIO_ID_FMT "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
+#define MDIO_ID_FMT "%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u"
#define MDIO_ID_ARGS(_id) \
- (_id)>>31, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \
+ ((_id)>>31) & 1, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \
((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \
((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \
((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4244d54..58b64a1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1619,6 +1619,8 @@ enum netdev_priv_flags {
* @perm_addr: Permanent hw address
* @addr_assign_type: Hw address assignment type
* @addr_len: Hardware address length
+ * @upper_level: Maximum depth level of upper devices.
+ * @lower_level: Maximum depth level of lower devices.
* @neigh_priv_len: Used in neigh_alloc()
* @dev_id: Used to differentiate devices that share
* the same link layer address
@@ -1853,6 +1855,8 @@ struct net_device {
unsigned char perm_addr[MAX_ADDR_LEN];
unsigned char addr_assign_type;
unsigned char addr_len;
+ unsigned char upper_level;
+ unsigned char lower_level;
unsigned short neigh_priv_len;
unsigned short dev_id;
unsigned short dev_port;
diff --git a/include/linux/nvme-fc-driver.h b/include/linux/nvme-fc-driver.h
index 496ff75..2f3ae41 100644
--- a/include/linux/nvme-fc-driver.h
+++ b/include/linux/nvme-fc-driver.h
@@ -282,6 +282,8 @@ struct nvme_fc_remote_port {
*
* Host/Initiator Transport Entrypoints/Parameters:
*
+ * @module: The LLDD module using the interface
+ *
* @localport_delete: The LLDD initiates deletion of a localport via
* nvme_fc_deregister_localport(). However, the teardown is
* asynchronous. This routine is called upon the completion of the
@@ -395,6 +397,8 @@ struct nvme_fc_remote_port {
* Value is Mandatory. Allowed to be zero.
*/
struct nvme_fc_port_template {
+ struct module *module;
+
/* initiator-based functions */
void (*localport_delete)(struct nvme_fc_local_port *);
void (*remoteport_delete)(struct nvme_fc_remote_port *);
diff --git a/include/linux/posix-clock.h b/include/linux/posix-clock.h
index 3a3bc71..03cb1f2 100644
--- a/include/linux/posix-clock.h
+++ b/include/linux/posix-clock.h
@@ -82,29 +82,32 @@ struct posix_clock_operations {
*
* @ops: Functional interface to the clock
* @cdev: Character device instance for this clock
- * @kref: Reference count.
+ * @dev: Pointer to the clock's device.
* @rwsem: Protects the 'zombie' field from concurrent access.
* @zombie: If 'zombie' is true, then the hardware has disappeared.
- * @release: A function to free the structure when the reference count reaches
- * zero. May be NULL if structure is statically allocated.
*
* Drivers should embed their struct posix_clock within a private
* structure, obtaining a reference to it during callbacks using
* container_of().
+ *
+ * Drivers should supply an initialized but not exposed struct device
+ * to posix_clock_register(). It is used to manage lifetime of the
+ * driver's private structure. It's 'release' field should be set to
+ * a release function for this private structure.
*/
struct posix_clock {
struct posix_clock_operations ops;
struct cdev cdev;
- struct kref kref;
+ struct device *dev;
struct rw_semaphore rwsem;
bool zombie;
- void (*release)(struct posix_clock *clk);
};
/**
* posix_clock_register() - register a new clock
- * @clk: Pointer to the clock. Caller must provide 'ops' and 'release'
- * @devid: Allocated device id
+ * @clk: Pointer to the clock. Caller must provide 'ops' field
+ * @dev: Pointer to the initialized device. Caller must provide
+ * 'release' field
*
* A clock driver calls this function to register itself with the
* clock device subsystem. If 'clk' points to dynamically allocated
@@ -113,7 +116,7 @@ struct posix_clock {
*
* Returns zero on success, non-zero otherwise.
*/
-int posix_clock_register(struct posix_clock *clk, dev_t devid);
+int posix_clock_register(struct posix_clock *clk, struct device *dev);
/**
* posix_clock_unregister() - unregister a clock
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index 4d809ef..02d7251 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
*/
#ifndef __QPNP_REVID
@@ -190,6 +190,15 @@
/* PMI632 */
#define PMI632_SUBTYPE 0x25
+/* PM6350 */
+#define PM6350_SUBTYPE 0x36
+
+/* PMK8350 */
+#define PMK8350_SUBTYPE 0x2F
+
+/* PMR735B */
+#define PMR735B_SUBTYPE 0x34
+
/* PM8008 SUBTYPE */
#define PM8008_SUBTYPE 0x2C
@@ -291,6 +300,30 @@
#define PM6125_V1P0_REV3 0x00
#define PM6125_V1P0_REV4 0x01
+/* PM2250_REV_ID */
+#define PM2250_V1P0_REV1 0x00
+#define PM2250_V1P0_REV2 0x01
+#define PM2250_V1P0_REV3 0x01
+#define PM2250_V1P0_REV4 0x01
+
+/* PM6350_REV_ID */
+#define PM6350_V1P0_REV1 0x10
+#define PM6350_V1P0_REV2 0x00
+#define PM6350_V1P0_REV3 0x00
+#define PM6350_V1P0_REV4 0x01
+
+/* PMK8350_REV_ID */
+#define PMK8350_V1P0_REV1 0x00
+#define PMK8350_V1P0_REV2 0x00
+#define PMK8350_V1P0_REV3 0x00
+#define PMK8350_V1P0_REV4 0x01
+
+/* PMR735B_REV_ID */
+#define PMR735B_V1P0_REV1 0x11
+#define PMR735B_V1P0_REV2 0x00
+#define PMR735B_V1P0_REV3 0x01
+#define PMR735B_V1P0_REV4 0x01
+
/* PMI8998 FAB_ID */
#define PMI8998_FAB_ID_SMIC 0x11
#define PMI8998_FAB_ID_GF 0x30
@@ -306,8 +339,8 @@
/* PM8937 */
#define PM8937_SUBTYPE 0x19
-/* PMI8937 */
-#define PMI8937_SUBTYPE 0x37
+/* PM2250 */
+#define PM2250_SUBTYPE 0x37
/* SMB1390 */
#define SMB1390_SUBTYPE 0x23
diff --git a/include/linux/quota.h b/include/linux/quota.h
index f32dd27..27aab84 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -263,7 +263,7 @@ enum {
};
struct dqstats {
- int stat[_DQST_DQSTAT_LAST];
+ unsigned long stat[_DQST_DQSTAT_LAST];
struct percpu_counter counter[_DQST_DQSTAT_LAST];
};
diff --git a/include/linux/rculist_nulls.h b/include/linux/rculist_nulls.h
index bc8206a..61974c4 100644
--- a/include/linux/rculist_nulls.h
+++ b/include/linux/rculist_nulls.h
@@ -101,6 +101,43 @@ static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n,
}
/**
+ * hlist_nulls_add_tail_rcu
+ * @n: the element to add to the hash list.
+ * @h: the list to add to.
+ *
+ * Description:
+ * Adds the specified element to the specified hlist_nulls,
+ * while permitting racing traversals.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_nulls_add_head_rcu()
+ * or hlist_nulls_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_nulls_for_each_entry_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs. Regardless of the type of CPU, the
+ * list-traversal primitive must be guarded by rcu_read_lock().
+ */
+static inline void hlist_nulls_add_tail_rcu(struct hlist_nulls_node *n,
+ struct hlist_nulls_head *h)
+{
+ struct hlist_nulls_node *i, *last = NULL;
+
+ /* Note: write side code, so rcu accessors are not needed. */
+ for (i = h->first; !is_a_nulls(i); i = i->next)
+ last = i;
+
+ if (last) {
+ n->next = last->next;
+ n->pprev = &last->next;
+ rcu_assign_pointer(hlist_next_rcu(last), n);
+ } else {
+ hlist_nulls_add_head_rcu(n, h);
+ }
+}
+
+/**
* hlist_nulls_for_each_entry_rcu - iterate over rcu list of given type
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_nulls_node to use as a loop cursor.
diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h
index 6d46f962..06978ce 100644
--- a/include/linux/regulator/ab8500.h
+++ b/include/linux/regulator/ab8500.h
@@ -38,7 +38,6 @@ enum ab8505_regulator_id {
AB8505_LDO_AUX6,
AB8505_LDO_INTCORE,
AB8505_LDO_ADC,
- AB8505_LDO_USB,
AB8505_LDO_AUDIO,
AB8505_LDO_ANAMIC1,
AB8505_LDO_ANAMIC2,
diff --git a/include/linux/sched/cpufreq.h b/include/linux/sched/cpufreq.h
index 5e85b9f..1e2aac5 100644
--- a/include/linux/sched/cpufreq.h
+++ b/include/linux/sched/cpufreq.h
@@ -17,6 +17,8 @@
#define SCHED_CPUFREQ_CONTINUE (1U << 8)
#ifdef CONFIG_CPU_FREQ
+struct cpufreq_policy;
+
struct update_util_data {
void (*func)(struct update_util_data *data, u64 time, unsigned int flags);
};
@@ -25,6 +27,7 @@ void cpufreq_add_update_util_hook(int cpu, struct update_util_data *data,
void (*func)(struct update_util_data *data, u64 time,
unsigned int flags));
void cpufreq_remove_update_util_hook(int cpu);
+bool cpufreq_this_cpu_can_update(struct cpufreq_policy *policy);
static inline unsigned long map_util_freq(unsigned long util,
unsigned long freq, unsigned long cap)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 80c3da1..25407c2 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1669,7 +1669,7 @@ static inline struct sk_buff *skb_peek_next(struct sk_buff *skb,
*/
static inline struct sk_buff *skb_peek_tail(const struct sk_buff_head *list_)
{
- struct sk_buff *skb = list_->prev;
+ struct sk_buff *skb = READ_ONCE(list_->prev);
if (skb == (struct sk_buff *)list_)
skb = NULL;
@@ -1737,7 +1737,9 @@ static inline void __skb_insert(struct sk_buff *newsk,
struct sk_buff *prev, struct sk_buff *next,
struct sk_buff_head *list)
{
- /* see skb_queue_empty_lockless() for the opposite READ_ONCE() */
+ /* See skb_queue_empty_lockless() and skb_peek_tail()
+ * for the opposite READ_ONCE()
+ */
WRITE_ONCE(newsk->next, next);
WRITE_ONCE(newsk->prev, prev);
WRITE_ONCE(next->prev, newsk);
diff --git a/include/net/cnss2.h b/include/net/cnss2.h
index ee6cbb7..78143ea 100644
--- a/include/net/cnss2.h
+++ b/include/net/cnss2.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */
#ifndef _NET_CNSS2_H
#define _NET_CNSS2_H
@@ -158,6 +158,8 @@ enum cnss_recovery_reason {
extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver);
extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver);
extern void cnss_device_crashed(struct device *dev);
+extern int cnss_pci_prevent_l1(struct device *dev);
+extern void cnss_pci_allow_l1(struct device *dev);
extern int cnss_pci_link_down(struct device *dev);
extern int cnss_pci_is_device_down(struct device *dev);
extern void cnss_schedule_recovery(struct device *dev,
diff --git a/include/net/dst.h b/include/net/dst.h
index ffc8ee0..35ae45f 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -93,7 +93,7 @@ struct dst_entry {
struct dst_metrics {
u32 metrics[RTAX_MAX];
refcount_t refcnt;
-};
+} __aligned(4); /* Low pointer bits contain DST_METRICS_FLAGS */
extern const struct dst_metrics dst_default_metrics;
u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
@@ -527,7 +527,16 @@ static inline void skb_dst_update_pmtu(struct sk_buff *skb, u32 mtu)
struct dst_entry *dst = skb_dst(skb);
if (dst && dst->ops->update_pmtu)
- dst->ops->update_pmtu(dst, NULL, skb, mtu);
+ dst->ops->update_pmtu(dst, NULL, skb, mtu, true);
+}
+
+/* update dst pmtu but not do neighbor confirm */
+static inline void skb_dst_update_pmtu_no_confirm(struct sk_buff *skb, u32 mtu)
+{
+ struct dst_entry *dst = skb_dst(skb);
+
+ if (dst && dst->ops->update_pmtu)
+ dst->ops->update_pmtu(dst, NULL, skb, mtu, false);
}
static inline void skb_tunnel_check_pmtu(struct sk_buff *skb,
@@ -537,7 +546,7 @@ static inline void skb_tunnel_check_pmtu(struct sk_buff *skb,
u32 encap_mtu = dst_mtu(encap_dst);
if (skb->len > encap_mtu - headroom)
- skb_dst_update_pmtu(skb, encap_mtu - headroom);
+ skb_dst_update_pmtu_no_confirm(skb, encap_mtu - headroom);
}
#endif /* _NET_DST_H */
diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h
index 5ec645f..443863c 100644
--- a/include/net/dst_ops.h
+++ b/include/net/dst_ops.h
@@ -27,7 +27,8 @@ struct dst_ops {
struct dst_entry * (*negative_advice)(struct dst_entry *);
void (*link_failure)(struct sk_buff *);
void (*update_pmtu)(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu);
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh);
void (*redirect)(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb);
int (*local_out)(struct net *net, struct sock *sk, struct sk_buff *skb);
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 9141e95..b875dce 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -106,13 +106,19 @@ struct inet_bind_hashbucket {
struct hlist_head chain;
};
-/*
- * Sockets can be hashed in established or listening table
+/* Sockets can be hashed in established or listening table.
+ * We must use different 'nulls' end-of-chain value for all hash buckets :
+ * A socket might transition from ESTABLISH to LISTEN state without
+ * RCU grace period. A lookup in ehash table needs to handle this case.
*/
+#define LISTENING_NULLS_BASE (1U << 29)
struct inet_listen_hashbucket {
spinlock_t lock;
unsigned int count;
- struct hlist_head head;
+ union {
+ struct hlist_head head;
+ struct hlist_nulls_head nulls_head;
+ };
};
/* This is for listening sockets, thus all sockets which possess wildcards. */
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index c84807c..5ce0359 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -459,7 +459,7 @@ static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb
do {
seq = read_seqbegin(&hh->hh_lock);
- hh_len = hh->hh_len;
+ hh_len = READ_ONCE(hh->hh_len);
if (likely(hh_len <= HH_DATA_MOD)) {
hh_alen = HH_DATA_MOD;
diff --git a/include/net/sock.h b/include/net/sock.h
index b5b126a..94ffacc 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -721,6 +721,11 @@ static inline void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_h
hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list);
}
+static inline void __sk_nulls_add_node_tail_rcu(struct sock *sk, struct hlist_nulls_head *list)
+{
+ hlist_nulls_add_tail_rcu(&sk->sk_nulls_node, list);
+}
+
static inline void sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list)
{
sock_hold(sk);
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index df156f1..f0a01a5 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -638,6 +638,7 @@ struct iscsi_reject {
#define ISCSI_REASON_BOOKMARK_INVALID 9
#define ISCSI_REASON_BOOKMARK_NO_RESOURCES 10
#define ISCSI_REASON_NEGOTIATION_RESET 11
+#define ISCSI_REASON_WAITING_FOR_LOGOUT 12
/* Max. number of Key=Value pairs in a text message */
#define MAX_KEY_VALUE_PAIRS 8192
diff --git a/include/trace/events/wbt.h b/include/trace/events/wbt.h
index b048694..37342a1 100644
--- a/include/trace/events/wbt.h
+++ b/include/trace/events/wbt.h
@@ -33,7 +33,8 @@ TRACE_EVENT(wbt_stat,
),
TP_fast_assign(
- strncpy(__entry->name, dev_name(bdi->dev), 32);
+ strlcpy(__entry->name, dev_name(bdi->dev),
+ ARRAY_SIZE(__entry->name));
__entry->rmean = stat[0].mean;
__entry->rmin = stat[0].min;
__entry->rmax = stat[0].max;
@@ -67,7 +68,8 @@ TRACE_EVENT(wbt_lat,
),
TP_fast_assign(
- strncpy(__entry->name, dev_name(bdi->dev), 32);
+ strlcpy(__entry->name, dev_name(bdi->dev),
+ ARRAY_SIZE(__entry->name));
__entry->lat = div_u64(lat, 1000);
),
@@ -103,7 +105,8 @@ TRACE_EVENT(wbt_step,
),
TP_fast_assign(
- strncpy(__entry->name, dev_name(bdi->dev), 32);
+ strlcpy(__entry->name, dev_name(bdi->dev),
+ ARRAY_SIZE(__entry->name));
__entry->msg = msg;
__entry->step = step;
__entry->window = div_u64(window, 1000);
@@ -138,7 +141,8 @@ TRACE_EVENT(wbt_timer,
),
TP_fast_assign(
- strncpy(__entry->name, dev_name(bdi->dev), 32);
+ strlcpy(__entry->name, dev_name(bdi->dev),
+ ARRAY_SIZE(__entry->name));
__entry->status = status;
__entry->step = step;
__entry->inflight = inflight;
diff --git a/include/uapi/drm/sde_drm.h b/include/uapi/drm/sde_drm.h
index 9101697..1247158 100644
--- a/include/uapi/drm/sde_drm.h
+++ b/include/uapi/drm/sde_drm.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 2020, The Linux Foundation. All rights reserved.
*/
#ifndef _SDE_DRM_H_
@@ -226,6 +226,7 @@ struct sde_drm_de_v1 {
#define SDE_DRM_QSEED3LITE
#define SDE_DRM_QSEED4
+#define SDE_DRM_INLINE_PREDOWNSCALE
/**
* struct sde_drm_scaler_v2 - version 2 of struct sde_drm_scaler
@@ -259,6 +260,10 @@ struct sde_drm_de_v1 {
* @unsharp_mask_blend: Unsharp Blend Filter Ratio
* @de_blend: Ratio of two unsharp mask filters
* @flags: Scaler configuration flags
+ * @pre_downscale_x_0 Pre-downscale ratio, x-direction, plane 0(Y/RGB)
+ * @pre_downscale_x_1 Pre-downscale ratio, x-direction, plane 1(UV)
+ * @pre_downscale_y_0 Pre-downscale ratio, y-direction, plane 0(Y/RGB)
+ * @pre_downscale_y_1 Pre-downscale ratio, y-direction, plane 1(UV)
*/
struct sde_drm_scaler_v2 {
/*
@@ -316,6 +321,14 @@ struct sde_drm_scaler_v2 {
uint32_t unsharp_mask_blend;
uint32_t de_blend;
uint32_t flags;
+
+ /*
+ * Inline pre-downscale settings
+ */
+ uint32_t pre_downscale_x_0;
+ uint32_t pre_downscale_x_1;
+ uint32_t pre_downscale_y_0;
+ uint32_t pre_downscale_y_1;
};
/* Number of dest scalers supported */
diff --git a/include/uapi/linux/cec-funcs.h b/include/uapi/linux/cec-funcs.h
index 8997d50..4511b85 100644
--- a/include/uapi/linux/cec-funcs.h
+++ b/include/uapi/linux/cec-funcs.h
@@ -923,7 +923,8 @@ static inline void cec_msg_give_deck_status(struct cec_msg *msg,
msg->len = 3;
msg->msg[1] = CEC_MSG_GIVE_DECK_STATUS;
msg->msg[2] = status_req;
- msg->reply = reply ? CEC_MSG_DECK_STATUS : 0;
+ msg->reply = (reply && status_req != CEC_OP_STATUS_REQ_OFF) ?
+ CEC_MSG_DECK_STATUS : 0;
}
static inline void cec_ops_give_deck_status(const struct cec_msg *msg,
@@ -1027,7 +1028,8 @@ static inline void cec_msg_give_tuner_device_status(struct cec_msg *msg,
msg->len = 3;
msg->msg[1] = CEC_MSG_GIVE_TUNER_DEVICE_STATUS;
msg->msg[2] = status_req;
- msg->reply = reply ? CEC_MSG_TUNER_DEVICE_STATUS : 0;
+ msg->reply = (reply && status_req != CEC_OP_STATUS_REQ_OFF) ?
+ CEC_MSG_TUNER_DEVICE_STATUS : 0;
}
static inline void cec_ops_give_tuner_device_status(const struct cec_msg *msg,
diff --git a/include/uapi/linux/netfilter/xt_sctp.h b/include/uapi/linux/netfilter/xt_sctp.h
index 4bc6d1a..b4d804a 100644
--- a/include/uapi/linux/netfilter/xt_sctp.h
+++ b/include/uapi/linux/netfilter/xt_sctp.h
@@ -41,19 +41,19 @@ struct xt_sctp_info {
#define SCTP_CHUNKMAP_SET(chunkmap, type) \
do { \
(chunkmap)[type / bytes(__u32)] |= \
- 1 << (type % bytes(__u32)); \
+ 1u << (type % bytes(__u32)); \
} while (0)
#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
do { \
(chunkmap)[type / bytes(__u32)] &= \
- ~(1 << (type % bytes(__u32))); \
+ ~(1u << (type % bytes(__u32))); \
} while (0)
#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
({ \
((chunkmap)[type / bytes (__u32)] & \
- (1 << (type % bytes (__u32)))) ? 1: 0; \
+ (1u << (type % bytes (__u32)))) ? 1: 0; \
})
#define SCTP_CHUNKMAP_RESET(chunkmap) \
diff --git a/include/uapi/linux/spss_utils.h b/include/uapi/linux/spss_utils.h
index a5ff6ed..6a34d19 100644
--- a/include/uapi/linux/spss_utils.h
+++ b/include/uapi/linux/spss_utils.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
- * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _UAPI_SPSS_UTILS_H_
@@ -17,14 +17,65 @@
*/
#define SPSS_IOC_MAGIC 'S'
-#define NUM_SPU_UEFI_APPS 3
+
+/* ---------- set fw cmac --------------------------------- */
+#define NUM_SPU_UEFI_APPS 3
+#define CMAC_SIZE_IN_WORDS 4
struct spss_ioc_set_fw_cmac {
- uint32_t cmac[4];
- uint32_t app_cmacs[NUM_SPU_UEFI_APPS][4];
+ uint32_t cmac[CMAC_SIZE_IN_WORDS];
+ uint32_t app_cmacs[NUM_SPU_UEFI_APPS][CMAC_SIZE_IN_WORDS];
} __packed;
#define SPSS_IOC_SET_FW_CMAC \
_IOWR(SPSS_IOC_MAGIC, 1, struct spss_ioc_set_fw_cmac)
+/* ---------- wait for event ------------------------------ */
+enum _spss_event_id {
+ /* signaled from user */
+ SPSS_EVENT_ID_PIL_CALLED = 0,
+ SPSS_EVENT_ID_NVM_READY = 1,
+ SPSS_EVENT_ID_SPU_READY = 2,
+ SPSS_NUM_USER_EVENTS,
+
+ /* signaled from kernel */
+ SPSS_EVENT_ID_SPU_POWER_DOWN = 6,
+ SPSS_EVENT_ID_SPU_POWER_UP = 7,
+ SPSS_NUM_EVENTS,
+} spss_event_id;
+
+enum _spss_event_status {
+ EVENT_STATUS_SIGNALED = 0xAAAA,
+ EVENT_STATUS_NOT_SIGNALED = 0xFFFF,
+ EVENT_STATUS_TIMEOUT = 0xEEE1,
+ EVENT_STATUS_ABORTED = 0xEEE2,
+} spss_event_status;
+
+struct spss_ioc_wait_for_event {
+ uint32_t event_id; /* input */
+ uint32_t timeout_sec; /* input */
+ uint32_t status; /* output */
+} __packed;
+
+#define SPSS_IOC_WAIT_FOR_EVENT \
+ _IOWR(SPSS_IOC_MAGIC, 2, struct spss_ioc_wait_for_event)
+
+/* ---------- signal event ------------------------------ */
+struct spss_ioc_signal_event {
+ uint32_t event_id; /* input */
+ uint32_t status; /* output */
+} __packed;
+
+#define SPSS_IOC_SIGNAL_EVENT \
+ _IOWR(SPSS_IOC_MAGIC, 3, struct spss_ioc_signal_event)
+
+/* ---------- is event isgnaled ------------------------------ */
+struct spss_ioc_is_signaled {
+ uint32_t event_id; /* input */
+ uint32_t status; /* output */
+} __attribute__((packed));
+
+#define SPSS_IOC_IS_EVENT_SIGNALED \
+ _IOWR(SPSS_IOC_MAGIC, 4, struct spss_ioc_is_signaled)
+
#endif /* _UAPI_SPSS_UTILS_H_ */
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 7cb7a7f..55fff5e 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -292,7 +292,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
bool irq_work_busy = false;
struct stack_map_irq_work *work = NULL;
- if (in_nmi()) {
+ if (irqs_disabled()) {
work = this_cpu_ptr(&up_read_work);
if (work->irq_work.flags & IRQ_WORK_BUSY)
/* cannot queue more up_read, fallback */
@@ -300,8 +300,9 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
}
/*
- * We cannot do up_read() in nmi context. To do build_id lookup
- * in nmi context, we need to run up_read() in irq_work. We use
+ * We cannot do up_read() when the irq is disabled, because of
+ * risk to deadlock with rq_lock. To do build_id lookup when the
+ * irqs are disabled, we need to run up_read() in irq_work. We use
* a percpu variable to do the irq_work. If the irq_work is
* already used by another lookup, we fall back to report ips.
*
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 1dff5f7..9e72b2f 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -4272,6 +4272,7 @@ static bool may_access_skb(enum bpf_prog_type type)
static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
{
struct bpf_reg_state *regs = cur_regs(env);
+ static const int ctx_reg = BPF_REG_6;
u8 mode = BPF_MODE(insn->code);
int i, err;
@@ -4305,11 +4306,11 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
}
/* check whether implicit source operand (register R6) is readable */
- err = check_reg_arg(env, BPF_REG_6, SRC_OP);
+ err = check_reg_arg(env, ctx_reg, SRC_OP);
if (err)
return err;
- if (regs[BPF_REG_6].type != PTR_TO_CTX) {
+ if (regs[ctx_reg].type != PTR_TO_CTX) {
verbose(env,
"at the time of BPF_LD_ABS|IND R6 != pointer to skb\n");
return -EINVAL;
@@ -4322,6 +4323,10 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
return err;
}
+ err = check_ctx_reg(env, ®s[ctx_reg], ctx_reg);
+ if (err < 0)
+ return err;
+
/* reset caller saved regs to unreadable */
for (i = 0; i < CALLER_SAVED_REGS; i++) {
mark_reg_not_init(env, regs, caller_saved[i]);
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index d4d666a..5bc24eb 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -837,8 +837,8 @@ static void rebuild_sched_domains_locked(void)
cpumask_var_t *doms;
int ndoms;
+ lockdep_assert_cpus_held();
lockdep_assert_held(&cpuset_mutex);
- get_online_cpus();
/*
* We have raced with CPU hotplug. Don't do anything to avoid
@@ -846,15 +846,13 @@ static void rebuild_sched_domains_locked(void)
* Anyways, hotplug work item will rebuild sched domains.
*/
if (!cpumask_equal(top_cpuset.effective_cpus, cpu_active_mask))
- goto out;
+ return;
/* Generate domain masks and attrs */
ndoms = generate_sched_domains(&doms, &attr);
/* Have scheduler rebuild the domains */
partition_sched_domains(ndoms, doms, attr);
-out:
- put_online_cpus();
}
#else /* !CONFIG_SMP */
static void rebuild_sched_domains_locked(void)
@@ -864,9 +862,11 @@ static void rebuild_sched_domains_locked(void)
void rebuild_sched_domains(void)
{
+ get_online_cpus();
mutex_lock(&cpuset_mutex);
rebuild_sched_domains_locked();
mutex_unlock(&cpuset_mutex);
+ put_online_cpus();
}
static int update_cpus_allowed(struct cpuset *cs, struct task_struct *p,
@@ -1634,6 +1634,7 @@ static int cpuset_write_u64(struct cgroup_subsys_state *css, struct cftype *cft,
cpuset_filetype_t type = cft->private;
int retval = 0;
+ get_online_cpus();
mutex_lock(&cpuset_mutex);
if (!is_cpuset_online(cs)) {
retval = -ENODEV;
@@ -1671,6 +1672,7 @@ static int cpuset_write_u64(struct cgroup_subsys_state *css, struct cftype *cft,
}
out_unlock:
mutex_unlock(&cpuset_mutex);
+ put_online_cpus();
return retval;
}
@@ -1681,6 +1683,7 @@ static int cpuset_write_s64(struct cgroup_subsys_state *css, struct cftype *cft,
cpuset_filetype_t type = cft->private;
int retval = -ENODEV;
+ get_online_cpus();
mutex_lock(&cpuset_mutex);
if (!is_cpuset_online(cs))
goto out_unlock;
@@ -1695,6 +1698,7 @@ static int cpuset_write_s64(struct cgroup_subsys_state *css, struct cftype *cft,
}
out_unlock:
mutex_unlock(&cpuset_mutex);
+ put_online_cpus();
return retval;
}
@@ -1733,6 +1737,7 @@ static ssize_t cpuset_write_resmask(struct kernfs_open_file *of,
kernfs_break_active_protection(of->kn);
flush_work(&cpuset_hotplug_work);
+ get_online_cpus();
mutex_lock(&cpuset_mutex);
if (!is_cpuset_online(cs))
goto out_unlock;
@@ -1758,6 +1763,7 @@ static ssize_t cpuset_write_resmask(struct kernfs_open_file *of,
free_trial_cpuset(trialcs);
out_unlock:
mutex_unlock(&cpuset_mutex);
+ put_online_cpus();
kernfs_unbreak_active_protection(of->kn);
css_put(&cs->css);
flush_workqueue(cpuset_migrate_mm_wq);
@@ -2007,6 +2013,7 @@ static int cpuset_css_online(struct cgroup_subsys_state *css)
if (!parent)
return 0;
+ get_online_cpus();
mutex_lock(&cpuset_mutex);
set_bit(CS_ONLINE, &cs->flags);
@@ -2058,6 +2065,7 @@ static int cpuset_css_online(struct cgroup_subsys_state *css)
spin_unlock_irq(&callback_lock);
out_unlock:
mutex_unlock(&cpuset_mutex);
+ put_online_cpus();
return 0;
}
@@ -2071,6 +2079,7 @@ static void cpuset_css_offline(struct cgroup_subsys_state *css)
{
struct cpuset *cs = css_cs(css);
+ get_online_cpus();
mutex_lock(&cpuset_mutex);
if (is_sched_load_balance(cs))
@@ -2080,6 +2089,7 @@ static void cpuset_css_offline(struct cgroup_subsys_state *css)
clear_bit(CS_ONLINE, &cs->flags);
mutex_unlock(&cpuset_mutex);
+ put_online_cpus();
}
static void cpuset_css_free(struct cgroup_subsys_state *css)
diff --git a/kernel/cred.c b/kernel/cred.c
index 5ab1f7e..a9f0f8b 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -220,7 +220,7 @@ struct cred *cred_alloc_blank(void)
new->magic = CRED_MAGIC;
#endif
- if (security_cred_alloc_blank(new, GFP_KERNEL) < 0)
+ if (security_cred_alloc_blank(new, GFP_KERNEL_ACCOUNT) < 0)
goto error;
return new;
@@ -279,7 +279,7 @@ struct cred *prepare_creds(void)
new->security = NULL;
#endif
- if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
+ if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)
goto error;
validate_creds(new);
return new;
@@ -654,7 +654,7 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
#ifdef CONFIG_SECURITY
new->security = NULL;
#endif
- if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
+ if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)
goto error;
put_cred(old);
diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c
index c007d25..3a23974 100644
--- a/kernel/dma/debug.c
+++ b/kernel/dma/debug.c
@@ -442,6 +442,7 @@ void debug_dma_dump_mappings(struct device *dev)
}
spin_unlock_irqrestore(&bucket->lock, flags);
+ cond_resched();
}
}
diff --git a/kernel/exit.c b/kernel/exit.c
index aae5cc5..d8eb9c7 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -578,10 +578,6 @@ static struct task_struct *find_child_reaper(struct task_struct *father,
}
write_unlock_irq(&tasklist_lock);
- if (unlikely(pid_ns == &init_pid_ns)) {
- panic("Attempted to kill init! exitcode=0x%08x\n",
- father->signal->group_exit_code ?: father->exit_code);
- }
list_for_each_entry_safe(p, n, dead, ptrace_entry) {
list_del_init(&p->ptrace_entry);
@@ -846,6 +842,14 @@ void __noreturn do_exit(long code)
acct_update_integrals(tsk);
group_dead = atomic_dec_and_test(&tsk->signal->live);
if (group_dead) {
+ /*
+ * If the last thread of global init has exited, panic
+ * immediately to get a useable coredump.
+ */
+ if (unlikely(is_global_init(tsk)))
+ panic("Attempted to kill init! exitcode=0x%08x\n",
+ tsk->signal->group_exit_code ?: (int)code);
+
#ifdef CONFIG_POSIX_TIMERS
hrtimer_cancel(&tsk->signal->real_timer);
exit_itimers(tsk->signal);
diff --git a/kernel/locking/spinlock_debug.c b/kernel/locking/spinlock_debug.c
index c18dadd..8ab57cc 100644
--- a/kernel/locking/spinlock_debug.c
+++ b/kernel/locking/spinlock_debug.c
@@ -53,19 +53,19 @@ EXPORT_SYMBOL(__rwlock_init);
static void spin_dump(raw_spinlock_t *lock, const char *msg)
{
- struct task_struct *owner = NULL;
+ struct task_struct *owner = READ_ONCE(lock->owner);
- if (lock->owner && lock->owner != SPINLOCK_OWNER_INIT)
- owner = lock->owner;
+ if (owner == SPINLOCK_OWNER_INIT)
+ owner = NULL;
printk(KERN_EMERG "BUG: spinlock %s on CPU#%d, %s/%d\n",
msg, raw_smp_processor_id(),
current->comm, task_pid_nr(current));
printk(KERN_EMERG " lock: %pS, .magic: %08x, .owner: %s/%d, "
".owner_cpu: %d\n",
- lock, lock->magic,
+ lock, READ_ONCE(lock->magic),
owner ? owner->comm : "<none>",
owner ? task_pid_nr(owner) : -1,
- lock->owner_cpu);
+ READ_ONCE(lock->owner_cpu));
#ifdef CONFIG_DEBUG_SPINLOCK_BITE_ON_BUG
msm_trigger_wdog_bite();
#elif defined(CONFIG_DEBUG_SPINLOCK_PANIC_ON_BUG)
@@ -87,16 +87,16 @@ static void spin_bug(raw_spinlock_t *lock, const char *msg)
static inline void
debug_spin_lock_before(raw_spinlock_t *lock)
{
- SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic");
- SPIN_BUG_ON(lock->owner == current, lock, "recursion");
- SPIN_BUG_ON(lock->owner_cpu == raw_smp_processor_id(),
+ SPIN_BUG_ON(READ_ONCE(lock->magic) != SPINLOCK_MAGIC, lock, "bad magic");
+ SPIN_BUG_ON(READ_ONCE(lock->owner) == current, lock, "recursion");
+ SPIN_BUG_ON(READ_ONCE(lock->owner_cpu) == raw_smp_processor_id(),
lock, "cpu recursion");
}
static inline void debug_spin_lock_after(raw_spinlock_t *lock)
{
- lock->owner_cpu = raw_smp_processor_id();
- lock->owner = current;
+ WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id());
+ WRITE_ONCE(lock->owner, current);
}
static inline void debug_spin_unlock(raw_spinlock_t *lock)
@@ -106,8 +106,8 @@ static inline void debug_spin_unlock(raw_spinlock_t *lock)
SPIN_BUG_ON(lock->owner != current, lock, "wrong owner");
SPIN_BUG_ON(lock->owner_cpu != raw_smp_processor_id(),
lock, "wrong CPU");
- lock->owner = SPINLOCK_OWNER_INIT;
- lock->owner_cpu = -1;
+ WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT);
+ WRITE_ONCE(lock->owner_cpu, -1);
}
/*
@@ -195,8 +195,8 @@ static inline void debug_write_lock_before(rwlock_t *lock)
static inline void debug_write_lock_after(rwlock_t *lock)
{
- lock->owner_cpu = raw_smp_processor_id();
- lock->owner = current;
+ WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id());
+ WRITE_ONCE(lock->owner, current);
}
static inline void debug_write_unlock(rwlock_t *lock)
@@ -205,8 +205,8 @@ static inline void debug_write_unlock(rwlock_t *lock)
RWLOCK_BUG_ON(lock->owner != current, lock, "wrong owner");
RWLOCK_BUG_ON(lock->owner_cpu != raw_smp_processor_id(),
lock, "wrong CPU");
- lock->owner = SPINLOCK_OWNER_INIT;
- lock->owner_cpu = -1;
+ WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT);
+ WRITE_ONCE(lock->owner_cpu, -1);
}
void do_raw_write_lock(rwlock_t *lock)
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 3d37c27..f2635fc 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -736,8 +736,15 @@ static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
* We have found the zone. Now walk the radix tree to find the leaf node
* for our PFN.
*/
+
+ /*
+ * If the zone we wish to scan is the the current zone and the
+ * pfn falls into the current node then we do not need to walk
+ * the tree.
+ */
node = bm->cur.node;
- if (((pfn - zone->start_pfn) & ~BM_BLOCK_MASK) == bm->cur.node_pfn)
+ if (zone == bm->cur.zone &&
+ ((pfn - zone->start_pfn) & ~BM_BLOCK_MASK) == bm->cur.node_pfn)
goto node_found;
node = zone->rtree;
diff --git a/kernel/sched/cpufreq.c b/kernel/sched/cpufreq.c
index 5e54cbc..42ce32a 100644
--- a/kernel/sched/cpufreq.c
+++ b/kernel/sched/cpufreq.c
@@ -8,6 +8,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/cpufreq.h>
+
#include "sched.h"
DEFINE_PER_CPU(struct update_util_data *, cpufreq_update_util_data);
@@ -60,3 +62,19 @@ void cpufreq_remove_update_util_hook(int cpu)
rcu_assign_pointer(per_cpu(cpufreq_update_util_data, cpu), NULL);
}
EXPORT_SYMBOL_GPL(cpufreq_remove_update_util_hook);
+
+/**
+ * cpufreq_this_cpu_can_update - Check if cpufreq policy can be updated.
+ * @policy: cpufreq policy to check.
+ *
+ * Return 'true' if:
+ * - the local and remote CPUs share @policy,
+ * - dvfs_possible_from_any_cpu is set in @policy and the local CPU is not going
+ * offline (in which case it is not expected to run cpufreq updates any more).
+ */
+bool cpufreq_this_cpu_can_update(struct cpufreq_policy *policy)
+{
+ return cpumask_test_cpu(smp_processor_id(), policy->cpus) ||
+ (policy->dvfs_possible_from_any_cpu &&
+ rcu_dereference_sched(*this_cpu_ptr(&cpufreq_update_util_data)));
+}
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index e9da7954..6d84301 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -106,12 +106,10 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time)
* by the hardware, as calculating the frequency is pointless if
* we cannot in fact act on it.
*
- * For the slow switching platforms, the kthread is always scheduled on
- * the right set of CPUs and any CPU can find the next frequency and
- * schedule the kthread.
+ * This is needed on the slow switching platforms too to prevent CPUs
+ * going offline from leaving stale IRQ work items behind.
*/
- if (sg_policy->policy->fast_switch_enabled &&
- !cpufreq_this_cpu_can_update(sg_policy->policy))
+ if (!cpufreq_this_cpu_can_update(sg_policy->policy))
return false;
if (unlikely(sg_policy->limits_changed)) {
@@ -267,7 +265,7 @@ static void sugov_deferred_update(struct sugov_policy *sg_policy, u64 time,
if (use_pelt())
sg_policy->work_in_progress = true;
- sched_irq_work_queue(&sg_policy->irq_work);
+ irq_work_queue(&sg_policy->irq_work);
}
#define TARGET_LOAD 80
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 46f24f9..979ed34 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -92,7 +92,6 @@ extern unsigned int sched_capacity_margin_up[NR_CPUS];
extern unsigned int sched_capacity_margin_down[NR_CPUS];
struct sched_walt_cpu_load {
- unsigned long prev_window_util;
unsigned long nl;
unsigned long pl;
bool rtgb_active;
@@ -618,11 +617,10 @@ struct cfs_rq {
struct list_head leaf_cfs_rq_list;
struct task_group *tg; /* group that "owns" this runqueue */
+#ifdef CONFIG_CFS_BANDWIDTH
#ifdef CONFIG_SCHED_WALT
struct walt_sched_stats walt_stats;
#endif
-
-#ifdef CONFIG_CFS_BANDWIDTH
int runtime_enabled;
s64 runtime_remaining;
@@ -2044,7 +2042,7 @@ cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load);
#define sched_ravg_window TICK_NSEC
static inline u64 sched_ktime_clock(void)
{
- return 0;
+ return sched_clock();
}
#endif
@@ -2506,16 +2504,20 @@ DECLARE_PER_CPU(struct update_util_data *, cpufreq_update_util_data);
static inline void cpufreq_update_util(struct rq *rq, unsigned int flags)
{
struct update_util_data *data;
+ u64 clock;
#ifdef CONFIG_SCHED_WALT
if (!(flags & SCHED_CPUFREQ_WALT))
return;
+ clock = sched_ktime_clock();
+#else
+ clock = rq_clock(rq);
#endif
data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data,
cpu_of(rq)));
if (data)
- data->func(data, sched_ktime_clock(), flags);
+ data->func(data, clock, flags);
}
#else
static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {}
@@ -3087,13 +3089,3 @@ struct sched_avg_stats {
int nr_scaled;
};
extern void sched_get_nr_running_avg(struct sched_avg_stats *stats);
-
-#ifdef CONFIG_SMP
-static inline void sched_irq_work_queue(struct irq_work *work)
-{
- if (likely(cpu_online(raw_smp_processor_id())))
- irq_work_queue(work);
- else
- irq_work_queue_on(work, cpumask_any(cpu_online_mask));
-}
-#endif
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index 07bbd77..85a9f2a 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -202,6 +202,14 @@ early_param("sched_predl", set_sched_predl);
__read_mostly unsigned int walt_scale_demand_divisor;
#define scale_demand(d) ((d)/walt_scale_demand_divisor)
+static inline void walt_irq_work_queue(struct irq_work *work)
+{
+ if (likely(cpu_online(raw_smp_processor_id())))
+ irq_work_queue(work);
+ else
+ irq_work_queue_on(work, cpumask_any(cpu_online_mask));
+}
+
void inc_rq_walt_stats(struct rq *rq, struct task_struct *p)
{
inc_nr_big_task(&rq->walt_stats, p);
@@ -567,7 +575,6 @@ __cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load)
nl = div64_u64(nl * (100 + boost), walt_cpu_util_freq_divisor);
- walt_load->prev_window_util = util;
walt_load->nl = nl;
walt_load->pl = pl;
walt_load->ws = walt_load_reported_window;
@@ -602,7 +609,6 @@ cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load)
mpct = 100;
util = ADJUSTED_ASYM_CAP_CPU_UTIL(util, util_other, mpct);
- walt_load->prev_window_util = util;
walt_load->nl = ADJUSTED_ASYM_CAP_CPU_UTIL(walt_load->nl, wl_other.nl,
mpct);
@@ -971,7 +977,7 @@ void fixup_busy_time(struct task_struct *p, int new_cpu)
if (!same_freq_domain(new_cpu, task_cpu(p))) {
src_rq->notif_pending = true;
dest_rq->notif_pending = true;
- sched_irq_work_queue(&walt_migration_irq_work);
+ walt_irq_work_queue(&walt_migration_irq_work);
}
if (is_ed_enabled()) {
@@ -2061,7 +2067,7 @@ static inline void run_walt_irq_work(u64 old_window_start, struct rq *rq)
result = atomic64_cmpxchg(&walt_irq_work_lastq_ws, old_window_start,
rq->window_start);
if (result == old_window_start)
- sched_irq_work_queue(&walt_cpufreq_irq_work);
+ walt_irq_work_queue(&walt_cpufreq_irq_work);
}
/* Reflect task activity on its demand and cpu's busy time statistics */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index e39d60e..410e3c1 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1715,7 +1715,7 @@ static struct ctl_table vm_table[] = {
.procname = "drop_caches",
.data = &sysctl_drop_caches,
.maxlen = sizeof(int),
- .mode = 0644,
+ .mode = 0200,
.proc_handler = drop_caches_sysctl_handler,
.extra1 = &one,
.extra2 = &four,
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 2dac07a..cd709fe 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -887,25 +887,33 @@ static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk)
{
struct signal_struct *sig = tsk->signal;
- struct taskstats *stats;
+ struct taskstats *stats_new, *stats;
- if (sig->stats || thread_group_empty(tsk))
- goto ret;
+ /* Pairs with smp_store_release() below. */
+ stats = smp_load_acquire(&sig->stats);
+ if (stats || thread_group_empty(tsk))
+ return stats;
/* No problem if kmem_cache_zalloc() fails */
- stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
+ stats_new = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
spin_lock_irq(&tsk->sighand->siglock);
- if (!sig->stats) {
- sig->stats = stats;
- stats = NULL;
+ stats = sig->stats;
+ if (!stats) {
+ /*
+ * Pairs with smp_store_release() above and order the
+ * kmem_cache_zalloc().
+ */
+ smp_store_release(&sig->stats, stats_new);
+ stats = stats_new;
+ stats_new = NULL;
}
spin_unlock_irq(&tsk->sighand->siglock);
- if (stats)
- kmem_cache_free(taskstats_cache, stats);
-ret:
- return sig->stats;
+ if (stats_new)
+ kmem_cache_free(taskstats_cache, stats_new);
+
+ return stats;
}
/* Send pid data out on exit */
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 4d506f6..3b8e78b 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -963,7 +963,8 @@ static int enqueue_hrtimer(struct hrtimer *timer,
base->cpu_base->active_bases |= 1 << base->index;
- timer->state |= HRTIMER_STATE_ENQUEUED;
+ /* Pairs with the lockless read in hrtimer_is_queued() */
+ WRITE_ONCE(timer->state, timer->state | HRTIMER_STATE_ENQUEUED);
return timerqueue_add(&base->active, &timer->node);
}
@@ -1006,7 +1007,7 @@ static void __remove_hrtimer(struct hrtimer *timer,
* We need to preserve PINNED state here, otherwise we may end up
* migrating pinned hrtimers as well.
*/
- timer->state = newstate | (timer->state & HRTIMER_STATE_PINNED);
+ WRITE_ONCE(timer->state, newstate | (timer->state & HRTIMER_STATE_PINNED));
}
/*
@@ -1015,8 +1016,9 @@ static void __remove_hrtimer(struct hrtimer *timer,
static inline int
remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool restart)
{
- if (hrtimer_is_queued(timer)) {
- u8 state = timer->state;
+ u8 state = timer->state;
+
+ if (state & HRTIMER_STATE_ENQUEUED) {
int reprogram;
/*
diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c
index fe56c4e..c8a8501 100644
--- a/kernel/time/posix-clock.c
+++ b/kernel/time/posix-clock.c
@@ -27,8 +27,6 @@
#include "posix-timers.h"
-static void delete_clock(struct kref *kref);
-
/*
* Returns NULL if the posix_clock instance attached to 'fp' is old and stale.
*/
@@ -138,7 +136,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp)
err = 0;
if (!err) {
- kref_get(&clk->kref);
+ get_device(clk->dev);
fp->private_data = clk;
}
out:
@@ -154,7 +152,7 @@ static int posix_clock_release(struct inode *inode, struct file *fp)
if (clk->ops.release)
err = clk->ops.release(clk);
- kref_put(&clk->kref, delete_clock);
+ put_device(clk->dev);
fp->private_data = NULL;
@@ -174,38 +172,35 @@ static const struct file_operations posix_clock_file_operations = {
#endif
};
-int posix_clock_register(struct posix_clock *clk, dev_t devid)
+int posix_clock_register(struct posix_clock *clk, struct device *dev)
{
int err;
- kref_init(&clk->kref);
init_rwsem(&clk->rwsem);
cdev_init(&clk->cdev, &posix_clock_file_operations);
+ err = cdev_device_add(&clk->cdev, dev);
+ if (err) {
+ pr_err("%s unable to add device %d:%d\n",
+ dev_name(dev), MAJOR(dev->devt), MINOR(dev->devt));
+ return err;
+ }
clk->cdev.owner = clk->ops.owner;
- err = cdev_add(&clk->cdev, devid, 1);
+ clk->dev = dev;
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(posix_clock_register);
-static void delete_clock(struct kref *kref)
-{
- struct posix_clock *clk = container_of(kref, struct posix_clock, kref);
-
- if (clk->release)
- clk->release(clk);
-}
-
void posix_clock_unregister(struct posix_clock *clk)
{
- cdev_del(&clk->cdev);
+ cdev_device_del(&clk->cdev, clk->dev);
down_write(&clk->rwsem);
clk->zombie = true;
up_write(&clk->rwsem);
- kref_put(&clk->kref, delete_clock);
+ put_device(clk->dev);
}
EXPORT_SYMBOL_GPL(posix_clock_unregister);
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index b3ce6a9..0000166 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -555,8 +555,7 @@ static int function_stat_show(struct seq_file *m, void *v)
}
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
- avg = rec->time;
- do_div(avg, rec->counter);
+ avg = div64_ul(rec->time, rec->counter);
if (tracing_thresh && (avg < tracing_thresh))
goto out;
#endif
@@ -582,7 +581,8 @@ static int function_stat_show(struct seq_file *m, void *v)
* Divide only 1000 for ns^2 -> us^2 conversion.
* trace_print_graph_duration will divide 1000 again.
*/
- do_div(stddev, rec->counter * (rec->counter - 1) * 1000);
+ stddev = div64_ul(stddev,
+ rec->counter * (rec->counter - 1) * 1000);
}
trace_seq_init(&s);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 1ccd235..6bd66b6 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4399,7 +4399,7 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
if (mask == TRACE_ITER_RECORD_TGID) {
if (!tgid_map)
- tgid_map = kcalloc(PID_MAX_DEFAULT + 1,
+ tgid_map = kvcalloc(PID_MAX_DEFAULT + 1,
sizeof(*tgid_map),
GFP_KERNEL);
if (!tgid_map) {
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 2fb7846..b949c39 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -1642,7 +1642,7 @@ static int process_system_preds(struct trace_subsystem_dir *dir,
parse_error(pe, FILT_ERR_BAD_SUBSYS_FILTER, 0);
return -EINVAL;
fail_mem:
- kfree(filter);
+ __free_filter(filter);
/* If any call succeeded, we still need to sync */
if (!fail)
tracepoint_synchronize_unregister();
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index f2c26a0..45c9ed1 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -665,7 +665,26 @@ static notrace void trace_event_raw_event_synth(void *__data,
strscpy(str_field, str_val, STR_VAR_LEN_MAX);
n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
} else {
- entry->fields[n_u64] = var_ref_vals[var_ref_idx + i];
+ struct synth_field *field = event->fields[i];
+ u64 val = var_ref_vals[var_ref_idx + i];
+
+ switch (field->size) {
+ case 1:
+ *(u8 *)&entry->fields[n_u64] = (u8)val;
+ break;
+
+ case 2:
+ *(u16 *)&entry->fields[n_u64] = (u16)val;
+ break;
+
+ case 4:
+ *(u32 *)&entry->fields[n_u64] = (u32)val;
+ break;
+
+ default:
+ entry->fields[n_u64] = val;
+ break;
+ }
n_u64++;
}
}
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index f9a0cd0..c61b2b0 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -519,11 +519,10 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
#if defined(CONFIG_KPROBES_ON_FTRACE) && \
!defined(CONFIG_KPROBE_EVENTS_ON_NOTRACE)
-static bool within_notrace_func(struct trace_kprobe *tk)
+static bool __within_notrace_func(unsigned long addr)
{
- unsigned long offset, size, addr;
+ unsigned long offset, size;
- addr = trace_kprobe_address(tk);
if (!addr || !kallsyms_lookup_size_offset(addr, &size, &offset))
return false;
@@ -536,6 +535,28 @@ static bool within_notrace_func(struct trace_kprobe *tk)
*/
return !ftrace_location_range(addr, addr + size - 1);
}
+
+static bool within_notrace_func(struct trace_kprobe *tk)
+{
+ unsigned long addr = addr = trace_kprobe_address(tk);
+ char symname[KSYM_NAME_LEN], *p;
+
+ if (!__within_notrace_func(addr))
+ return false;
+
+ /* Check if the address is on a suffixed-symbol */
+ if (!lookup_symbol_name(addr, symname)) {
+ p = strchr(symname, '.');
+ if (!p)
+ return true;
+ *p = '\0';
+ addr = (unsigned long)kprobe_lookup_name(symname, 0);
+ if (addr)
+ return __within_notrace_func(addr);
+ }
+
+ return true;
+}
#else
#define within_notrace_func(tk) (false)
#endif
diff --git a/kernel/trace/tracing_map.c b/kernel/trace/tracing_map.c
index 9a1c223..9e31bfc 100644
--- a/kernel/trace/tracing_map.c
+++ b/kernel/trace/tracing_map.c
@@ -148,8 +148,8 @@ static int tracing_map_cmp_atomic64(void *val_a, void *val_b)
#define DEFINE_TRACING_MAP_CMP_FN(type) \
static int tracing_map_cmp_##type(void *val_a, void *val_b) \
{ \
- type a = *(type *)val_a; \
- type b = *(type *)val_b; \
+ type a = (type)(*(u64 *)val_a); \
+ type b = (type)(*(u64 *)val_b); \
\
return (a > b) ? 1 : ((a < b) ? -1 : 0); \
}
diff --git a/mm/migrate.c b/mm/migrate.c
index 0019713..fddfaf0 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1512,9 +1512,11 @@ static int do_move_pages_to_node(struct mm_struct *mm,
/*
* Resolves the given address to a struct page, isolates it from the LRU and
* puts it to the given pagelist.
- * Returns -errno if the page cannot be found/isolated or 0 when it has been
- * queued or the page doesn't need to be migrated because it is already on
- * the target node
+ * Returns:
+ * errno - if the page cannot be found/isolated
+ * 0 - when it doesn't have to be migrated because it is already on the
+ * target node
+ * 1 - when it has been queued
*/
static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
int node, struct list_head *pagelist, bool migrate_all)
@@ -1553,7 +1555,7 @@ static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
if (PageHuge(page)) {
if (PageHead(page)) {
isolate_huge_page(page, pagelist);
- err = 0;
+ err = 1;
}
} else {
struct page *head;
@@ -1563,7 +1565,7 @@ static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
if (err)
goto out_putpage;
- err = 0;
+ err = 1;
list_add_tail(&head->lru, pagelist);
mod_node_page_state(page_pgdat(head),
NR_ISOLATED_ANON + page_is_file_cache(head),
@@ -1640,8 +1642,17 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
*/
err = add_page_for_migration(mm, addr, current_node,
&pagelist, flags & MPOL_MF_MOVE_ALL);
- if (!err)
+
+ if (!err) {
+ /* The page is already on the target node */
+ err = store_status(status, i, current_node, 1);
+ if (err)
+ goto out_flush;
continue;
+ } else if (err > 0) {
+ /* The page is successfully queued for migration */
+ continue;
+ }
err = store_status(status, i, err, 1);
if (err)
diff --git a/mm/mmap.c b/mm/mmap.c
index 8f503c1..10b5f6e 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -89,12 +89,6 @@ static void unmap_region(struct mm_struct *mm,
* MAP_PRIVATE r: (no) no r: (yes) yes r: (no) yes r: (no) yes
* w: (no) no w: (no) no w: (copy) copy w: (no) no
* x: (no) no x: (no) yes x: (no) yes x: (yes) yes
- *
- * On arm64, PROT_EXEC has the following behaviour for both MAP_SHARED and
- * MAP_PRIVATE:
- * r: (no) no
- * w: (no) no
- * x: (yes) yes
*/
pgprot_t protection_map[16] __ro_after_init = {
__P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
diff --git a/mm/slub.c b/mm/slub.c
index 9e5a7e6..d5f745f 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1487,6 +1487,25 @@ static int init_cache_random_seq(struct kmem_cache *s)
return 0;
}
+/* re-initialize the random sequence cache */
+static int reinit_cache_random_seq(struct kmem_cache *s)
+{
+ int err;
+
+ if (s->random_seq) {
+ cache_random_seq_destroy(s);
+ err = init_cache_random_seq(s);
+
+ if (err) {
+ pr_err("SLUB: Unable to re-initialize random sequence cache for %s\n",
+ s->name);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
/* Initialize each random sequence freelist per cache */
static void __init init_freelist_randomization(void)
{
@@ -1561,6 +1580,10 @@ static inline int init_cache_random_seq(struct kmem_cache *s)
{
return 0;
}
+static inline int reinit_cache_random_seq(struct kmem_cache *s)
+{
+ return 0;
+}
static inline void init_freelist_randomization(void) { }
static inline bool shuffle_freelist(struct kmem_cache *s, struct page *page)
{
@@ -4935,6 +4958,7 @@ static ssize_t order_store(struct kmem_cache *s,
return -EINVAL;
calculate_sizes(s, order);
+ reinit_cache_random_seq(s);
return length;
}
@@ -5172,6 +5196,7 @@ static ssize_t red_zone_store(struct kmem_cache *s,
s->flags |= SLAB_RED_ZONE;
}
calculate_sizes(s, -1);
+ reinit_cache_random_seq(s);
return length;
}
SLAB_ATTR(red_zone);
@@ -5192,6 +5217,7 @@ static ssize_t poison_store(struct kmem_cache *s,
s->flags |= SLAB_POISON;
}
calculate_sizes(s, -1);
+ reinit_cache_random_seq(s);
return length;
}
SLAB_ATTR(poison);
@@ -5213,6 +5239,7 @@ static ssize_t store_user_store(struct kmem_cache *s,
s->flags |= SLAB_STORE_USER;
}
calculate_sizes(s, -1);
+ reinit_cache_random_seq(s);
return length;
}
SLAB_ATTR(store_user);
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index 0ae2f5f..12966a8 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -2092,6 +2092,11 @@ static int zs_page_migrate(struct address_space *mapping, struct page *newpage,
zs_pool_dec_isolated(pool);
}
+ if (page_zone(newpage) != page_zone(page)) {
+ dec_zone_page_state(page, NR_ZSPAGES);
+ inc_zone_page_state(newpage, NR_ZSPAGES);
+ }
+
reset_page(page);
put_page(page);
page = newpage;
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 44df1c3..e9cd8ef 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -114,6 +114,7 @@ int vlan_check_real_dev(struct net_device *real_dev,
void vlan_setup(struct net_device *dev);
int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack);
void unregister_vlan_dev(struct net_device *dev, struct list_head *head);
+void vlan_dev_uninit(struct net_device *dev);
bool vlan_dev_inherit_address(struct net_device *dev,
struct net_device *real_dev);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index fce3b7e..84ef837 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -612,7 +612,8 @@ static int vlan_dev_init(struct net_device *dev)
return 0;
}
-static void vlan_dev_uninit(struct net_device *dev)
+/* Note: this function might be called multiple times for the same device. */
+void vlan_dev_uninit(struct net_device *dev)
{
struct vlan_priority_tci_mapping *pm;
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index 9b60c1e..74042b9 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -110,11 +110,13 @@ static int vlan_changelink(struct net_device *dev, struct nlattr *tb[],
struct ifla_vlan_flags *flags;
struct ifla_vlan_qos_mapping *m;
struct nlattr *attr;
- int rem;
+ int rem, err;
if (data[IFLA_VLAN_FLAGS]) {
flags = nla_data(data[IFLA_VLAN_FLAGS]);
- vlan_dev_change_flags(dev, flags->flags, flags->mask);
+ err = vlan_dev_change_flags(dev, flags->flags, flags->mask);
+ if (err)
+ return err;
}
if (data[IFLA_VLAN_INGRESS_QOS]) {
nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
@@ -125,7 +127,9 @@ static int vlan_changelink(struct net_device *dev, struct nlattr *tb[],
if (data[IFLA_VLAN_EGRESS_QOS]) {
nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
m = nla_data(attr);
- vlan_dev_set_egress_priority(dev, m->from, m->to);
+ err = vlan_dev_set_egress_priority(dev, m->from, m->to);
+ if (err)
+ return err;
}
}
return 0;
@@ -181,10 +185,11 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
return -EINVAL;
err = vlan_changelink(dev, tb, data, extack);
- if (err < 0)
- return err;
-
- return register_vlan_dev(dev, extack);
+ if (!err)
+ err = register_vlan_dev(dev, extack);
+ if (err)
+ vlan_dev_uninit(dev);
+ return err;
}
static inline size_t vlan_qos_map_size(unsigned int n)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 15d1cb5..db735d0 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -931,6 +931,14 @@ static void hci_req_directed_advertising(struct hci_request *req,
return;
memset(&cp, 0, sizeof(cp));
+
+ /* Some controllers might reject command if intervals are not
+ * within range for undirected advertising.
+ * BCM20702A0 is known to be affected by this.
+ */
+ cp.min_interval = cpu_to_le16(0x0020);
+ cp.max_interval = cpu_to_le16(0x0020);
+
cp.type = LE_ADV_DIRECT_IND;
cp.own_address_type = own_addr_type;
cp.direct_addr_type = conn->dst_type;
@@ -1165,8 +1173,10 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
if (!conn)
return ERR_PTR(-ENOMEM);
- if (hci_explicit_conn_params_set(hdev, dst, dst_type) < 0)
+ if (hci_explicit_conn_params_set(hdev, dst, dst_type) < 0) {
+ hci_conn_del(conn);
return ERR_PTR(-EBUSY);
+ }
conn->state = BT_CONNECT;
set_bit(HCI_CONN_SCANNING, &conn->flags);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 5afd67e..e03faca 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -841,8 +841,8 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT) {
struct hci_cp_le_write_def_data_len cp;
- cp.tx_len = hdev->le_max_tx_len;
- cp.tx_time = hdev->le_max_tx_time;
+ cp.tx_len = cpu_to_le16(hdev->le_max_tx_len);
+ cp.tx_time = cpu_to_le16(hdev->le_max_tx_time);
hci_req_add(req, HCI_OP_LE_WRITE_DEF_DATA_LEN, sizeof(cp), &cp);
}
@@ -4330,7 +4330,14 @@ static void hci_rx_work(struct work_struct *work)
hci_send_to_sock(hdev, skb);
}
- if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
+ /* If the device has been opened in HCI_USER_CHANNEL,
+ * the userspace has exclusive access to device.
+ * When device is HCI_INIT, we still need to process
+ * the data packets to the driver in order
+ * to complete its setup().
+ */
+ if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
+ !test_bit(HCI_INIT, &hdev->flags)) {
kfree_skb(skb);
continue;
}
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 9448ebd..a8ddd21 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -1258,6 +1258,14 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
instance_flags = get_adv_instance_flags(hdev, instance);
+ /* If instance already has the flags set skip adding it once
+ * again.
+ */
+ if (adv_instance && eir_get_data(adv_instance->adv_data,
+ adv_instance->adv_data_len, EIR_FLAGS,
+ NULL))
+ goto skip_flags;
+
/* The Add Advertising command allows userspace to set both the general
* and limited discoverable flags.
*/
@@ -1290,6 +1298,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
}
}
+skip_flags:
if (adv_instance) {
memcpy(ptr, adv_instance->adv_data,
adv_instance->adv_data_len);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 974c1b8..0d84d1f 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4918,10 +4918,8 @@ void __l2cap_physical_cfm(struct l2cap_chan *chan, int result)
BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d",
chan, result, local_amp_id, remote_amp_id);
- if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) {
- l2cap_chan_unlock(chan);
+ if (chan->state == BT_DISCONN || chan->state == BT_CLOSED)
return;
- }
if (chan->state != BT_CONNECTED) {
l2cap_do_create(chan, result, local_amp_id, remote_amp_id);
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
index 212c184..ccab290 100644
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -646,6 +646,9 @@ static unsigned int br_nf_forward_arp(void *priv,
nf_bridge_pull_encap_header(skb);
}
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct arphdr))))
+ return NF_DROP;
+
if (arp_hdr(skb)->ar_pln != 4) {
if (IS_VLAN_ARP(skb))
nf_bridge_push_encap_header(skb);
diff --git a/net/bridge/br_nf_core.c b/net/bridge/br_nf_core.c
index 8e2d7cf..d88e724 100644
--- a/net/bridge/br_nf_core.c
+++ b/net/bridge/br_nf_core.c
@@ -26,7 +26,8 @@
#endif
static void fake_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu)
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh)
{
}
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 7d249af..785e19af 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -1876,7 +1876,7 @@ static int ebt_buf_count(struct ebt_entries_buf_state *state, unsigned int sz)
}
static int ebt_buf_add(struct ebt_entries_buf_state *state,
- void *data, unsigned int sz)
+ const void *data, unsigned int sz)
{
if (state->buf_kern_start == NULL)
goto count_only;
@@ -1910,7 +1910,7 @@ enum compat_mwt {
EBT_COMPAT_TARGET,
};
-static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
+static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt,
enum compat_mwt compat_mwt,
struct ebt_entries_buf_state *state,
const unsigned char *base)
@@ -1988,22 +1988,23 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
/* return size of all matches, watchers or target, including necessary
* alignment and padding.
*/
-static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32,
+static int ebt_size_mwt(const struct compat_ebt_entry_mwt *match32,
unsigned int size_left, enum compat_mwt type,
struct ebt_entries_buf_state *state, const void *base)
{
+ const char *buf = (const char *)match32;
int growth = 0;
- char *buf;
if (size_left == 0)
return 0;
- buf = (char *) match32;
-
- while (size_left >= sizeof(*match32)) {
+ do {
struct ebt_entry_match *match_kern;
int ret;
+ if (size_left < sizeof(*match32))
+ return -EINVAL;
+
match_kern = (struct ebt_entry_match *) state->buf_kern_start;
if (match_kern) {
char *tmp;
@@ -2040,22 +2041,18 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32,
if (match_kern)
match_kern->match_size = ret;
- /* rule should have no remaining data after target */
- if (type == EBT_COMPAT_TARGET && size_left)
- return -EINVAL;
-
match32 = (struct compat_ebt_entry_mwt *) buf;
- }
+ } while (size_left);
return growth;
}
/* called for all ebt_entry structures. */
-static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
+static int size_entry_mwt(const struct ebt_entry *entry, const unsigned char *base,
unsigned int *total,
struct ebt_entries_buf_state *state)
{
- unsigned int i, j, startoff, new_offset = 0;
+ unsigned int i, j, startoff, next_expected_off, new_offset = 0;
/* stores match/watchers/targets & offset of next struct ebt_entry: */
unsigned int offsets[4];
unsigned int *offsets_update = NULL;
@@ -2141,11 +2138,13 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
return ret;
}
- startoff = state->buf_user_offset - startoff;
-
- if (WARN_ON(*total < startoff))
+ next_expected_off = state->buf_user_offset - startoff;
+ if (next_expected_off != entry->next_offset)
return -EINVAL;
- *total -= startoff;
+
+ if (*total < entry->next_offset)
+ return -EINVAL;
+ *total -= entry->next_offset;
return 0;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index 055f21f..100784c 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -151,6 +151,7 @@
#include "net-sysfs.h"
#define MAX_GRO_SKBS 8
+#define MAX_NEST_DEV 8
/* This should be increased if a protocol with a bigger head is added. */
#define GRO_MAX_HEAD (MAX_HEADER + 128)
@@ -6572,6 +6573,21 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
}
EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu);
+static struct net_device *netdev_next_upper_dev(struct net_device *dev,
+ struct list_head **iter)
+{
+ struct netdev_adjacent *upper;
+
+ upper = list_entry((*iter)->next, struct netdev_adjacent, list);
+
+ if (&upper->list == &dev->adj_list.upper)
+ return NULL;
+
+ *iter = &upper->list;
+
+ return upper->dev;
+}
+
static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
struct list_head **iter)
{
@@ -6589,28 +6605,93 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
return upper->dev;
}
+static int netdev_walk_all_upper_dev(struct net_device *dev,
+ int (*fn)(struct net_device *dev,
+ void *data),
+ void *data)
+{
+ struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
+ struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
+ int ret, cur = 0;
+
+ now = dev;
+ iter = &dev->adj_list.upper;
+
+ while (1) {
+ if (now != dev) {
+ ret = fn(now, data);
+ if (ret)
+ return ret;
+ }
+
+ next = NULL;
+ while (1) {
+ udev = netdev_next_upper_dev(now, &iter);
+ if (!udev)
+ break;
+
+ next = udev;
+ niter = &udev->adj_list.upper;
+ dev_stack[cur] = now;
+ iter_stack[cur++] = iter;
+ break;
+ }
+
+ if (!next) {
+ if (!cur)
+ return 0;
+ next = dev_stack[--cur];
+ niter = iter_stack[cur];
+ }
+
+ now = next;
+ iter = niter;
+ }
+
+ return 0;
+}
+
int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
int (*fn)(struct net_device *dev,
void *data),
void *data)
{
- struct net_device *udev;
- struct list_head *iter;
- int ret;
+ struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
+ struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
+ int ret, cur = 0;
- for (iter = &dev->adj_list.upper,
- udev = netdev_next_upper_dev_rcu(dev, &iter);
- udev;
- udev = netdev_next_upper_dev_rcu(dev, &iter)) {
- /* first is the upper device itself */
- ret = fn(udev, data);
- if (ret)
- return ret;
+ now = dev;
+ iter = &dev->adj_list.upper;
- /* then look at all of its upper devices */
- ret = netdev_walk_all_upper_dev_rcu(udev, fn, data);
- if (ret)
- return ret;
+ while (1) {
+ if (now != dev) {
+ ret = fn(now, data);
+ if (ret)
+ return ret;
+ }
+
+ next = NULL;
+ while (1) {
+ udev = netdev_next_upper_dev_rcu(now, &iter);
+ if (!udev)
+ break;
+
+ next = udev;
+ niter = &udev->adj_list.upper;
+ dev_stack[cur] = now;
+ iter_stack[cur++] = iter;
+ break;
+ }
+
+ if (!next) {
+ if (!cur)
+ return 0;
+ next = dev_stack[--cur];
+ niter = iter_stack[cur];
+ }
+
+ now = next;
+ iter = niter;
}
return 0;
@@ -6718,23 +6799,42 @@ int netdev_walk_all_lower_dev(struct net_device *dev,
void *data),
void *data)
{
- struct net_device *ldev;
- struct list_head *iter;
- int ret;
+ struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
+ struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
+ int ret, cur = 0;
- for (iter = &dev->adj_list.lower,
- ldev = netdev_next_lower_dev(dev, &iter);
- ldev;
- ldev = netdev_next_lower_dev(dev, &iter)) {
- /* first is the lower device itself */
- ret = fn(ldev, data);
- if (ret)
- return ret;
+ now = dev;
+ iter = &dev->adj_list.lower;
- /* then look at all of its lower devices */
- ret = netdev_walk_all_lower_dev(ldev, fn, data);
- if (ret)
- return ret;
+ while (1) {
+ if (now != dev) {
+ ret = fn(now, data);
+ if (ret)
+ return ret;
+ }
+
+ next = NULL;
+ while (1) {
+ ldev = netdev_next_lower_dev(now, &iter);
+ if (!ldev)
+ break;
+
+ next = ldev;
+ niter = &ldev->adj_list.lower;
+ dev_stack[cur] = now;
+ iter_stack[cur++] = iter;
+ break;
+ }
+
+ if (!next) {
+ if (!cur)
+ return 0;
+ next = dev_stack[--cur];
+ niter = iter_stack[cur];
+ }
+
+ now = next;
+ iter = niter;
}
return 0;
@@ -6755,28 +6855,93 @@ static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
return lower->dev;
}
+static u8 __netdev_upper_depth(struct net_device *dev)
+{
+ struct net_device *udev;
+ struct list_head *iter;
+ u8 max_depth = 0;
+
+ for (iter = &dev->adj_list.upper,
+ udev = netdev_next_upper_dev(dev, &iter);
+ udev;
+ udev = netdev_next_upper_dev(dev, &iter)) {
+ if (max_depth < udev->upper_level)
+ max_depth = udev->upper_level;
+ }
+
+ return max_depth;
+}
+
+static u8 __netdev_lower_depth(struct net_device *dev)
+{
+ struct net_device *ldev;
+ struct list_head *iter;
+ u8 max_depth = 0;
+
+ for (iter = &dev->adj_list.lower,
+ ldev = netdev_next_lower_dev(dev, &iter);
+ ldev;
+ ldev = netdev_next_lower_dev(dev, &iter)) {
+ if (max_depth < ldev->lower_level)
+ max_depth = ldev->lower_level;
+ }
+
+ return max_depth;
+}
+
+static int __netdev_update_upper_level(struct net_device *dev, void *data)
+{
+ dev->upper_level = __netdev_upper_depth(dev) + 1;
+ return 0;
+}
+
+static int __netdev_update_lower_level(struct net_device *dev, void *data)
+{
+ dev->lower_level = __netdev_lower_depth(dev) + 1;
+ return 0;
+}
+
int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
int (*fn)(struct net_device *dev,
void *data),
void *data)
{
- struct net_device *ldev;
- struct list_head *iter;
- int ret;
+ struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
+ struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
+ int ret, cur = 0;
- for (iter = &dev->adj_list.lower,
- ldev = netdev_next_lower_dev_rcu(dev, &iter);
- ldev;
- ldev = netdev_next_lower_dev_rcu(dev, &iter)) {
- /* first is the lower device itself */
- ret = fn(ldev, data);
- if (ret)
- return ret;
+ now = dev;
+ iter = &dev->adj_list.lower;
- /* then look at all of its lower devices */
- ret = netdev_walk_all_lower_dev_rcu(ldev, fn, data);
- if (ret)
- return ret;
+ while (1) {
+ if (now != dev) {
+ ret = fn(now, data);
+ if (ret)
+ return ret;
+ }
+
+ next = NULL;
+ while (1) {
+ ldev = netdev_next_lower_dev_rcu(now, &iter);
+ if (!ldev)
+ break;
+
+ next = ldev;
+ niter = &ldev->adj_list.lower;
+ dev_stack[cur] = now;
+ iter_stack[cur++] = iter;
+ break;
+ }
+
+ if (!next) {
+ if (!cur)
+ return 0;
+ next = dev_stack[--cur];
+ niter = iter_stack[cur];
+ }
+
+ now = next;
+ iter = niter;
}
return 0;
@@ -7033,6 +7198,9 @@ static int __netdev_upper_dev_link(struct net_device *dev,
if (netdev_has_upper_dev(upper_dev, dev))
return -EBUSY;
+ if ((dev->lower_level + upper_dev->upper_level) > MAX_NEST_DEV)
+ return -EMLINK;
+
if (!master) {
if (netdev_has_upper_dev(dev, upper_dev))
return -EEXIST;
@@ -7059,6 +7227,12 @@ static int __netdev_upper_dev_link(struct net_device *dev,
if (ret)
goto rollback;
+ __netdev_update_upper_level(dev, NULL);
+ netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
+
+ __netdev_update_lower_level(upper_dev, NULL);
+ netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, NULL);
+
return 0;
rollback:
@@ -7141,6 +7315,12 @@ void netdev_upper_dev_unlink(struct net_device *dev,
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
&changeupper_info.info);
+
+ __netdev_update_upper_level(dev, NULL);
+ netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
+
+ __netdev_update_lower_level(upper_dev, NULL);
+ netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, NULL);
}
EXPORT_SYMBOL(netdev_upper_dev_unlink);
@@ -9008,6 +9188,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
dev->gso_max_size = GSO_MAX_SIZE;
dev->gso_max_segs = GSO_MAX_SEGS;
+ dev->upper_level = 1;
+ dev->lower_level = 1;
INIT_LIST_HEAD(&dev->napi_list);
INIT_LIST_HEAD(&dev->unreg_list);
diff --git a/net/core/filter.c b/net/core/filter.c
index e6fa885..91b9502 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2007,6 +2007,7 @@ static inline int __bpf_tx_skb(struct net_device *dev, struct sk_buff *skb)
}
skb->dev = dev;
+ skb->tstamp = 0;
__this_cpu_inc(xmit_recursion);
ret = dev_queue_xmit(skb);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 286aca5..e6260c8 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1097,7 +1097,7 @@ static void neigh_update_hhs(struct neighbour *neigh)
if (update) {
hh = &neigh->hh;
- if (hh->hh_len) {
+ if (READ_ONCE(hh->hh_len)) {
write_seqlock_bh(&hh->hh_lock);
update(hh, neigh->dev, neigh->ha);
write_sequnlock_bh(&hh->hh_lock);
@@ -1360,7 +1360,7 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
struct net_device *dev = neigh->dev;
unsigned int seq;
- if (dev->header_ops->cache && !neigh->hh.hh_len)
+ if (dev->header_ops->cache && !READ_ONCE(neigh->hh.hh_len))
neigh_hh_init(neigh);
do {
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index d67ec17..6cec08c 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -281,6 +281,7 @@ static int proc_dointvec_minmax_bpf_enable(struct ctl_table *table, int write,
return ret;
}
+# ifdef CONFIG_HAVE_EBPF_JIT
static int
proc_dointvec_minmax_bpf_restricted(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
@@ -291,6 +292,7 @@ proc_dointvec_minmax_bpf_restricted(struct ctl_table *table, int write,
return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
}
+# endif /* CONFIG_HAVE_EBPF_JIT */
static int
proc_dolongvec_minmax_bpf_restricted(struct ctl_table *table, int write,
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 1c002c0..658191f 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -118,7 +118,8 @@ static void dn_dst_ifdown(struct dst_entry *, struct net_device *dev, int how);
static struct dst_entry *dn_dst_negative_advice(struct dst_entry *);
static void dn_dst_link_failure(struct sk_buff *);
static void dn_dst_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb , u32 mtu);
+ struct sk_buff *skb , u32 mtu,
+ bool confirm_neigh);
static void dn_dst_redirect(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb);
static struct neighbour *dn_dst_neigh_lookup(const struct dst_entry *dst,
@@ -259,7 +260,8 @@ static int dn_dst_gc(struct dst_ops *ops)
* advertise to the other end).
*/
static void dn_dst_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu)
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh)
{
struct dn_route *rt = (struct dn_route *) dst;
struct neighbour *n = rt->n;
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index fd8faa0..ca06e9a 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -239,7 +239,12 @@ int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh, __be16
eth->h_proto = type;
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, neigh->ha, ETH_ALEN);
- hh->hh_len = ETH_HLEN;
+
+ /* Pairs with READ_ONCE() in neigh_resolve_output(),
+ * neigh_hh_output() and neigh_update_hhs().
+ */
+ smp_store_release(&hh->hh_len, ETH_HLEN);
+
return 0;
}
EXPORT_SYMBOL(eth_header_cache);
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 0167e23..4efa5e3 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -254,10 +254,11 @@ bool icmp_global_allow(void)
bool rc = false;
/* Check if token bucket is empty and cannot be refilled
- * without taking the spinlock.
+ * without taking the spinlock. The READ_ONCE() are paired
+ * with the following WRITE_ONCE() in this same function.
*/
- if (!icmp_global.credit) {
- delta = min_t(u32, now - icmp_global.stamp, HZ);
+ if (!READ_ONCE(icmp_global.credit)) {
+ delta = min_t(u32, now - READ_ONCE(icmp_global.stamp), HZ);
if (delta < HZ / 50)
return false;
}
@@ -267,14 +268,14 @@ bool icmp_global_allow(void)
if (delta >= HZ / 50) {
incr = sysctl_icmp_msgs_per_sec * delta / HZ ;
if (incr)
- icmp_global.stamp = now;
+ WRITE_ONCE(icmp_global.stamp, now);
}
credit = min_t(u32, icmp_global.credit + incr, sysctl_icmp_msgs_burst);
if (credit) {
credit--;
rc = true;
}
- icmp_global.credit = credit;
+ WRITE_ONCE(icmp_global.credit, credit);
spin_unlock(&icmp_global.lock);
return rc;
}
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 6a56ec8..9ef63de 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -1096,7 +1096,7 @@ struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu)
if (!dst)
goto out;
}
- dst->ops->update_pmtu(dst, sk, NULL, mtu);
+ dst->ops->update_pmtu(dst, sk, NULL, mtu, true);
dst = __sk_dst_check(sk, 0);
if (!dst)
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 5731670..9742b37 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -918,11 +918,12 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
struct inet_listen_hashbucket *ilb;
+ struct hlist_nulls_node *node;
num = 0;
ilb = &hashinfo->listening_hash[i];
spin_lock(&ilb->lock);
- sk_for_each(sk, &ilb->head) {
+ sk_nulls_for_each(sk, node, &ilb->nulls_head) {
struct inet_sock *inet = inet_sk(sk);
if (!net_eq(sock_net(sk), net))
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 7be966a..b53da26 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -308,6 +308,7 @@ struct sock *__inet_lookup_listener(struct net *net,
bool exact_dif = inet_exact_dif_match(net, skb);
struct inet_listen_hashbucket *ilb2;
struct sock *sk, *result = NULL;
+ struct hlist_nulls_node *node;
int score, hiscore = 0;
unsigned int hash2;
u32 phash = 0;
@@ -343,7 +344,7 @@ struct sock *__inet_lookup_listener(struct net *net,
goto done;
port_lookup:
- sk_for_each_rcu(sk, &ilb->head) {
+ sk_nulls_for_each_rcu(sk, node, &ilb->nulls_head) {
score = compute_score(sk, net, hnum, daddr,
dif, sdif, exact_dif);
if (score > hiscore) {
@@ -560,10 +561,11 @@ static int inet_reuseport_add_sock(struct sock *sk,
struct inet_listen_hashbucket *ilb)
{
struct inet_bind_bucket *tb = inet_csk(sk)->icsk_bind_hash;
+ const struct hlist_nulls_node *node;
struct sock *sk2;
kuid_t uid = sock_i_uid(sk);
- sk_for_each_rcu(sk2, &ilb->head) {
+ sk_nulls_for_each_rcu(sk2, node, &ilb->nulls_head) {
if (sk2 != sk &&
sk2->sk_family == sk->sk_family &&
ipv6_only_sock(sk2) == ipv6_only_sock(sk) &&
@@ -599,9 +601,9 @@ int __inet_hash(struct sock *sk, struct sock *osk)
}
if (IS_ENABLED(CONFIG_IPV6) && sk->sk_reuseport &&
sk->sk_family == AF_INET6)
- hlist_add_tail_rcu(&sk->sk_node, &ilb->head);
+ __sk_nulls_add_node_tail_rcu(sk, &ilb->nulls_head);
else
- hlist_add_head_rcu(&sk->sk_node, &ilb->head);
+ __sk_nulls_add_node_rcu(sk, &ilb->nulls_head);
inet_hash2(hashinfo, sk);
ilb->count++;
sock_set_flag(sk, SOCK_RCU_FREE);
@@ -650,11 +652,9 @@ void inet_unhash(struct sock *sk)
reuseport_detach_sock(sk);
if (ilb) {
inet_unhash2(hashinfo, sk);
- __sk_del_node_init(sk);
- ilb->count--;
- } else {
- __sk_nulls_del_node_init_rcu(sk);
+ ilb->count--;
}
+ __sk_nulls_del_node_init_rcu(sk);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
unlock:
spin_unlock_bh(lock);
@@ -790,7 +790,8 @@ void inet_hashinfo_init(struct inet_hashinfo *h)
for (i = 0; i < INET_LHTABLE_SIZE; i++) {
spin_lock_init(&h->listening_hash[i].lock);
- INIT_HLIST_HEAD(&h->listening_hash[i].head);
+ INIT_HLIST_NULLS_HEAD(&h->listening_hash[i].nulls_head,
+ i + LISTENING_NULLS_BASE);
h->listening_hash[i].count = 0;
}
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index be77859..ff327a6 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -160,7 +160,12 @@ static void inet_peer_gc(struct inet_peer_base *base,
base->total / inet_peer_threshold * HZ;
for (i = 0; i < gc_cnt; i++) {
p = gc_stack[i];
- delta = (__u32)jiffies - p->dtime;
+
+ /* The READ_ONCE() pairs with the WRITE_ONCE()
+ * in inet_putpeer()
+ */
+ delta = (__u32)jiffies - READ_ONCE(p->dtime);
+
if (delta < ttl || !refcount_dec_if_one(&p->refcnt))
gc_stack[i] = NULL;
}
@@ -237,7 +242,10 @@ EXPORT_SYMBOL_GPL(inet_getpeer);
void inet_putpeer(struct inet_peer *p)
{
- p->dtime = (__u32)jiffies;
+ /* The WRITE_ONCE() pairs with itself (we run lockless)
+ * and the READ_ONCE() in inet_peer_gc()
+ */
+ WRITE_ONCE(p->dtime, (__u32)jiffies);
if (refcount_dec_and_test(&p->refcnt))
call_rcu(&p->rcu, inetpeer_free_rcu);
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 054d01c..420e891 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -513,7 +513,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
else
mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
- skb_dst_update_pmtu(skb, mtu);
+ skb_dst_update_pmtu_no_confirm(skb, mtu);
if (skb->protocol == htons(ETH_P_IP)) {
if (!skb_is_gso(skb) &&
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 808f8d1..960f4fa 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -235,7 +235,7 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
mtu = dst_mtu(dst);
if (skb->len > mtu) {
- skb_dst_update_pmtu(skb, mtu);
+ skb_dst_update_pmtu_no_confirm(skb, mtu);
if (skb->protocol == htons(ETH_P_IP)) {
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
htonl(mtu));
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 2dc83de..0199ee8 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -915,8 +915,6 @@ static int __do_replace(struct net *net, const char *name,
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
- xt_table_unlock(t);
-
get_old_counters(oldinfo, counters);
/* Decrease module usage counts and free resource */
@@ -931,6 +929,7 @@ static int __do_replace(struct net *net, const char *name,
net_warn_ratelimited("arptables: counters copy to user failed while replacing table\n");
}
vfree(counters);
+ xt_table_unlock(t);
return ret;
put_module:
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index e77872c..62934d3 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1079,8 +1079,6 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
- xt_table_unlock(t);
-
get_old_counters(oldinfo, counters);
/* Decrease module usage counts and free resource */
@@ -1094,6 +1092,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
net_warn_ratelimited("iptables: counters copy to user failed while replacing table\n");
}
vfree(counters);
+ xt_table_unlock(t);
return ret;
put_module:
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 69127f60..4590af5 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -142,7 +142,8 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst);
static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
static void ipv4_link_failure(struct sk_buff *skb);
static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu);
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh);
static void ip_do_redirect(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb);
static void ipv4_dst_destroy(struct dst_entry *dst);
@@ -1035,7 +1036,8 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
}
static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu)
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh)
{
struct rtable *rt = (struct rtable *) dst;
struct flowi4 fl4;
@@ -2559,7 +2561,8 @@ static unsigned int ipv4_blackhole_mtu(const struct dst_entry *dst)
}
static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu)
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh)
{
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 591f041..5986c2e 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -488,7 +488,7 @@ static void tcp_tx_timestamp(struct sock *sk, u16 tsflags)
static inline bool tcp_stream_is_readable(const struct tcp_sock *tp,
int target, struct sock *sk)
{
- return (tp->rcv_nxt - tp->copied_seq >= target) ||
+ return (READ_ONCE(tp->rcv_nxt) - tp->copied_seq >= target) ||
(sk->sk_prot->stream_memory_read ?
sk->sk_prot->stream_memory_read(sk) : false);
}
@@ -2869,7 +2869,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
else if (tp->repair_queue == TCP_SEND_QUEUE)
tp->write_seq = val;
else if (tp->repair_queue == TCP_RECV_QUEUE)
- tp->rcv_nxt = val;
+ WRITE_ONCE(tp->rcv_nxt, val);
else
err = -EINVAL;
break;
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 81148f7..c9e97f3 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -30,7 +30,7 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
} else if (sk->sk_type == SOCK_STREAM) {
const struct tcp_sock *tp = tcp_sk(sk);
- r->idiag_rqueue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
+ r->idiag_rqueue = max_t(int, READ_ONCE(tp->rcv_nxt) - tp->copied_seq, 0);
r->idiag_wqueue = tp->write_seq - tp->snd_una;
}
if (info)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 57e8dad..578b65e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1716,8 +1716,11 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
}
/* Ignore very old stuff early */
- if (!after(sp[used_sacks].end_seq, prior_snd_una))
+ if (!after(sp[used_sacks].end_seq, prior_snd_una)) {
+ if (i == 0)
+ first_sack_index = -1;
continue;
+ }
used_sacks++;
}
@@ -3348,7 +3351,7 @@ static void tcp_rcv_nxt_update(struct tcp_sock *tp, u32 seq)
sock_owned_by_me((struct sock *)tp);
tp->bytes_received += delta;
- tp->rcv_nxt = seq;
+ WRITE_ONCE(tp->rcv_nxt, seq);
}
/* Update our send window.
@@ -5829,7 +5832,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
/* Ok.. it's good. Set up sequence numbers and
* move to established.
*/
- tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
+ WRITE_ONCE(tp->rcv_nxt, TCP_SKB_CB(skb)->seq + 1);
tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
/* RFC1323: The window in SYN & SYN/ACK segments is
@@ -5932,7 +5935,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
tp->tcp_header_len = sizeof(struct tcphdr);
}
- tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
+ WRITE_ONCE(tp->rcv_nxt, TCP_SKB_CB(skb)->seq + 1);
tp->copied_seq = tp->rcv_nxt;
tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 4ad1984..da19770 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2020,13 +2020,14 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
struct tcp_iter_state *st = seq->private;
struct net *net = seq_file_net(seq);
struct inet_listen_hashbucket *ilb;
+ struct hlist_nulls_node *node;
struct sock *sk = cur;
if (!sk) {
get_head:
ilb = &tcp_hashinfo.listening_hash[st->bucket];
spin_lock(&ilb->lock);
- sk = sk_head(&ilb->head);
+ sk = sk_nulls_head(&ilb->nulls_head);
st->offset = 0;
goto get_sk;
}
@@ -2034,9 +2035,9 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
++st->num;
++st->offset;
- sk = sk_next(sk);
+ sk = sk_nulls_next(sk);
get_sk:
- sk_for_each_from(sk) {
+ sk_nulls_for_each_from(sk, node) {
if (!net_eq(sock_net(sk), net))
continue;
if (sk->sk_family == afinfo->family)
@@ -2333,7 +2334,8 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
/* Because we don't lock the socket,
* we might find a transient negative value.
*/
- rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
+ rx_queue = max_t(int, READ_ONCE(tp->rcv_nxt) -
+ tp->copied_seq, 0);
seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d",
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 12affb7..7ba8a90 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -454,6 +454,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
struct tcp_request_sock *treq = tcp_rsk(req);
struct inet_connection_sock *newicsk;
struct tcp_sock *oldtp, *newtp;
+ u32 seq;
if (!newsk)
return NULL;
@@ -467,8 +468,10 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
/* Now setup tcp_sock */
newtp->pred_flags = 0;
- newtp->rcv_wup = newtp->copied_seq =
- newtp->rcv_nxt = treq->rcv_isn + 1;
+ seq = treq->rcv_isn + 1;
+ newtp->rcv_wup = seq;
+ newtp->copied_seq = seq;
+ WRITE_ONCE(newtp->rcv_nxt, seq);
newtp->segs_in = 1;
newtp->snd_sml = newtp->snd_una =
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index ad787e7..1cc20ed 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -60,6 +60,9 @@ static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb)
__skb_unlink(skb, &sk->sk_write_queue);
tcp_rbtree_insert(&sk->tcp_rtx_queue, skb);
+ if (tp->highest_sack == NULL)
+ tp->highest_sack = skb;
+
tp->packets_out += tcp_skb_pcount(skb);
if (!prior_packets || icsk->icsk_pending == ICSK_TIME_LOSS_PROBE)
tcp_rearm_rto(sk);
@@ -2373,6 +2376,14 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
if (tcp_small_queue_check(sk, skb, 0))
break;
+ /* Argh, we hit an empty skb(), presumably a thread
+ * is sleeping in sendmsg()/sk_stream_wait_memory().
+ * We do not want to send a pure-ack packet and have
+ * a strange looking rtx queue with empty packet(s).
+ */
+ if (TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq)
+ break;
+
if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
break;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 0618ec7..6d22933 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1418,7 +1418,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
* queue contains some other skb
*/
rmem = atomic_add_return(size, &sk->sk_rmem_alloc);
- if (rmem > (size + sk->sk_rcvbuf))
+ if (rmem > (size + (unsigned int)sk->sk_rcvbuf))
goto uncharge_drop;
spin_lock(&list->lock);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 2b144b9..1e5e2e4 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -222,12 +222,13 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
}
static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu)
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh)
{
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
struct dst_entry *path = xdst->route;
- path->ops->update_pmtu(path, sk, skb, mtu);
+ path->ops->update_pmtu(path, sk, skb, mtu, confirm_neigh);
}
static void xfrm4_redirect(struct dst_entry *dst, struct sock *sk,
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 9a31d13..890adad 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -150,7 +150,7 @@ struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu)
if (IS_ERR(dst))
return NULL;
- dst->ops->update_pmtu(dst, sk, NULL, mtu);
+ dst->ops->update_pmtu(dst, sk, NULL, mtu, true);
dst = inet6_csk_route_socket(sk, &fl6);
return IS_ERR(dst) ? NULL : dst;
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 91d6ea9..d9e2575 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -171,6 +171,7 @@ struct sock *inet6_lookup_listener(struct net *net,
bool exact_dif = inet6_exact_dif_match(net, skb);
struct inet_listen_hashbucket *ilb2;
struct sock *sk, *result = NULL;
+ struct hlist_nulls_node *node;
int score, hiscore = 0;
unsigned int hash2;
u32 phash = 0;
@@ -206,7 +207,7 @@ struct sock *inet6_lookup_listener(struct net *net,
goto done;
port_lookup:
- sk_for_each(sk, &ilb->head) {
+ sk_nulls_for_each(sk, node, &ilb->nulls_head) {
score = compute_score(sk, net, hnum, daddr, dif, sdif, exact_dif);
if (score > hiscore) {
if (sk->sk_reuseport) {
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 8fd28ed..b3515a4 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -1060,7 +1060,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
/* TooBig packet may have updated dst->dev's mtu */
if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu)
- dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu);
+ dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu, false);
err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
NEXTHDR_GRE);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index d0ad85b..e3b4237 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -645,7 +645,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (rel_info > dst_mtu(skb_dst(skb2)))
goto out;
- skb_dst_update_pmtu(skb2, rel_info);
+ skb_dst_update_pmtu_no_confirm(skb2, rel_info);
}
icmp_send(skb2, rel_type, rel_code, htonl(rel_info));
@@ -1137,7 +1137,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
mtu = max(mtu, skb->protocol == htons(ETH_P_IPV6) ?
IPV6_MIN_MTU : IPV4_MIN_MTU);
- skb_dst_update_pmtu(skb, mtu);
+ skb_dst_update_pmtu_no_confirm(skb, mtu);
if (skb->len - t->tun_hlen - eth_hlen > mtu && !skb_is_gso(skb)) {
*pmtu = mtu;
err = -EMSGSIZE;
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index 8b6eeff..bfd39db3 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -483,7 +483,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
mtu = dst_mtu(dst);
if (skb->len > mtu) {
- skb_dst_update_pmtu(skb, mtu);
+ skb_dst_update_pmtu_no_confirm(skb, mtu);
if (skb->protocol == htons(ETH_P_IPV6)) {
if (mtu < IPV6_MIN_MTU)
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index daf2e9e..06341def 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1096,8 +1096,6 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
- xt_table_unlock(t);
-
get_old_counters(oldinfo, counters);
/* Decrease module usage counts and free resource */
@@ -1111,6 +1109,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
net_warn_ratelimited("ip6tables: counters copy to user failed while replacing table\n");
}
vfree(counters);
+ xt_table_unlock(t);
return ret;
put_module:
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index b74fcd8..6370f07 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -99,7 +99,8 @@ static int ip6_pkt_prohibit(struct sk_buff *skb);
static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
static void ip6_link_failure(struct sk_buff *skb);
static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu);
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh);
static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb);
static int rt6_score_route(struct fib6_info *rt, int oif, int strict);
@@ -266,7 +267,8 @@ static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
}
static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu)
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh)
{
}
@@ -2352,7 +2354,8 @@ static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
}
static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
- const struct ipv6hdr *iph, u32 mtu)
+ const struct ipv6hdr *iph, u32 mtu,
+ bool confirm_neigh)
{
const struct in6_addr *daddr, *saddr;
struct rt6_info *rt6 = (struct rt6_info *)dst;
@@ -2370,7 +2373,10 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
daddr = NULL;
saddr = NULL;
}
- dst_confirm_neigh(dst, daddr);
+
+ if (confirm_neigh)
+ dst_confirm_neigh(dst, daddr);
+
mtu = max_t(u32, mtu, IPV6_MIN_MTU);
if (mtu >= dst_mtu(dst))
return;
@@ -2401,9 +2407,11 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
}
static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu)
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh)
{
- __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
+ __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu,
+ confirm_neigh);
}
void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
@@ -2423,7 +2431,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
dst = ip6_route_output(net, NULL, &fl6);
if (!dst->error)
- __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
+ __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu), true);
dst_release(dst);
}
EXPORT_SYMBOL_GPL(ip6_update_pmtu);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 41b3fe8..bfed750 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -943,7 +943,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
}
if (tunnel->parms.iph.daddr)
- skb_dst_update_pmtu(skb, mtu);
+ skb_dst_update_pmtu_no_confirm(skb, mtu);
if (skb->len > mtu && !skb_is_gso(skb)) {
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5a0bff9..c4932a6 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1840,7 +1840,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
/* Because we don't lock the socket,
* we might find a transient negative value.
*/
- rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
+ rx_queue = max_t(int, READ_ONCE(tp->rcv_nxt) -
+ tp->copied_seq, 0);
if (inet->transparent)
state_seq |= 0x80;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index d35bcf9..3023259 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -221,12 +221,13 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
}
static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu)
+ struct sk_buff *skb, u32 mtu,
+ bool confirm_neigh)
{
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
struct dst_entry *path = xdst->route;
- path->ops->update_pmtu(path, sk, skb, mtu);
+ path->ops->update_pmtu(path, sk, skb, mtu, confirm_neigh);
}
static void xfrm6_redirect(struct dst_entry *dst, struct sock *sk,
diff --git a/net/llc/llc_station.c b/net/llc/llc_station.c
index 204a835..c29170e 100644
--- a/net/llc/llc_station.c
+++ b/net/llc/llc_station.c
@@ -32,7 +32,7 @@ static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb)
return LLC_PDU_IS_CMD(pdu) && /* command PDU */
LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID &&
- !pdu->dsap ? 0 : 1; /* NULL DSAP value */
+ !pdu->dsap; /* NULL DSAP value */
}
static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb)
@@ -42,7 +42,7 @@ static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb)
return LLC_PDU_IS_CMD(pdu) && /* command PDU */
LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST &&
- !pdu->dsap ? 0 : 1; /* NULL DSAP */
+ !pdu->dsap; /* NULL DSAP */
}
static int llc_station_ac_send_xid_r(struct sk_buff *skb)
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 9afd3fc..d5db1c4 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -871,7 +871,8 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
I802_DEBUG_INC(local->dot11FailedCount);
}
- if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) &&
+ if ((ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) &&
+ ieee80211_has_pm(fc) &&
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS) &&
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
local->ps_sdata && !(local->scanning)) {
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 473cce2..3f75cd9 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -209,7 +209,7 @@ static inline void maybe_update_pmtu(int skb_af, struct sk_buff *skb, int mtu)
struct rtable *ort = skb_rtable(skb);
if (!skb->dev && sk && sk_fullsock(sk))
- ort->dst.ops->update_pmtu(&ort->dst, sk, NULL, mtu);
+ ort->dst.ops->update_pmtu(&ort->dst, sk, NULL, mtu, true);
}
static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af,
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 47e5a07..7ba9ea5 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -3576,6 +3576,9 @@ static void __net_exit ctnetlink_net_exit_batch(struct list_head *net_exit_list)
list_for_each_entry(net, net_exit_list, exit_list)
ctnetlink_net_exit(net);
+
+ /* wait for other cpus until they are done with ctnl_notifiers */
+ synchronize_rcu();
}
static struct pernet_operations ctnetlink_net_ops = {
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index a96a8c1..ee6d983 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -174,7 +174,7 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
goto err;
}
- if (!skb_dst_force(skb) && state->hook != NF_INET_PRE_ROUTING) {
+ if (skb_dst(skb) && !skb_dst_force(skb)) {
status = -ENETDOWN;
goto err;
}
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 0e1b1f7..4711a8b 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -4117,8 +4117,10 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
return err;
err = -EINVAL;
- if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
+ if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) {
+ nft_data_release(&elem.key.val, desc.type);
return err;
+ }
priv = set->ops->get(ctx->net, set, &elem, flags);
if (IS_ERR(priv))
@@ -4351,14 +4353,20 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (nla[NFTA_SET_ELEM_DATA] == NULL &&
!(flags & NFT_SET_ELEM_INTERVAL_END))
return -EINVAL;
- if (nla[NFTA_SET_ELEM_DATA] != NULL &&
- flags & NFT_SET_ELEM_INTERVAL_END)
- return -EINVAL;
} else {
if (nla[NFTA_SET_ELEM_DATA] != NULL)
return -EINVAL;
}
+ if ((flags & NFT_SET_ELEM_INTERVAL_END) &&
+ (nla[NFTA_SET_ELEM_DATA] ||
+ nla[NFTA_SET_ELEM_OBJREF] ||
+ nla[NFTA_SET_ELEM_TIMEOUT] ||
+ nla[NFTA_SET_ELEM_EXPIRATION] ||
+ nla[NFTA_SET_ELEM_USERDATA] ||
+ nla[NFTA_SET_ELEM_EXPR]))
+ return -EINVAL;
+
timeout = 0;
if (nla[NFTA_SET_ELEM_TIMEOUT] != NULL) {
if (!(set->flags & NFT_SET_TIMEOUT))
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
index fff8073..058ee84 100644
--- a/net/netfilter/nft_bitwise.c
+++ b/net/netfilter/nft_bitwise.c
@@ -83,7 +83,7 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
tb[NFTA_BITWISE_MASK]);
if (err < 0)
return err;
- if (d1.len != priv->len) {
+ if (d1.type != NFT_DATA_VALUE || d1.len != priv->len) {
err = -EINVAL;
goto err1;
}
@@ -92,7 +92,7 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
tb[NFTA_BITWISE_XOR]);
if (err < 0)
goto err1;
- if (d2.len != priv->len) {
+ if (d2.type != NFT_DATA_VALUE || d2.len != priv->len) {
err = -EINVAL;
goto err2;
}
diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c
index 79d48c1..7007045 100644
--- a/net/netfilter/nft_cmp.c
+++ b/net/netfilter/nft_cmp.c
@@ -82,6 +82,12 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
if (err < 0)
return err;
+ if (desc.type != NFT_DATA_VALUE) {
+ err = -EINVAL;
+ nft_data_release(&priv->data, desc.type);
+ return err;
+ }
+
priv->sreg = nft_parse_register(tb[NFTA_CMP_SREG]);
err = nft_validate_register_load(priv->sreg, desc.len);
if (err < 0)
diff --git a/net/netfilter/nft_range.c b/net/netfilter/nft_range.c
index cedb96c..2e1d2ec 100644
--- a/net/netfilter/nft_range.c
+++ b/net/netfilter/nft_range.c
@@ -70,11 +70,21 @@ static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr
if (err < 0)
return err;
+ if (desc_from.type != NFT_DATA_VALUE) {
+ err = -EINVAL;
+ goto err1;
+ }
+
err = nft_data_init(NULL, &priv->data_to, sizeof(priv->data_to),
&desc_to, tb[NFTA_RANGE_TO_DATA]);
if (err < 0)
goto err1;
+ if (desc_to.type != NFT_DATA_VALUE) {
+ err = -EINVAL;
+ goto err2;
+ }
+
if (desc_from.len != desc_to.len) {
err = -EINVAL;
goto err2;
diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
index b3e75f9..0221510 100644
--- a/net/netfilter/nft_set_rbtree.c
+++ b/net/netfilter/nft_set_rbtree.c
@@ -77,8 +77,13 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
parent = rcu_dereference_raw(parent->rb_left);
continue;
}
- if (nft_rbtree_interval_end(rbe))
- goto out;
+ if (nft_rbtree_interval_end(rbe)) {
+ if (nft_set_is_anonymous(set))
+ return false;
+ parent = rcu_dereference_raw(parent->rb_left);
+ interval = NULL;
+ continue;
+ }
*ext = &rbe->ext;
return true;
@@ -91,7 +96,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
*ext = &interval->ext;
return true;
}
-out:
+
return false;
}
@@ -139,8 +144,10 @@ static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set,
} else if (d > 0) {
parent = rcu_dereference_raw(parent->rb_right);
} else {
- if (!nft_set_elem_active(&rbe->ext, genmask))
+ if (!nft_set_elem_active(&rbe->ext, genmask)) {
parent = rcu_dereference_raw(parent->rb_left);
+ continue;
+ }
if (!nft_set_ext_exists(&rbe->ext, NFT_SET_EXT_FLAGS) ||
(*nft_set_ext_flags(&rbe->ext) & NFT_SET_ELEM_INTERVAL_END) ==
@@ -148,7 +155,11 @@ static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set,
*elem = rbe;
return true;
}
- return false;
+
+ if (nft_rbtree_interval_end(rbe))
+ interval = NULL;
+
+ parent = rcu_dereference_raw(parent->rb_left);
}
}
diff --git a/net/netfilter/nft_tproxy.c b/net/netfilter/nft_tproxy.c
index f92a82c..9598015 100644
--- a/net/netfilter/nft_tproxy.c
+++ b/net/netfilter/nft_tproxy.c
@@ -50,7 +50,7 @@ static void nft_tproxy_eval_v4(const struct nft_expr *expr,
taddr = nf_tproxy_laddr4(skb, taddr, iph->daddr);
if (priv->sreg_port)
- tport = regs->data[priv->sreg_port];
+ tport = nft_reg_load16(®s->data[priv->sreg_port]);
if (!tport)
tport = hp->dest;
@@ -117,7 +117,7 @@ static void nft_tproxy_eval_v6(const struct nft_expr *expr,
taddr = *nf_tproxy_laddr6(skb, &taddr, &iph->daddr);
if (priv->sreg_port)
- tport = regs->data[priv->sreg_port];
+ tport = nft_reg_load16(®s->data[priv->sreg_port]);
if (!tport)
tport = hp->dest;
diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c
index a66f102..040576d 100644
--- a/net/nfc/nci/uart.c
+++ b/net/nfc/nci/uart.c
@@ -348,7 +348,7 @@ static int nci_uart_default_recv_buf(struct nci_uart *nu, const u8 *data,
nu->rx_packet_len = -1;
nu->rx_skb = nci_skb_alloc(nu->ndev,
NCI_MAX_PACKET_SIZE,
- GFP_KERNEL);
+ GFP_ATOMIC);
if (!nu->rx_skb)
return -ENOMEM;
}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 7e25a6a..fa6cc71 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -552,7 +552,8 @@ static int prb_calc_retire_blk_tmo(struct packet_sock *po,
msec = 1;
div = ecmd.base.speed / 1000;
}
- }
+ } else
+ return DEFAULT_PRB_RETIRE_TOV;
mbits = (blk_size_in_bytes * 8) / (1024 * 1024);
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index f0a061c..88841a3 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -1009,10 +1009,13 @@ static void rfkill_sync_work(struct work_struct *work)
int __must_check rfkill_register(struct rfkill *rfkill)
{
static unsigned long rfkill_no;
- struct device *dev = &rfkill->dev;
+ struct device *dev;
int error;
- BUG_ON(!rfkill);
+ if (!rfkill)
+ return -EINVAL;
+
+ dev = &rfkill->dev;
mutex_lock(&rfkill_global_mutex);
@@ -1323,10 +1326,12 @@ static const struct file_operations rfkill_fops = {
.llseek = no_llseek,
};
+#define RFKILL_NAME "rfkill"
+
static struct miscdevice rfkill_miscdev = {
- .name = "rfkill",
.fops = &rfkill_fops,
- .minor = MISC_DYNAMIC_MINOR,
+ .name = RFKILL_NAME,
+ .minor = RFKILL_MINOR,
};
static int __init rfkill_init(void)
@@ -1378,3 +1383,6 @@ static void __exit rfkill_exit(void)
class_unregister(&rfkill_class);
}
module_exit(rfkill_exit);
+
+MODULE_ALIAS_MISCDEV(RFKILL_MINOR);
+MODULE_ALIAS("devname:" RFKILL_NAME);
diff --git a/net/rxrpc/peer_event.c b/net/rxrpc/peer_event.c
index dc7fdaf..42582a9 100644
--- a/net/rxrpc/peer_event.c
+++ b/net/rxrpc/peer_event.c
@@ -153,6 +153,9 @@ void rxrpc_error_report(struct sock *sk)
struct rxrpc_peer *peer;
struct sk_buff *skb;
+ if (unlikely(!local))
+ return;
+
_enter("%p{%d}", sk, local->debug_id);
skb = sock_dequeue_err_skb(sk);
diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
index e4cf72b0..824e3c3 100644
--- a/net/sched/sch_cake.c
+++ b/net/sched/sch_cake.c
@@ -1758,7 +1758,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
q->avg_window_begin));
u64 b = q->avg_window_bytes * (u64)NSEC_PER_SEC;
- do_div(b, window_interval);
+ b = div64_u64(b, window_interval);
q->avg_peak_bandwidth =
cake_ewma(q->avg_peak_bandwidth, b,
b > q->avg_peak_bandwidth ? 2 : 8);
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index 4808713..1ee2b77 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -735,10 +735,12 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt,
if (tb[TCA_FQ_QUANTUM]) {
u32 quantum = nla_get_u32(tb[TCA_FQ_QUANTUM]);
- if (quantum > 0)
+ if (quantum > 0 && quantum <= (1 << 20)) {
q->quantum = quantum;
- else
+ } else {
+ NL_SET_ERR_MSG_MOD(extack, "invalid quantum");
err = -EINVAL;
+ }
}
if (tb[TCA_FQ_INITIAL_QUANTUM])
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 5672abe..1cbbd8c 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -314,8 +314,14 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
bool any_qdisc_is_offloaded;
int err;
- if (new == NULL)
- new = &noop_qdisc;
+ if (!new) {
+ new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
+ TC_H_MAKE(sch->handle, arg), extack);
+ if (!new)
+ new = &noop_qdisc;
+ else
+ qdisc_hash_add(new, true);
+ }
*old = qdisc_replace(sch, new, &q->queues[band]);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 6d36f74..269b528 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -242,6 +242,7 @@ static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
sa->sin_port = sh->dest;
sa->sin_addr.s_addr = ip_hdr(skb)->daddr;
}
+ memset(sa->sin_zero, 0, sizeof(sa->sin_zero));
}
/* Initialize an sctp_addr from a socket. */
@@ -250,6 +251,7 @@ static void sctp_v4_from_sk(union sctp_addr *addr, struct sock *sk)
addr->v4.sin_family = AF_INET;
addr->v4.sin_port = 0;
addr->v4.sin_addr.s_addr = inet_sk(sk)->inet_rcv_saddr;
+ memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));
}
/* Initialize sk->sk_rcv_saddr from sctp_addr. */
@@ -272,6 +274,7 @@ static void sctp_v4_from_addr_param(union sctp_addr *addr,
addr->v4.sin_family = AF_INET;
addr->v4.sin_port = port;
addr->v4.sin_addr.s_addr = param->v4.addr.s_addr;
+ memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));
}
/* Initialize an address parameter from a sctp_addr and return the length
@@ -296,6 +299,7 @@ static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct flowi4 *fl4,
saddr->v4.sin_family = AF_INET;
saddr->v4.sin_port = port;
saddr->v4.sin_addr.s_addr = fl4->saddr;
+ memset(saddr->v4.sin_zero, 0, sizeof(saddr->v4.sin_zero));
}
/* Compare two addresses exactly. */
@@ -318,6 +322,7 @@ static void sctp_v4_inaddr_any(union sctp_addr *addr, __be16 port)
addr->v4.sin_family = AF_INET;
addr->v4.sin_addr.s_addr = htonl(INADDR_ANY);
addr->v4.sin_port = port;
+ memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));
}
/* Is this a wildcard address? */
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index de8a82b..0234a64 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1373,8 +1373,10 @@ static int sctp_cmd_interpreter(enum sctp_event event_type,
/* Generate an INIT ACK chunk. */
new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC,
0);
- if (!new_obj)
- goto nomem;
+ if (!new_obj) {
+ error = -ENOMEM;
+ break;
+ }
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(new_obj));
@@ -1396,7 +1398,8 @@ static int sctp_cmd_interpreter(enum sctp_event event_type,
if (!new_obj) {
if (cmd->obj.chunk)
sctp_chunk_free(cmd->obj.chunk);
- goto nomem;
+ error = -ENOMEM;
+ break;
}
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(new_obj));
@@ -1443,8 +1446,10 @@ static int sctp_cmd_interpreter(enum sctp_event event_type,
/* Generate a SHUTDOWN chunk. */
new_obj = sctp_make_shutdown(asoc, chunk);
- if (!new_obj)
- goto nomem;
+ if (!new_obj) {
+ error = -ENOMEM;
+ break;
+ }
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(new_obj));
break;
@@ -1780,11 +1785,17 @@ static int sctp_cmd_interpreter(enum sctp_event event_type,
break;
}
- if (error)
+ if (error) {
+ cmd = sctp_next_cmd(commands);
+ while (cmd) {
+ if (cmd->verb == SCTP_CMD_REPLY)
+ sctp_chunk_free(cmd->obj.chunk);
+ cmd = sctp_next_cmd(commands);
+ }
break;
+ }
}
-out:
/* If this is in response to a received chunk, wait until
* we are done with the packet to open the queue so that we don't
* send multiple packets in response to a single request.
@@ -1799,7 +1810,4 @@ static int sctp_cmd_interpreter(enum sctp_event event_type,
sp->data_ready_signalled = 0;
return error;
-nomem:
- error = -ENOMEM;
- goto out;
}
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index ad158d3..c0d55ed 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -278,7 +278,7 @@ bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
pf->af->from_sk(&addr, sk);
pf->to_sk_daddr(&t->ipaddr, sk);
- dst->ops->update_pmtu(dst, sk, NULL, pmtu);
+ dst->ops->update_pmtu(dst, sk, NULL, pmtu, true);
pf->to_sk_daddr(&addr, sk);
dst = sctp_transport_dst_check(t);
diff --git a/net/socket.c b/net/socket.c
index 7a0ddf8..4a4c11d 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -877,7 +877,7 @@ static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to)
.msg_iocb = iocb};
ssize_t res;
- if (file->f_flags & O_NONBLOCK)
+ if (file->f_flags & O_NONBLOCK || (iocb->ki_flags & IOCB_NOWAIT))
msg.msg_flags = MSG_DONTWAIT;
if (iocb->ki_pos != 0)
@@ -902,7 +902,7 @@ static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (iocb->ki_pos != 0)
return -ESPIPE;
- if (file->f_flags & O_NONBLOCK)
+ if (file->f_flags & O_NONBLOCK || (iocb->ki_flags & IOCB_NOWAIT))
msg.msg_flags = MSG_DONTWAIT;
if (sock->type == SOCK_SEQPACKET)
diff --git a/samples/bpf/syscall_tp_kern.c b/samples/bpf/syscall_tp_kern.c
index 9149c52..8833aac 100644
--- a/samples/bpf/syscall_tp_kern.c
+++ b/samples/bpf/syscall_tp_kern.c
@@ -50,13 +50,27 @@ static __always_inline void count(void *map)
SEC("tracepoint/syscalls/sys_enter_open")
int trace_enter_open(struct syscalls_enter_open_args *ctx)
{
- count((void *)&enter_open_map);
+ count(&enter_open_map);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_enter_openat")
+int trace_enter_open_at(struct syscalls_enter_open_args *ctx)
+{
+ count(&enter_open_map);
return 0;
}
SEC("tracepoint/syscalls/sys_exit_open")
int trace_enter_exit(struct syscalls_exit_open_args *ctx)
{
- count((void *)&exit_open_map);
+ count(&exit_open_map);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_openat")
+int trace_enter_exit_at(struct syscalls_exit_open_args *ctx)
+{
+ count(&exit_open_map);
return 0;
}
diff --git a/samples/bpf/trace_event_user.c b/samples/bpf/trace_event_user.c
index d08046ab8..d330224 100644
--- a/samples/bpf/trace_event_user.c
+++ b/samples/bpf/trace_event_user.c
@@ -35,9 +35,9 @@ static void print_ksym(__u64 addr)
return;
sym = ksym_search(addr);
printf("%s;", sym->name);
- if (!strcmp(sym->name, "sys_read"))
+ if (!strstr(sym->name, "sys_read"))
sys_read_seen = true;
- else if (!strcmp(sym->name, "sys_write"))
+ else if (!strstr(sym->name, "sys_write"))
sys_write_seen = true;
}
diff --git a/samples/pktgen/functions.sh b/samples/pktgen/functions.sh
index f8bb3cd..7d92857 100644
--- a/samples/pktgen/functions.sh
+++ b/samples/pktgen/functions.sh
@@ -5,6 +5,8 @@
# Author: Jesper Dangaaard Brouer
# License: GPL
+set -o errexit
+
## -- General shell logging cmds --
function err() {
local exitcode=$1
@@ -58,6 +60,7 @@
function proc_cmd() {
local result
local proc_file=$1
+ local status=0
# after shift, the remaining args are contained in $@
shift
local proc_ctrl=${PROC_DIR}/$proc_file
@@ -73,13 +76,13 @@
echo "cmd: $@ > $proc_ctrl"
fi
# Quoting of "$@" is important for space expansion
- echo "$@" > "$proc_ctrl"
- local status=$?
+ echo "$@" > "$proc_ctrl" || status=$?
- result=$(grep "Result: OK:" $proc_ctrl)
- # Due to pgctrl, cannot use exit code $? from grep
- if [[ "$result" == "" ]]; then
- grep "Result:" $proc_ctrl >&2
+ if [[ "$proc_file" != "pgctrl" ]]; then
+ result=$(grep "Result: OK:" $proc_ctrl) || true
+ if [[ "$result" == "" ]]; then
+ grep "Result:" $proc_ctrl >&2
+ fi
fi
if (( $status != 0 )); then
err 5 "Write error($status) occurred cmd: \"$@ > $proc_ctrl\""
@@ -105,6 +108,8 @@
fi
}
+[[ $EUID -eq 0 ]] && trap 'pg_ctrl "reset"' EXIT
+
## -- General shell tricks --
function root_check_run_with_sudo() {
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 31ed7f3..4b2711c 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -491,6 +491,8 @@ static void build_initial_tok_table(void)
table[pos] = table[i];
learn_symbol(table[pos].sym, table[pos].len);
pos++;
+ } else {
+ free(table[i].sym);
}
}
table_cnt = pos;
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index e1a39e9..7e38070 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -252,6 +252,13 @@ static int expr_eq(struct expr *e1, struct expr *e2)
{
int res, old_count;
+ /*
+ * A NULL expr is taken to be yes, but there's also a different way to
+ * represent yes. expr_is_yes() checks for either representation.
+ */
+ if (!e1 || !e2)
+ return expr_is_yes(e1) && expr_is_yes(e2);
+
if (e1->type != e2->type)
return 0;
switch (e1->type) {
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index d95a7e4..0a57d10 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -593,7 +593,7 @@ static __poll_t ns_revision_poll(struct file *file, poll_table *pt)
void __aa_bump_ns_revision(struct aa_ns *ns)
{
- ns->revision++;
+ WRITE_ONCE(ns->revision, ns->revision + 1);
wake_up_interruptible(&ns->wait);
}
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 11975ec..bdf9e4c 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -321,6 +321,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
if (!bprm || !profile->xattr_count)
return 0;
+ might_sleep();
/* transition from exec match to xattr set */
state = aa_dfa_null_transition(profile->xmatch, state);
@@ -365,10 +366,11 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
}
/**
- * __attach_match_ - find an attachment match
+ * find_attach - do attachment search for unconfined processes
* @bprm - binprm structure of transitioning task
- * @name - to match against (NOT NULL)
+ * @ns: the current namespace (NOT NULL)
* @head - profile list to walk (NOT NULL)
+ * @name - to match against (NOT NULL)
* @info - info message if there was an error (NOT NULL)
*
* Do a linear search on the profiles in the list. There is a matching
@@ -378,12 +380,11 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
*
* Requires: @head not be shared or have appropriate locks held
*
- * Returns: profile or NULL if no match found
+ * Returns: label or NULL if no match found
*/
-static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
- const char *name,
- struct list_head *head,
- const char **info)
+static struct aa_label *find_attach(const struct linux_binprm *bprm,
+ struct aa_ns *ns, struct list_head *head,
+ const char *name, const char **info)
{
int candidate_len = 0, candidate_xattrs = 0;
bool conflict = false;
@@ -392,6 +393,8 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
AA_BUG(!name);
AA_BUG(!head);
+ rcu_read_lock();
+restart:
list_for_each_entry_rcu(profile, head, base.list) {
if (profile->label.flags & FLAG_NULL &&
&profile->label == ns_unconfined(profile->ns))
@@ -417,16 +420,32 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
perm = dfa_user_allow(profile->xmatch, state);
/* any accepting state means a valid match. */
if (perm & MAY_EXEC) {
- int ret;
+ int ret = 0;
if (count < candidate_len)
continue;
- ret = aa_xattrs_match(bprm, profile, state);
- /* Fail matching if the xattrs don't match */
- if (ret < 0)
- continue;
+ if (bprm && profile->xattr_count) {
+ long rev = READ_ONCE(ns->revision);
+ if (!aa_get_profile_not0(profile))
+ goto restart;
+ rcu_read_unlock();
+ ret = aa_xattrs_match(bprm, profile,
+ state);
+ rcu_read_lock();
+ aa_put_profile(profile);
+ if (rev !=
+ READ_ONCE(ns->revision))
+ /* policy changed */
+ goto restart;
+ /*
+ * Fail matching if the xattrs don't
+ * match
+ */
+ if (ret < 0)
+ continue;
+ }
/*
* TODO: allow for more flexible best match
*
@@ -449,43 +468,28 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
candidate_xattrs = ret;
conflict = false;
}
- } else if (!strcmp(profile->base.name, name))
+ } else if (!strcmp(profile->base.name, name)) {
/*
* old exact non-re match, without conditionals such
* as xattrs. no more searching required
*/
- return profile;
+ candidate = profile;
+ goto out;
+ }
}
- if (conflict) {
- *info = "conflicting profile attachments";
+ if (!candidate || conflict) {
+ if (conflict)
+ *info = "conflicting profile attachments";
+ rcu_read_unlock();
return NULL;
}
- return candidate;
-}
-
-/**
- * find_attach - do attachment search for unconfined processes
- * @bprm - binprm structure of transitioning task
- * @ns: the current namespace (NOT NULL)
- * @list: list to search (NOT NULL)
- * @name: the executable name to match against (NOT NULL)
- * @info: info message if there was an error
- *
- * Returns: label or NULL if no match found
- */
-static struct aa_label *find_attach(const struct linux_binprm *bprm,
- struct aa_ns *ns, struct list_head *list,
- const char *name, const char **info)
-{
- struct aa_profile *profile;
-
- rcu_read_lock();
- profile = aa_get_profile(__attach_match(bprm, name, list, info));
+out:
+ candidate = aa_get_newest_profile(candidate);
rcu_read_unlock();
- return profile ? &profile->label : NULL;
+ return &candidate->label;
}
static const char *next_name(int xtype, const char *name)
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index ba11bdf..2469549 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -1462,11 +1462,13 @@ static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label,
/* helper macro for snprint routines */
#define update_for_len(total, len, size, str) \
do { \
+ size_t ulen = len; \
+ \
AA_BUG(len < 0); \
- total += len; \
- len = min(len, size); \
- size -= len; \
- str += len; \
+ total += ulen; \
+ ulen = min(ulen, size); \
+ size -= ulen; \
+ str += ulen; \
} while (0)
/**
@@ -1601,7 +1603,7 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns,
struct aa_ns *prev_ns = NULL;
struct label_it i;
int count = 0, total = 0;
- size_t len;
+ ssize_t len;
AA_BUG(!str && size != 0);
AA_BUG(!label);
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 1590e2d..3a4293c 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -1126,8 +1126,8 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_label *subj,
if (!name) {
/* remove namespace - can only happen if fqname[0] == ':' */
mutex_lock_nested(&ns->parent->lock, ns->level);
- __aa_remove_ns(ns);
__aa_bump_ns_revision(ns);
+ __aa_remove_ns(ns);
mutex_unlock(&ns->parent->lock);
} else {
/* remove profile */
@@ -1139,9 +1139,9 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_label *subj,
goto fail_ns_lock;
}
name = profile->base.hname;
+ __aa_bump_ns_revision(ns);
__remove_profile(profile);
__aa_labelset_update_subtree(ns);
- __aa_bump_ns_revision(ns);
mutex_unlock(&ns->lock);
}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a0112b9..43504e6 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -754,6 +754,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
LONG_MAX - runtime->buffer_size)
runtime->boundary *= 2;
+ /* clear the buffer for avoiding possible kernel info leaks */
+ if (runtime->dma_area && !substream->ops->copy_user)
+ memset(runtime->dma_area, 0, runtime->dma_bytes);
+
snd_pcm_timer_resolution_change(substream);
snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 61fefa7..5a9e570 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -88,6 +88,9 @@ static LIST_HEAD(snd_timer_slave_list);
/* lock for slave active lists */
static DEFINE_SPINLOCK(slave_active_lock);
+#define MAX_SLAVE_INSTANCES 1000
+static int num_slaves;
+
static DEFINE_MUTEX(register_mutex);
static int snd_timer_free(struct snd_timer *timer);
@@ -266,6 +269,10 @@ int snd_timer_open(struct snd_timer_instance **ti,
err = -EINVAL;
goto unlock;
}
+ if (num_slaves >= MAX_SLAVE_INSTANCES) {
+ err = -EBUSY;
+ goto unlock;
+ }
timeri = snd_timer_instance_new(owner, NULL);
if (!timeri) {
err = -ENOMEM;
@@ -275,6 +282,7 @@ int snd_timer_open(struct snd_timer_instance **ti,
timeri->slave_id = tid->device;
timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
list_add_tail(&timeri->open_list, &snd_timer_slave_list);
+ num_slaves++;
err = snd_timer_check_slave(timeri);
if (err < 0) {
snd_timer_close_locked(timeri, &card_dev_to_put);
@@ -364,6 +372,8 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri,
struct snd_timer_instance *slave, *tmp;
list_del(&timeri->open_list);
+ if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
+ num_slaves--;
/* force to stop the timer */
snd_timer_stop(timeri);
diff --git a/sound/firewire/motu/motu-proc.c b/sound/firewire/motu/motu-proc.c
index ab6830a..015b4ec 100644
--- a/sound/firewire/motu/motu-proc.c
+++ b/sound/firewire/motu/motu-proc.c
@@ -17,7 +17,7 @@ static const char *const clock_names[] = {
[SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT] = "S/PDIF on optical interface",
[SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A] = "S/PDIF on optical interface A",
[SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B] = "S/PDIF on optical interface B",
- [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PCIF on coaxial interface",
+ [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PDIF on coaxial interface",
[SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR] = "AESEBU on XLR interface",
[SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC] = "Word clock on BNC interface",
};
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 70559e5..7d4e18c 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -293,7 +293,8 @@ static int snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev)
} else {
mpu_port[dev] = pnp_port_start(pdev, 0);
if (mpu_irq[dev] >= 0 &&
- pnp_irq_valid(pdev, 0) && pnp_irq(pdev, 0) >= 0) {
+ pnp_irq_valid(pdev, 0) &&
+ pnp_irq(pdev, 0) != (resource_size_t)-1) {
mpu_irq[dev] = pnp_irq(pdev, 0);
} else {
mpu_irq[dev] = -1; /* disable interrupt */
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 8fcb421..fa261b2 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -883,7 +883,7 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr,
return -EAGAIN; /* give a chance to retry */
}
- dev_WARN(chip->card->dev,
+ dev_err(chip->card->dev,
"azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n",
bus->last_cmd[addr]);
chip->single_cmd = 1;
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 6a9b89e..bc4edc5 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -1683,13 +1683,14 @@ struct scp_msg {
static void dspio_clear_response_queue(struct hda_codec *codec)
{
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
unsigned int dummy = 0;
- int status = -1;
+ int status;
/* clear all from the response queue */
do {
status = dspio_read(codec, &dummy);
- } while (status == 0);
+ } while (status == 0 && time_before(jiffies, timeout));
}
static int dspio_get_response_data(struct hda_codec *codec)
@@ -6754,12 +6755,14 @@ static void ca0132_process_dsp_response(struct hda_codec *codec,
struct ca0132_spec *spec = codec->spec;
codec_dbg(codec, "ca0132_process_dsp_response\n");
+ snd_hda_power_up_pm(codec);
if (spec->wait_scp) {
if (dspio_get_response_data(codec) >= 0)
spec->wait_scp = 0;
}
dspio_clear_response_queue(codec);
+ snd_hda_power_down_pm(codec);
}
static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
@@ -6770,11 +6773,10 @@ static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
/* Delay enabling the HP amp, to let the mic-detection
* state machine run.
*/
- cancel_delayed_work(&spec->unsol_hp_work);
- schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
tbl = snd_hda_jack_tbl_get(codec, cb->nid);
if (tbl)
tbl->block_report = 1;
+ schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
}
static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
@@ -7408,12 +7410,25 @@ static void ca0132_reboot_notify(struct hda_codec *codec)
codec->patch_ops.free(codec);
}
+#ifdef CONFIG_PM
+static int ca0132_suspend(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ cancel_delayed_work_sync(&spec->unsol_hp_work);
+ return 0;
+}
+#endif
+
static const struct hda_codec_ops ca0132_patch_ops = {
.build_controls = ca0132_build_controls,
.build_pcms = ca0132_build_pcms,
.init = ca0132_init,
.free = ca0132_free,
.unsol_event = snd_hda_jack_unsol_event,
+#ifdef CONFIG_PM
+ .suspend = ca0132_suspend,
+#endif
.reboot_notify = ca0132_reboot_notify,
};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 019dee9..1f6a036 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -513,6 +513,7 @@ static void alc_shutup_pins(struct hda_codec *codec)
struct alc_spec *spec = codec->spec;
switch (codec->core.vendor_id) {
+ case 0x10ec0283:
case 0x10ec0286:
case 0x10ec0288:
case 0x10ec0298:
@@ -5441,6 +5442,16 @@ static void alc295_fixup_disable_dac3(struct hda_codec *codec,
}
}
+/* force NID 0x17 (Bass Speaker) to DAC1 to share it with the main speaker */
+static void alc285_fixup_speaker2_to_dac1(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ hda_nid_t conn[1] = { 0x02 };
+ snd_hda_override_conn_list(codec, 0x17, 1, conn);
+ }
+}
+
/* Hook to update amp GPIO4 for automute */
static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,
struct hda_jack_callback *jack)
@@ -5661,6 +5672,7 @@ enum {
ALC225_FIXUP_DISABLE_MIC_VREF,
ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC295_FIXUP_DISABLE_DAC3,
+ ALC285_FIXUP_SPEAKER2_TO_DAC1,
ALC280_FIXUP_HP_HEADSET_MIC,
ALC221_FIXUP_HP_FRONT_MIC,
ALC292_FIXUP_TPT460,
@@ -5702,9 +5714,12 @@ enum {
ALC256_FIXUP_ASUS_HEADSET_MIC,
ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
ALC299_FIXUP_PREDATOR_SPK,
- ALC294_FIXUP_ASUS_INTSPK_HEADSET_MIC,
ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE,
- ALC294_FIXUP_ASUS_INTSPK_GPIO,
+ ALC289_FIXUP_DELL_SPK2,
+ ALC289_FIXUP_DUAL_SPK,
+ ALC294_FIXUP_SPK2_TO_DAC1,
+ ALC294_FIXUP_ASUS_DUAL_SPK,
+
};
static const struct hda_fixup alc269_fixups[] = {
@@ -6441,6 +6456,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc295_fixup_disable_dac3,
},
+ [ALC285_FIXUP_SPEAKER2_TO_DAC1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
+ },
[ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -6748,16 +6767,6 @@ static const struct hda_fixup alc269_fixups[] = {
{ }
}
},
- [ALC294_FIXUP_ASUS_INTSPK_HEADSET_MIC] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x411111f0 }, /* disable confusing internal speaker */
- { 0x19, 0x04a11150 }, /* use as headset mic, without its own jack detect */
- { }
- },
- .chained = true,
- .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
- },
[ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -6768,13 +6777,35 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
},
- [ALC294_FIXUP_ASUS_INTSPK_GPIO] = {
+ [ALC289_FIXUP_DELL_SPK2] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x17, 0x90170130 }, /* bass spk */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE
+ },
+ [ALC289_FIXUP_DUAL_SPK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
+ .chained = true,
+ .chain_id = ALC289_FIXUP_DELL_SPK2
+ },
+ [ALC294_FIXUP_SPK2_TO_DAC1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
+ .chained = true,
+ .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
+ },
+ [ALC294_FIXUP_ASUS_DUAL_SPK] = {
.type = HDA_FIXUP_FUNC,
/* The GPIO must be pulled to initialize the AMP */
.v.func = alc_fixup_gpio4,
.chained = true,
- .chain_id = ALC294_FIXUP_ASUS_INTSPK_HEADSET_MIC
+ .chain_id = ALC294_FIXUP_SPK2_TO_DAC1
},
+
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -6847,6 +6878,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
+ SND_PCI_QUIRK(0x1028, 0x097e, "Dell Precision", ALC289_FIXUP_DUAL_SPK),
+ SND_PCI_QUIRK(0x1028, 0x097d, "Dell Precision", ALC289_FIXUP_DUAL_SPK),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -6934,7 +6967,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
- SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_INTSPK_GPIO),
+ SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC),
@@ -7006,6 +7039,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x2293, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_SPEAKER2_TO_DAC1),
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
@@ -7189,6 +7223,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC255_FIXUP_DELL_SPK_NOISE, .name = "dell-spk-noise"},
{.id = ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc225-dell1"},
{.id = ALC295_FIXUP_DISABLE_DAC3, .name = "alc295-disable-dac3"},
+ {.id = ALC285_FIXUP_SPEAKER2_TO_DAC1, .name = "alc285-speaker2-to-dac1"},
{.id = ALC280_FIXUP_HP_HEADSET_MIC, .name = "alc280-hp-headset"},
{.id = ALC221_FIXUP_HP_FRONT_MIC, .name = "alc221-hp-mic"},
{.id = ALC298_FIXUP_SPK_VOLUME, .name = "alc298-spk-volume"},
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 057c2f3..41ea8e7 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -661,6 +661,7 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
unsigned long flags;
unsigned char mclk_change;
unsigned int i, old_rate;
+ bool call_set_rate = false;
if (rate > ice->hw_rates->list[ice->hw_rates->count - 1])
return -EINVAL;
@@ -684,7 +685,7 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
* setting clock rate for internal clock mode */
old_rate = ice->get_rate(ice);
if (force || (old_rate != rate))
- ice->set_rate(ice, rate);
+ call_set_rate = true;
else if (rate == ice->cur_rate) {
spin_unlock_irqrestore(&ice->reg_lock, flags);
return 0;
@@ -692,12 +693,14 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
}
ice->cur_rate = rate;
+ spin_unlock_irqrestore(&ice->reg_lock, flags);
+
+ if (call_set_rate)
+ ice->set_rate(ice, rate);
/* setting master clock */
mclk_change = ice->set_mclk(ice, rate);
- spin_unlock_irqrestore(&ice->reg_lock, flags);
-
if (mclk_change && ice->gpio.i2s_mclk_changed)
ice->gpio.i2s_mclk_changed(ice);
if (ice->gpio.set_pro_rate)
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index c3b28b2..89b6e18 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2121,10 +2121,8 @@ static void max98090_pll_det_disable_work(struct work_struct *work)
M98090_IULK_MASK, 0);
}
-static void max98090_pll_work(struct work_struct *work)
+static void max98090_pll_work(struct max98090_priv *max98090)
{
- struct max98090_priv *max98090 =
- container_of(work, struct max98090_priv, pll_work);
struct snd_soc_component *component = max98090->component;
if (!snd_soc_component_is_active(component))
@@ -2277,7 +2275,7 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
if (active & M98090_ULK_MASK) {
dev_dbg(component->dev, "M98090_ULK_MASK\n");
- schedule_work(&max98090->pll_work);
+ max98090_pll_work(max98090);
}
if (active & M98090_JDET_MASK) {
@@ -2440,7 +2438,6 @@ static int max98090_probe(struct snd_soc_component *component)
max98090_pll_det_enable_work);
INIT_WORK(&max98090->pll_det_disable_work,
max98090_pll_det_disable_work);
- INIT_WORK(&max98090->pll_work, max98090_pll_work);
/* Enable jack detection */
snd_soc_component_write(component, M98090_REG_JACK_DETECT,
@@ -2493,7 +2490,6 @@ static void max98090_remove(struct snd_soc_component *component)
cancel_delayed_work_sync(&max98090->jack_work);
cancel_delayed_work_sync(&max98090->pll_det_enable_work);
cancel_work_sync(&max98090->pll_det_disable_work);
- cancel_work_sync(&max98090->pll_work);
max98090->component = NULL;
}
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index b1572a2..388d2f7 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -1533,7 +1533,6 @@ struct max98090_priv {
struct delayed_work jack_work;
struct delayed_work pll_det_enable_work;
struct work_struct pll_det_disable_work;
- struct work_struct pll_work;
struct snd_soc_jack *jack;
unsigned int dai_fmt;
int tdm_slots;
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 9b7a183..71b7b88 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -297,6 +297,7 @@ static bool rt5677_volatile_register(struct device *dev, unsigned int reg)
case RT5677_I2C_MASTER_CTRL7:
case RT5677_I2C_MASTER_CTRL8:
case RT5677_HAP_GENE_CTRL2:
+ case RT5677_PWR_ANLG2: /* Modified by DSP firmware */
case RT5677_PWR_DSP_ST:
case RT5677_PRIV_DATA:
case RT5677_ASRC_22:
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index deff6516..0a3b746 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -2413,6 +2413,8 @@ static int wm2200_i2c_probe(struct i2c_client *i2c,
err_pm_runtime:
pm_runtime_disable(&i2c->dev);
+ if (i2c->irq)
+ free_irq(i2c->irq, wm2200);
err_reset:
if (wm2200->pdata.reset)
gpio_set_value_cansleep(wm2200->pdata.reset, 0);
@@ -2429,12 +2431,15 @@ static int wm2200_i2c_remove(struct i2c_client *i2c)
{
struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c);
+ pm_runtime_disable(&i2c->dev);
if (i2c->irq)
free_irq(i2c->irq, wm2200);
if (wm2200->pdata.reset)
gpio_set_value_cansleep(wm2200->pdata.reset, 0);
if (wm2200->pdata.ldo_ena)
gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+ regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
+ wm2200->core_supplies);
return 0;
}
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index ba89d9d..b793701 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2620,6 +2620,7 @@ static int wm5100_i2c_probe(struct i2c_client *i2c,
return ret;
err_reset:
+ pm_runtime_disable(&i2c->dev);
if (i2c->irq)
free_irq(i2c->irq, wm5100);
wm5100_free_gpio(i2c);
@@ -2643,6 +2644,7 @@ static int wm5100_i2c_remove(struct i2c_client *i2c)
{
struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
+ pm_runtime_disable(&i2c->dev);
if (i2c->irq)
free_irq(i2c->irq, wm5100);
wm5100_free_gpio(i2c);
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 1965635..d14e851 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -1902,6 +1902,7 @@ static int wm8904_set_bias_level(struct snd_soc_component *component,
snd_soc_component_update_bits(component, WM8904_BIAS_CONTROL_0,
WM8904_BIAS_ENA, 0);
+ snd_soc_component_write(component, WM8904_SW_RESET_AND_ID, 0);
regcache_cache_only(wm8904->regmap, true);
regcache_mark_dirty(wm8904->regmap);
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index efd8910..dde015f 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2792,7 +2792,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
if (target % Fref == 0) {
fll_div->theta = 0;
- fll_div->lambda = 0;
+ fll_div->lambda = 1;
} else {
gcd_fll = gcd(target, fratio * Fref);
@@ -2862,7 +2862,7 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
return -EINVAL;
}
- if (fll_div.theta || fll_div.lambda)
+ if (fll_div.theta)
fll1 |= WM8962_FLL_FRAC;
/* Stop the FLL while we reconfigure */
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index b6dc524..e58240e 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -414,10 +414,12 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
},
- .driver_data = (void *)(BYT_RT5640_IN1_MAP |
- BYT_RT5640_MCLK_EN |
- BYT_RT5640_SSP0_AIF1),
-
+ .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_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
},
{
.matches = {
@@ -675,13 +677,17 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_MCLK_EN),
},
{
+ /* Teclast X89 */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
},
.driver_data = (void *)(BYT_RT5640_IN3_MAP |
- BYT_RT5640_MCLK_EN |
- BYT_RT5640_SSP0_AIF1),
+ BYT_RT5640_JD_SRC_JD1_IN4P |
+ BYT_RT5640_OVCD_TH_2000UA |
+ BYT_RT5640_OVCD_SF_1P0 |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
},
{ /* Toshiba Satellite Click Mini L9W-B */
.matches = {
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index b8a03f5..f36e33a 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -423,6 +423,9 @@ static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
dmic_constraints);
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
}
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 88a7e86..069f38f 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -1890,6 +1890,7 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
int count = hdr->count;
int i;
bool abi_match;
+ int ret;
if (tplg->pass != SOC_TPLG_PASS_PCM_DAI)
return 0;
@@ -1926,7 +1927,12 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
}
/* create the FE DAIs and DAI links */
- soc_tplg_pcm_create(tplg, _pcm);
+ ret = soc_tplg_pcm_create(tplg, _pcm);
+ if (ret < 0) {
+ if (!abi_match)
+ kfree(_pcm);
+ return ret;
+ }
/* offset by version-specific struct size and
* real priv data size
diff --git a/sound/usb/card.h b/sound/usb/card.h
index baa3887..1282799a 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -142,6 +142,7 @@ struct snd_usb_substream {
struct snd_usb_endpoint *sync_endpoint;
unsigned long flags;
bool need_setup_ep; /* (re)configure EP at prepare? */
+ bool need_setup_fmt; /* (re)configure fmt after resume? */
unsigned int speed; /* USB_SPEED_XXX */
u64 formats; /* format bitmasks (all or'ed) */
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index f594294..1e28280 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -578,15 +578,15 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
if (WARN_ON(!iface))
return -EINVAL;
alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
- altsd = get_iface_desc(alts);
- if (WARN_ON(altsd->bAlternateSetting != fmt->altsetting))
+ if (WARN_ON(!alts))
return -EINVAL;
+ altsd = get_iface_desc(alts);
- if (fmt == subs->cur_audiofmt)
+ if (fmt == subs->cur_audiofmt && !subs->need_setup_fmt)
return 0;
/* close the old interface */
- if (subs->interface >= 0 && subs->interface != fmt->iface) {
+ if (subs->interface >= 0 && (subs->interface != fmt->iface || subs->need_setup_fmt)) {
if (!subs->stream->chip->keep_iface) {
err = usb_set_interface_timeout(subs->dev,
subs->interface, 0, MAX_SETALT_TIMEOUT_MS);
@@ -601,6 +601,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
subs->altset_idx = 0;
}
+ if (subs->need_setup_fmt)
+ subs->need_setup_fmt = false;
+
/* set interface */
if (iface->cur_altsetting != alts) {
err = snd_usb_select_mode_quirk(subs, fmt);
@@ -1864,6 +1867,13 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
subs->data_endpoint->retire_data_urb = retire_playback_urb;
subs->running = 0;
return 0;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (subs->stream->chip->setup_fmt_after_resume_quirk) {
+ stop_endpoints(subs, true);
+ subs->need_setup_fmt = true;
+ return 0;
+ }
+ break;
}
return -EINVAL;
@@ -1896,6 +1906,13 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream
subs->data_endpoint->retire_data_urb = retire_capture_urb;
subs->running = 1;
return 0;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (subs->stream->chip->setup_fmt_after_resume_quirk) {
+ stop_endpoints(subs, true);
+ subs->need_setup_fmt = true;
+ return 0;
+ }
+ break;
}
return -EINVAL;
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 57c6209..65f9c4b 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3400,7 +3400,8 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
.vendor_name = "Dell",
.product_name = "WD19 Dock",
.profile_name = "Dell-WD15-Dock",
- .ifnum = QUIRK_NO_INTERFACE
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_SETUP_FMT_AFTER_RESUME
}
},
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 052b4ad..bc70212 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -519,6 +519,16 @@ static int create_standard_mixer_quirk(struct snd_usb_audio *chip,
return snd_usb_create_mixer(chip, quirk->ifnum, 0);
}
+
+static int setup_fmt_after_resume_quirk(struct snd_usb_audio *chip,
+ struct usb_interface *iface,
+ struct usb_driver *driver,
+ const struct snd_usb_audio_quirk *quirk)
+{
+ chip->setup_fmt_after_resume_quirk = 1;
+ return 1; /* Continue with creating streams and mixer */
+}
+
/*
* audio-interface quirks
*
@@ -557,6 +567,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
[QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,
[QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
+ [QUIRK_SETUP_FMT_AFTER_RESUME] = setup_fmt_after_resume_quirk,
};
if (quirk->type < QUIRK_TYPE_COUNT) {
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 8bf7ea6..a0a39a3 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -44,7 +44,7 @@ struct snd_usb_audio {
wait_queue_head_t shutdown_wait;
unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
unsigned int tx_length_quirk:1; /* Put length specifier in transfers */
-
+ unsigned int setup_fmt_after_resume_quirk:1; /* setup the format to interface after resume */
int num_interfaces;
int num_suspended_intf;
int sample_rate_read_error;
@@ -110,6 +110,7 @@ enum quirk_type {
QUIRK_AUDIO_EDIROL_UAXX,
QUIRK_AUDIO_ALIGN_TRANSFER,
QUIRK_AUDIO_STANDARD_MIXER,
+ QUIRK_SETUP_FMT_AFTER_RESUME,
QUIRK_TYPE_COUNT
};
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index a62be78..249fa8d 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1073,16 +1073,22 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd)
return -errno;
new_fd = open("/", O_RDONLY | O_CLOEXEC);
- if (new_fd < 0)
+ if (new_fd < 0) {
+ err = -errno;
goto err_free_new_name;
+ }
new_fd = dup3(fd, new_fd, O_CLOEXEC);
- if (new_fd < 0)
+ if (new_fd < 0) {
+ err = -errno;
goto err_close_new_fd;
+ }
err = zclose(map->fd);
- if (err)
+ if (err) {
+ err = -errno;
goto err_close_new_fd;
+ }
free(map->name);
map->fd = new_fd;
@@ -1101,7 +1107,7 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd)
close(new_fd);
err_free_new_name:
free(new_name);
- return -errno;
+ return err;
}
static int
diff --git a/tools/lib/subcmd/Makefile b/tools/lib/subcmd/Makefile
index 5b2cd5e..5dbb0dd 100644
--- a/tools/lib/subcmd/Makefile
+++ b/tools/lib/subcmd/Makefile
@@ -28,7 +28,9 @@
endif
endif
-ifeq ($(CC_NO_CLANG), 0)
+ifeq ($(DEBUG),1)
+ CFLAGS += -O0
+else ifeq ($(CC_NO_CLANG), 0)
CFLAGS += -O3
else
CFLAGS += -O6
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index bca0c9e..05f8a0f 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -115,6 +115,7 @@
LIB_TARGET = libtraceevent.a libtraceevent.so.$(EVENT_PARSE_VERSION)
LIB_INSTALL = libtraceevent.a libtraceevent.so*
+LIB_INSTALL := $(addprefix $(OUTPUT),$(LIB_INSTALL))
INCLUDES = -I. -I $(srctree)/tools/include $(CONFIG_INCLUDES)
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
index e76154c..2700f1f 100644
--- a/tools/lib/traceevent/parse-filter.c
+++ b/tools/lib/traceevent/parse-filter.c
@@ -1475,8 +1475,10 @@ static int copy_filter_type(struct event_filter *filter,
if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
/* Add trivial event */
arg = allocate_arg();
- if (arg == NULL)
+ if (arg == NULL) {
+ free(str);
return -1;
+ }
arg->type = FILTER_ARG_BOOLEAN;
if (strcmp(str, "TRUE") == 0)
@@ -1485,8 +1487,11 @@ static int copy_filter_type(struct event_filter *filter,
arg->boolean.value = 0;
filter_type = add_filter_type(filter, event->id);
- if (filter_type == NULL)
+ if (filter_type == NULL) {
+ free(str);
+ free_arg(arg);
return -1;
+ }
filter_type->filter = arg;
diff --git a/tools/objtool/arch/x86/lib/x86-opcode-map.txt b/tools/objtool/arch/x86/lib/x86-opcode-map.txt
index e0b8593..0a0e911 100644
--- a/tools/objtool/arch/x86/lib/x86-opcode-map.txt
+++ b/tools/objtool/arch/x86/lib/x86-opcode-map.txt
@@ -333,7 +333,7 @@
06: CLTS
07: SYSRET (o64)
08: INVD
-09: WBINVD
+09: WBINVD | WBNOINVD (F3)
0a:
0b: UD2 (1B)
0c:
@@ -364,7 +364,7 @@
# a ModR/M byte.
1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev
1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv
-1c:
+1c: Grp20 (1A),(1C)
1d:
1e:
1f: NOP Ev
@@ -792,6 +792,8 @@
f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v)
f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v)
f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v)
+f8: MOVDIR64B Gv,Mdqq (66) | ENQCMD Gv,Mdqq (F2) | ENQCMDS Gv,Mdqq (F3)
+f9: MOVDIRI My,Gy
EndTable
Table: 3-byte opcode 2 (0x0f 0x3a)
@@ -943,9 +945,9 @@
EndTable
GrpTable: Grp7
-0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
-1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B)
-2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B)
+0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) | PCONFIG (101),(11B) | ENCLV (000),(11B)
+1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) | ENCLS (111),(11B)
+2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) | ENCLU (111),(11B)
3: LIDT Ms
4: SMSW Mw/Rv
5: rdpkru (110),(11B) | wrpkru (111),(11B)
@@ -1020,7 +1022,7 @@
3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B)
4: XSAVE | ptwrite Ey (F3),(11B)
5: XRSTOR | lfence (11B)
-6: XSAVEOPT | clwb (66) | mfence (11B)
+6: XSAVEOPT | clwb (66) | mfence (11B) | TPAUSE Rd (66),(11B) | UMONITOR Rv (F3),(11B) | UMWAIT Rd (F2),(11B)
7: clflush | clflushopt (66) | sfence (11B)
EndTable
@@ -1051,6 +1053,10 @@
6: vscatterpf1qps/d Wx (66),(ev)
EndTable
+GrpTable: Grp20
+0: cldemote Mb
+EndTable
+
# AMD's Prefetch Group
GrpTable: GrpP
0: PREFETCH
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index b2188e6..2f94f7a 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -383,6 +383,13 @@ static int report__setup_sample_type(struct report *rep)
PERF_SAMPLE_BRANCH_ANY))
rep->nonany_branch_mode = true;
+#ifndef HAVE_LIBUNWIND_SUPPORT
+ if (dwarf_callchain_users) {
+ ui__warning("Please install libunwind development packages "
+ "during the perf build.\n");
+ }
+#endif
+
return 0;
}
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index a4c7849..1200973 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -428,7 +428,7 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
"selected. Hence, no address to lookup the source line number.\n");
return -EINVAL;
}
- if (PRINT_FIELD(BRSTACKINSN) &&
+ if (PRINT_FIELD(BRSTACKINSN) && !allow_user_set &&
!(perf_evlist__combined_branch_type(session->evlist) &
PERF_SAMPLE_BRANCH_ANY)) {
pr_err("Display of branch stack assembler requested, but non all-branch filter set\n"
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
index 6cd9623e..38b5888 100644
--- a/tools/perf/pmu-events/jevents.c
+++ b/tools/perf/pmu-events/jevents.c
@@ -754,6 +754,7 @@ static int process_mapfile(FILE *outfp, char *fpath)
char *line, *p;
int line_num;
char *tblname;
+ int ret = 0;
pr_info("%s: Processing mapfile %s\n", prog, fpath);
@@ -765,6 +766,7 @@ static int process_mapfile(FILE *outfp, char *fpath)
if (!mapfp) {
pr_info("%s: Error %s opening %s\n", prog, strerror(errno),
fpath);
+ free(line);
return -1;
}
@@ -791,7 +793,8 @@ static int process_mapfile(FILE *outfp, char *fpath)
/* TODO Deal with lines longer than 16K */
pr_info("%s: Mapfile %s: line %d too long, aborting\n",
prog, fpath, line_num);
- return -1;
+ ret = -1;
+ goto out;
}
line[strlen(line)-1] = '\0';
@@ -821,7 +824,9 @@ static int process_mapfile(FILE *outfp, char *fpath)
out:
print_mapping_table_suffix(outfp);
- return 0;
+ fclose(mapfp);
+ free(line);
+ return ret;
}
/*
@@ -1118,6 +1123,7 @@ int main(int argc, char *argv[])
goto empty_map;
} else if (rc < 0) {
/* Make build fail */
+ fclose(eventsfp);
free_arch_std_events();
return 1;
} else if (rc) {
@@ -1130,6 +1136,7 @@ int main(int argc, char *argv[])
goto empty_map;
} else if (rc < 0) {
/* Make build fail */
+ fclose(eventsfp);
free_arch_std_events();
return 1;
} else if (rc) {
@@ -1147,6 +1154,8 @@ int main(int argc, char *argv[])
if (process_mapfile(eventsfp, mapfile)) {
pr_info("%s: Error processing mapfile %s\n", prog, mapfile);
/* Make build fail */
+ fclose(eventsfp);
+ free_arch_std_events();
return 1;
}
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index 910e25e..6cf0065 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -48,14 +48,6 @@ asm (
"__test_function:\n"
"incq (%rdi)\n"
"ret\n");
-#elif defined (__aarch64__)
-extern void __test_function(volatile long *ptr);
-asm (
- ".globl __test_function\n"
- "__test_function:\n"
- "str x30, [x0]\n"
- "ret\n");
-
#else
static void __test_function(volatile long *ptr)
{
@@ -301,10 +293,15 @@ bool test__bp_signal_is_supported(void)
* stepping into the SIGIO handler and getting stuck on the
* breakpointed instruction.
*
+ * Since arm64 has the same issue with arm for the single-step
+ * handling, this case also gets suck on the breakpointed
+ * instruction.
+ *
* Just disable the test for these architectures until these
* issues are resolved.
*/
-#if defined(__powerpc__) || defined(__s390x__) || defined(__arm__)
+#if defined(__powerpc__) || defined(__s390x__) || defined(__arm__) || \
+ defined(__aarch64__)
return false;
#else
return true;
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index e92fa60..788b080 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -105,6 +105,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused
if (perf_evlist__mmap(evlist, 128) < 0) {
pr_debug("failed to mmap events: %d (%s)\n", errno,
str_error_r(errno, sbuf, sizeof(sbuf)));
+ err = -1;
goto out_delete_evlist;
}
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 7eb7de5..29e75c0 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -321,20 +321,50 @@ bool die_is_func_def(Dwarf_Die *dw_die)
}
/**
+ * die_entrypc - Returns entry PC (the lowest address) of a DIE
+ * @dw_die: a DIE
+ * @addr: where to store entry PC
+ *
+ * Since dwarf_entrypc() does not return entry PC if the DIE has only address
+ * range, we have to use this to retrieve the lowest address from the address
+ * range attribute.
+ */
+int die_entrypc(Dwarf_Die *dw_die, Dwarf_Addr *addr)
+{
+ Dwarf_Addr base, end;
+
+ if (!addr)
+ return -EINVAL;
+
+ if (dwarf_entrypc(dw_die, addr) == 0)
+ return 0;
+
+ return dwarf_ranges(dw_die, 0, &base, addr, &end) < 0 ? -ENOENT : 0;
+}
+
+/**
* die_is_func_instance - Ensure that this DIE is an instance of a subprogram
* @dw_die: a DIE
*
* Ensure that this DIE is an instance (which has an entry address).
- * This returns true if @dw_die is a function instance. If not, you need to
- * call die_walk_instances() to find actual instances.
+ * This returns true if @dw_die is a function instance. If not, the @dw_die
+ * must be a prototype. You can use die_walk_instances() to find actual
+ * instances.
**/
bool die_is_func_instance(Dwarf_Die *dw_die)
{
Dwarf_Addr tmp;
+ Dwarf_Attribute attr_mem;
+ int tag = dwarf_tag(dw_die);
- /* Actually gcc optimizes non-inline as like as inlined */
- return !dwarf_func_inline(dw_die) && dwarf_entrypc(dw_die, &tmp) == 0;
+ if (tag != DW_TAG_subprogram &&
+ tag != DW_TAG_inlined_subroutine)
+ return false;
+
+ return dwarf_entrypc(dw_die, &tmp) == 0 ||
+ dwarf_attr(dw_die, DW_AT_ranges, &attr_mem) != NULL;
}
+
/**
* die_get_data_member_location - Get the data-member offset
* @mb_die: a DIE of a member of a data structure
@@ -611,6 +641,9 @@ static int __die_walk_instances_cb(Dwarf_Die *inst, void *data)
Dwarf_Die *origin;
int tmp;
+ if (!die_is_func_instance(inst))
+ return DIE_FIND_CB_CONTINUE;
+
attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem);
if (attr == NULL)
return DIE_FIND_CB_CONTINUE;
@@ -682,15 +715,14 @@ static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
fname = die_get_call_file(in_die);
lineno = die_get_call_lineno(in_die);
- if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
+ if (fname && lineno > 0 && die_entrypc(in_die, &addr) == 0) {
lw->retval = lw->callback(fname, lineno, addr, lw->data);
if (lw->retval != 0)
return DIE_FIND_CB_END;
}
+ if (!lw->recursive)
+ return DIE_FIND_CB_SIBLING;
}
- if (!lw->recursive)
- /* Don't need to search recursively */
- return DIE_FIND_CB_SIBLING;
if (addr) {
fname = dwarf_decl_file(in_die);
@@ -723,7 +755,7 @@ static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
/* Handle function declaration line */
fname = dwarf_decl_file(sp_die);
if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
- dwarf_entrypc(sp_die, &addr) == 0) {
+ die_entrypc(sp_die, &addr) == 0) {
lw.retval = callback(fname, lineno, addr, data);
if (lw.retval != 0)
goto done;
@@ -737,6 +769,10 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
{
struct __line_walk_param *lw = data;
+ /*
+ * Since inlined function can include another inlined function in
+ * the same file, we need to walk in it recursively.
+ */
lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data);
if (lw->retval != 0)
return DWARF_CB_ABORT;
@@ -761,11 +797,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
Dwarf_Lines *lines;
Dwarf_Line *line;
Dwarf_Addr addr;
- const char *fname, *decf = NULL;
+ const char *fname, *decf = NULL, *inf = NULL;
int lineno, ret = 0;
int decl = 0, inl;
Dwarf_Die die_mem, *cu_die;
size_t nlines, i;
+ bool flag;
/* Get the CU die */
if (dwarf_tag(rt_die) != DW_TAG_compile_unit) {
@@ -796,6 +833,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
"Possible error in debuginfo.\n");
continue;
}
+ /* Skip end-of-sequence */
+ if (dwarf_lineendsequence(line, &flag) != 0 || flag)
+ continue;
+ /* Skip Non statement line-info */
+ if (dwarf_linebeginstatement(line, &flag) != 0 || !flag)
+ continue;
/* Filter lines based on address */
if (rt_die != cu_die) {
/*
@@ -805,13 +848,21 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
*/
if (!dwarf_haspc(rt_die, addr))
continue;
+
if (die_find_inlinefunc(rt_die, addr, &die_mem)) {
+ /* Call-site check */
+ inf = die_get_call_file(&die_mem);
+ if ((inf && !strcmp(inf, decf)) &&
+ die_get_call_lineno(&die_mem) == lineno)
+ goto found;
+
dwarf_decl_line(&die_mem, &inl);
if (inl != decl ||
decf != dwarf_decl_file(&die_mem))
continue;
}
}
+found:
/* Get source line */
fname = dwarf_linesrc(line, NULL, NULL);
@@ -826,8 +877,9 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
*/
if (rt_die != cu_die)
/*
- * Don't need walk functions recursively, because nested
- * inlined functions don't have lines of the specified DIE.
+ * Don't need walk inlined functions recursively, because
+ * inner inlined functions don't have the lines of the
+ * specified function.
*/
ret = __die_walk_funclines(rt_die, false, callback, data);
else {
@@ -1002,7 +1054,7 @@ static int die_get_var_innermost_scope(Dwarf_Die *sp_die, Dwarf_Die *vr_die,
bool first = true;
const char *name;
- ret = dwarf_entrypc(sp_die, &entry);
+ ret = die_entrypc(sp_die, &entry);
if (ret)
return ret;
@@ -1065,7 +1117,7 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf)
bool first = true;
const char *name;
- ret = dwarf_entrypc(sp_die, &entry);
+ ret = die_entrypc(sp_die, &entry);
if (ret)
return ret;
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index 8ac53bf1..ee15fac4 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -41,6 +41,9 @@ int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
/* Get DW_AT_linkage_name (should be NULL for C binary) */
const char *die_get_linkage_name(Dwarf_Die *dw_die);
+/* Get the lowest PC in DIE (including range list) */
+int die_entrypc(Dwarf_Die *dw_die, Dwarf_Addr *addr);
+
/* Ensure that this DIE is a subprogram and definition (not declaration) */
bool die_is_func_def(Dwarf_Die *dw_die);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 1a7c76d..95043ca 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1282,8 +1282,15 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
if (get_config_terms(head_config, &config_terms))
return -ENOMEM;
- if (perf_pmu__config(pmu, &attr, head_config, parse_state->error))
+ if (perf_pmu__config(pmu, &attr, head_config, parse_state->error)) {
+ struct perf_evsel_config_term *pos, *tmp;
+
+ list_for_each_entry_safe(pos, tmp, &config_terms, list) {
+ list_del_init(&pos->list);
+ free(pos);
+ }
return -EINVAL;
+ }
evsel = __add_event(list, &parse_state->idx, &attr,
get_config_name(head_config), pmu,
@@ -1843,15 +1850,20 @@ int parse_events(struct perf_evlist *evlist, const char *str,
ret = parse_events__scanner(str, &parse_state, PE_START_EVENTS);
perf_pmu__parse_cleanup();
+
+ if (!ret && list_empty(&parse_state.list)) {
+ WARN_ONCE(true, "WARNING: event parser found nothing\n");
+ return -1;
+ }
+
+ /*
+ * Add list to the evlist even with errors to allow callers to clean up.
+ */
+ perf_evlist__splice_list_tail(evlist, &parse_state.list);
+
if (!ret) {
struct perf_evsel *last;
- if (list_empty(&parse_state.list)) {
- WARN_ONCE(true, "WARNING: event parser found nothing\n");
- return -1;
- }
-
- perf_evlist__splice_list_tail(evlist, &parse_state.list);
evlist->nr_groups += parse_state.nr_groups;
last = perf_evlist__last(evlist);
last->cmdline_group_boundary = true;
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index c9319f8..f732e3a 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -34,7 +34,7 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
static inline const char *perf_reg_name(int id __maybe_unused)
{
- return NULL;
+ return "unknown";
}
static inline int perf_reg_value(u64 *valp __maybe_unused,
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c37fbef..7ccabb8 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -764,6 +764,16 @@ static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
return 0;
}
+/* Return innermost DIE */
+static int find_inner_scope_cb(Dwarf_Die *fn_die, void *data)
+{
+ struct find_scope_param *fsp = data;
+
+ memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
+ fsp->found = true;
+ return 1;
+}
+
/* Find an appropriate scope fits to given conditions */
static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
{
@@ -775,8 +785,13 @@ static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
.die_mem = die_mem,
.found = false,
};
+ int ret;
- cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp);
+ ret = cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb,
+ &fsp);
+ if (!ret && !fsp.found)
+ cu_walk_functions_at(&pf->cu_die, pf->addr,
+ find_inner_scope_cb, &fsp);
return fsp.found ? die_mem : NULL;
}
@@ -950,7 +965,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
ret = find_probe_point_lazy(in_die, pf);
else {
/* Get probe address */
- if (dwarf_entrypc(in_die, &addr) != 0) {
+ if (die_entrypc(in_die, &addr) != 0) {
pr_warning("Failed to get entry address of %s.\n",
dwarf_diename(in_die));
return -ENOENT;
@@ -1002,7 +1017,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
param->retval = find_probe_point_by_line(pf);
} else if (die_is_func_instance(sp_die)) {
/* Instances always have the entry address */
- dwarf_entrypc(sp_die, &pf->addr);
+ die_entrypc(sp_die, &pf->addr);
/* But in some case the entry address is 0 */
if (pf->addr == 0) {
pr_debug("%s has no entry PC. Skipped\n",
@@ -1414,6 +1429,18 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
return DIE_FIND_CB_END;
}
+static bool available_var_finder_overlap(struct available_var_finder *af)
+{
+ int i;
+
+ for (i = 0; i < af->nvls; i++) {
+ if (af->pf.addr == af->vls[i].point.address)
+ return true;
+ }
+ return false;
+
+}
+
/* Add a found vars into available variables list */
static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
{
@@ -1424,6 +1451,14 @@ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
Dwarf_Die die_mem;
int ret;
+ /*
+ * For some reason (e.g. different column assigned to same address),
+ * this callback can be called with the address which already passed.
+ * Ignore it first.
+ */
+ if (available_var_finder_overlap(af))
+ return 0;
+
/* Check number of tevs */
if (af->nvls == af->max_vls) {
pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
@@ -1567,7 +1602,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
/* Get function entry information */
func = basefunc = dwarf_diename(&spdie);
if (!func ||
- dwarf_entrypc(&spdie, &baseaddr) != 0 ||
+ die_entrypc(&spdie, &baseaddr) != 0 ||
dwarf_decl_line(&spdie, &baseline) != 0) {
lineno = 0;
goto post;
@@ -1584,7 +1619,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr,
&indie)) {
/* There is an inline function */
- if (dwarf_entrypc(&indie, &_addr) == 0 &&
+ if (die_entrypc(&indie, &_addr) == 0 &&
_addr == addr) {
/*
* addr is at an inline function entry.
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 9005fbe..23092fd 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -109,7 +109,6 @@ static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
return ret;
}
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
- va_end(ap_saved);
if (len > strbuf_avail(sb)) {
pr_debug("this should not happen, your vsnprintf is broken");
va_end(ap_saved);
diff --git a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
index f794d6b..3e4ff4a 100644
--- a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
@@ -40,7 +40,6 @@ static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = {
{
.name = "PC9",
.desc = N_("Processor Package C9"),
- .desc = N_("Processor Package C2"),
.id = PC9,
.range = RANGE_PACKAGE,
.get_count_percent = hsw_ext_get_count_percent,
diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c
index cf16948..6af24f9 100644
--- a/tools/testing/selftests/bpf/cgroup_helpers.c
+++ b/tools/testing/selftests/bpf/cgroup_helpers.c
@@ -44,7 +44,7 @@
*/
int setup_cgroup_environment(void)
{
- char cgroup_workdir[PATH_MAX + 1];
+ char cgroup_workdir[PATH_MAX - 24];
format_cgroup_path(cgroup_workdir, "");
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc
index ce361b9..da298f1 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc
@@ -25,9 +25,9 @@
test $N -eq 256 && break
done
-L=`wc -l kprobe_events`
-if [ $L -ne $N ]; then
- echo "The number of kprobes events ($L) is not $N"
+L=`cat kprobe_events | wc -l`
+if [ $L -ne 256 ]; then
+ echo "The number of kprobes events ($L) is not 256"
exit_fail
fi
diff --git a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh
index fef88eb..fa6a88c 100755
--- a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh
+++ b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh
@@ -36,7 +36,7 @@
{
ip -6 route del 2001:db8:1::/64 vrf v$h2
ip -4 route del 192.0.2.0/28 vrf v$h2
- simple_if_fini $h2 192.0.2.130/28
+ simple_if_fini $h2 192.0.2.130/28 2001:db8:2::2/64
}
router_create()
diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh
index e101af5..ff665de7 100755
--- a/tools/testing/selftests/net/rtnetlink.sh
+++ b/tools/testing/selftests/net/rtnetlink.sh
@@ -234,6 +234,26 @@
echo "PASS: route get"
}
+kci_test_addrlft()
+{
+ for i in $(seq 10 100) ;do
+ lft=$(((RANDOM%3) + 1))
+ ip addr add 10.23.11.$i/32 dev "$devdummy" preferred_lft $lft valid_lft $((lft+1))
+ check_err $?
+ done
+
+ sleep 5
+
+ ip addr show dev "$devdummy" | grep "10.23.11."
+ if [ $? -eq 0 ]; then
+ echo "FAIL: preferred_lft addresses remaining"
+ check_err 1
+ return
+ fi
+
+ echo "PASS: preferred_lft addresses have expired"
+}
+
kci_test_addrlabel()
{
ret=0
@@ -965,6 +985,7 @@
kci_test_polrouting
kci_test_route_get
+ kci_test_addrlft
kci_test_tc
kci_test_gre
kci_test_gretap
diff --git a/tools/testing/selftests/rseq/param_test.c b/tools/testing/selftests/rseq/param_test.c
index eec2663..e8a657a 100644
--- a/tools/testing/selftests/rseq/param_test.c
+++ b/tools/testing/selftests/rseq/param_test.c
@@ -15,7 +15,7 @@
#include <errno.h>
#include <stddef.h>
-static inline pid_t gettid(void)
+static inline pid_t rseq_gettid(void)
{
return syscall(__NR_gettid);
}
@@ -373,11 +373,12 @@ void *test_percpu_spinlock_thread(void *arg)
rseq_percpu_unlock(&data->lock, cpu);
#ifndef BENCHMARK
if (i != 0 && !(i % (reps / 10)))
- printf_verbose("tid %d: count %lld\n", (int) gettid(), i);
+ printf_verbose("tid %d: count %lld\n",
+ (int) rseq_gettid(), i);
#endif
}
printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n",
- (int) gettid(), nr_abort, signals_delivered);
+ (int) rseq_gettid(), nr_abort, signals_delivered);
if (!opt_disable_rseq && thread_data->reg &&
rseq_unregister_current_thread())
abort();
@@ -454,11 +455,12 @@ void *test_percpu_inc_thread(void *arg)
} while (rseq_unlikely(ret));
#ifndef BENCHMARK
if (i != 0 && !(i % (reps / 10)))
- printf_verbose("tid %d: count %lld\n", (int) gettid(), i);
+ printf_verbose("tid %d: count %lld\n",
+ (int) rseq_gettid(), i);
#endif
}
printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n",
- (int) gettid(), nr_abort, signals_delivered);
+ (int) rseq_gettid(), nr_abort, signals_delivered);
if (!opt_disable_rseq && thread_data->reg &&
rseq_unregister_current_thread())
abort();
@@ -605,7 +607,7 @@ void *test_percpu_list_thread(void *arg)
}
printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n",
- (int) gettid(), nr_abort, signals_delivered);
+ (int) rseq_gettid(), nr_abort, signals_delivered);
if (!opt_disable_rseq && rseq_unregister_current_thread())
abort();
@@ -796,7 +798,7 @@ void *test_percpu_buffer_thread(void *arg)
}
printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n",
- (int) gettid(), nr_abort, signals_delivered);
+ (int) rseq_gettid(), nr_abort, signals_delivered);
if (!opt_disable_rseq && rseq_unregister_current_thread())
abort();
@@ -1011,7 +1013,7 @@ void *test_percpu_memcpy_buffer_thread(void *arg)
}
printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n",
- (int) gettid(), nr_abort, signals_delivered);
+ (int) rseq_gettid(), nr_abort, signals_delivered);
if (!opt_disable_rseq && rseq_unregister_current_thread())
abort();
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index d982650..3de40a9 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -382,10 +382,16 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
* We might get preempted before the vCPU actually runs, but
* over-invalidation doesn't affect correctness.
*/
- if (*last_ran != vcpu->vcpu_id) {
+ if (*last_ran != -1 && *last_ran != vcpu->vcpu_id) {
kvm_call_hyp(__kvm_tlb_flush_local_vmid, vcpu);
- *last_ran = vcpu->vcpu_id;
+
+ /*
+ * 'last_ran' and this vcpu may share an ASID and hit the
+ * conditions for Cortex-A77 erratum 1542418.
+ */
+ kvm_workaround_1542418_vmid_rollover();
}
+ *last_ran = vcpu->vcpu_id;
vcpu->cpu = cpu;
vcpu->arch.host_cpu_context = this_cpu_ptr(&kvm_host_cpu_state);
@@ -470,15 +476,16 @@ bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
return vcpu_mode_priv(vcpu);
}
-/* Just ensure a guest exit from a particular CPU */
-static void exit_vm_noop(void *info)
+static void exit_vmid_rollover(void *info)
{
+ kvm_workaround_1542418_vmid_rollover();
}
-void force_vm_exit(const cpumask_t *mask)
+static void force_vmid_rollover_exit(const cpumask_t *mask)
{
preempt_disable();
- smp_call_function_many(mask, exit_vm_noop, NULL, true);
+ smp_call_function_many(mask, exit_vmid_rollover, NULL, true);
+ kvm_workaround_1542418_vmid_rollover();
preempt_enable();
}
@@ -536,10 +543,10 @@ static void update_vttbr(struct kvm *kvm)
/*
* On SMP we know no other CPUs can use this CPU's or each
- * other's VMID after force_vm_exit returns since the
+ * other's VMID after force_vmid_rollover_exit returns since the
* kvm_vmid_lock blocks them from reentry to the guest.
*/
- force_vm_exit(cpu_all_mask);
+ force_vmid_rollover_exit(cpu_all_mask);
/*
* Now broadcast TLB + ICACHE invalidation over the inner
* shareable domain to make sure all data structures are