2251 lines
75 KiB
Diff
2251 lines
75 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index 7a47a2594f957..032751f6be0c1 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 5
|
|
PATCHLEVEL = 4
|
|
-SUBLEVEL = 96
|
|
+SUBLEVEL = 97
|
|
EXTRAVERSION =
|
|
NAME = Kleptomaniac Octopus
|
|
|
|
@@ -920,12 +920,6 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init)
|
|
# change __FILE__ to the relative path from the srctree
|
|
KBUILD_CFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
|
|
|
|
-# ensure -fcf-protection is disabled when using retpoline as it is
|
|
-# incompatible with -mindirect-branch=thunk-extern
|
|
-ifdef CONFIG_RETPOLINE
|
|
-KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
|
|
-endif
|
|
-
|
|
include scripts/Makefile.kasan
|
|
include scripts/Makefile.extrawarn
|
|
include scripts/Makefile.ubsan
|
|
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapro.dts b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
|
|
index 01ccff756996d..5740f9442705c 100644
|
|
--- a/arch/arm/boot/dts/sun7i-a20-bananapro.dts
|
|
+++ b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
|
|
@@ -110,7 +110,7 @@
|
|
pinctrl-names = "default";
|
|
pinctrl-0 = <&gmac_rgmii_pins>;
|
|
phy-handle = <&phy1>;
|
|
- phy-mode = "rgmii";
|
|
+ phy-mode = "rgmii-id";
|
|
phy-supply = <®_gmac_3v3>;
|
|
status = "okay";
|
|
};
|
|
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
|
|
index 8b81a17f675d9..e17ec92b90dd8 100644
|
|
--- a/arch/arm/mach-footbridge/dc21285.c
|
|
+++ b/arch/arm/mach-footbridge/dc21285.c
|
|
@@ -66,15 +66,15 @@ dc21285_read_config(struct pci_bus *bus, unsigned int devfn, int where,
|
|
if (addr)
|
|
switch (size) {
|
|
case 1:
|
|
- asm("ldrb %0, [%1, %2]"
|
|
+ asm volatile("ldrb %0, [%1, %2]"
|
|
: "=r" (v) : "r" (addr), "r" (where) : "cc");
|
|
break;
|
|
case 2:
|
|
- asm("ldrh %0, [%1, %2]"
|
|
+ asm volatile("ldrh %0, [%1, %2]"
|
|
: "=r" (v) : "r" (addr), "r" (where) : "cc");
|
|
break;
|
|
case 4:
|
|
- asm("ldr %0, [%1, %2]"
|
|
+ asm volatile("ldr %0, [%1, %2]"
|
|
: "=r" (v) : "r" (addr), "r" (where) : "cc");
|
|
break;
|
|
}
|
|
@@ -100,17 +100,17 @@ dc21285_write_config(struct pci_bus *bus, unsigned int devfn, int where,
|
|
if (addr)
|
|
switch (size) {
|
|
case 1:
|
|
- asm("strb %0, [%1, %2]"
|
|
+ asm volatile("strb %0, [%1, %2]"
|
|
: : "r" (value), "r" (addr), "r" (where)
|
|
: "cc");
|
|
break;
|
|
case 2:
|
|
- asm("strh %0, [%1, %2]"
|
|
+ asm volatile("strh %0, [%1, %2]"
|
|
: : "r" (value), "r" (addr), "r" (where)
|
|
: "cc");
|
|
break;
|
|
case 4:
|
|
- asm("str %0, [%1, %2]"
|
|
+ asm volatile("str %0, [%1, %2]"
|
|
: : "r" (value), "r" (addr), "r" (where)
|
|
: "cc");
|
|
break;
|
|
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
|
index 354ef2f3eac67..9533c85fb0a30 100644
|
|
--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
|
+++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
|
@@ -2382,7 +2382,7 @@
|
|
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
|
|
dr_mode = "host";
|
|
snps,dis_u2_susphy_quirk;
|
|
- snps,quirk-frame-length-adjustment;
|
|
+ snps,quirk-frame-length-adjustment = <0x20>;
|
|
snps,parkmode-disable-ss-quirk;
|
|
};
|
|
};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
|
|
index d4c1da3d4bde2..04d4b1b11a00a 100644
|
|
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
|
|
@@ -304,7 +304,7 @@
|
|
|
|
dcfg: dcfg@1ee0000 {
|
|
compatible = "fsl,ls1046a-dcfg", "syscon";
|
|
- reg = <0x0 0x1ee0000 0x0 0x10000>;
|
|
+ reg = <0x0 0x1ee0000 0x0 0x1000>;
|
|
big-endian;
|
|
};
|
|
|
|
diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
|
|
index f539b3655f6b9..e638f216dbfb3 100644
|
|
--- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
|
|
+++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
|
|
@@ -243,6 +243,8 @@
|
|
&i2c3 {
|
|
status = "okay";
|
|
clock-frequency = <400000>;
|
|
+ /* Overwrite pinctrl-0 from sdm845.dtsi */
|
|
+ pinctrl-0 = <&qup_i2c3_default &i2c3_hid_active>;
|
|
|
|
tsel: hid@15 {
|
|
compatible = "hid-over-i2c";
|
|
@@ -250,9 +252,6 @@
|
|
hid-descr-addr = <0x1>;
|
|
|
|
interrupts-extended = <&tlmm 37 IRQ_TYPE_LEVEL_HIGH>;
|
|
-
|
|
- pinctrl-names = "default";
|
|
- pinctrl-0 = <&i2c3_hid_active>;
|
|
};
|
|
|
|
tsc2: hid@2c {
|
|
@@ -261,11 +260,6 @@
|
|
hid-descr-addr = <0x20>;
|
|
|
|
interrupts-extended = <&tlmm 37 IRQ_TYPE_LEVEL_HIGH>;
|
|
-
|
|
- pinctrl-names = "default";
|
|
- pinctrl-0 = <&i2c3_hid_active>;
|
|
-
|
|
- status = "disabled";
|
|
};
|
|
};
|
|
|
|
diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi
|
|
index 9e09909a510a1..98b014a8f9165 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/px30.dtsi
|
|
+++ b/arch/arm64/boot/dts/rockchip/px30.dtsi
|
|
@@ -860,7 +860,7 @@
|
|
vopl_mmu: iommu@ff470f00 {
|
|
compatible = "rockchip,iommu";
|
|
reg = <0x0 0xff470f00 0x0 0x100>;
|
|
- interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
|
|
interrupt-names = "vopl_mmu";
|
|
clocks = <&cru ACLK_VOPL>, <&cru HCLK_VOPL>;
|
|
clock-names = "aclk", "hclk";
|
|
diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
|
|
index 179b41ad63baf..18618af3835f9 100644
|
|
--- a/arch/um/drivers/virtio_uml.c
|
|
+++ b/arch/um/drivers/virtio_uml.c
|
|
@@ -959,6 +959,7 @@ static void virtio_uml_release_dev(struct device *d)
|
|
}
|
|
|
|
os_close_file(vu_dev->sock);
|
|
+ kfree(vu_dev);
|
|
}
|
|
|
|
/* Platform device */
|
|
@@ -977,7 +978,7 @@ static int virtio_uml_probe(struct platform_device *pdev)
|
|
if (!pdata)
|
|
return -EINVAL;
|
|
|
|
- vu_dev = devm_kzalloc(&pdev->dev, sizeof(*vu_dev), GFP_KERNEL);
|
|
+ vu_dev = kzalloc(sizeof(*vu_dev), GFP_KERNEL);
|
|
if (!vu_dev)
|
|
return -ENOMEM;
|
|
|
|
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
|
|
index 94df0868804bc..b5e3bfd4facea 100644
|
|
--- a/arch/x86/Makefile
|
|
+++ b/arch/x86/Makefile
|
|
@@ -131,6 +131,9 @@ else
|
|
|
|
KBUILD_CFLAGS += -mno-red-zone
|
|
KBUILD_CFLAGS += -mcmodel=kernel
|
|
+
|
|
+ # Intel CET isn't enabled in the kernel
|
|
+ KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
|
|
endif
|
|
|
|
ifdef CONFIG_X86_X32
|
|
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
|
|
index 6016559ed1713..5bef1575708dc 100644
|
|
--- a/arch/x86/include/asm/apic.h
|
|
+++ b/arch/x86/include/asm/apic.h
|
|
@@ -197,16 +197,6 @@ static inline bool apic_needs_pit(void) { return true; }
|
|
#endif /* !CONFIG_X86_LOCAL_APIC */
|
|
|
|
#ifdef CONFIG_X86_X2APIC
|
|
-/*
|
|
- * Make previous memory operations globally visible before
|
|
- * sending the IPI through x2apic wrmsr. We need a serializing instruction or
|
|
- * mfence for this.
|
|
- */
|
|
-static inline void x2apic_wrmsr_fence(void)
|
|
-{
|
|
- asm volatile("mfence" : : : "memory");
|
|
-}
|
|
-
|
|
static inline void native_apic_msr_write(u32 reg, u32 v)
|
|
{
|
|
if (reg == APIC_DFR || reg == APIC_ID || reg == APIC_LDR ||
|
|
diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h
|
|
index 7f828fe497978..4819d5e5a3353 100644
|
|
--- a/arch/x86/include/asm/barrier.h
|
|
+++ b/arch/x86/include/asm/barrier.h
|
|
@@ -84,4 +84,22 @@ do { \
|
|
|
|
#include <asm-generic/barrier.h>
|
|
|
|
+/*
|
|
+ * Make previous memory operations globally visible before
|
|
+ * a WRMSR.
|
|
+ *
|
|
+ * MFENCE makes writes visible, but only affects load/store
|
|
+ * instructions. WRMSR is unfortunately not a load/store
|
|
+ * instruction and is unaffected by MFENCE. The LFENCE ensures
|
|
+ * that the WRMSR is not reordered.
|
|
+ *
|
|
+ * Most WRMSRs are full serializing instructions themselves and
|
|
+ * do not require this barrier. This is only required for the
|
|
+ * IA32_TSC_DEADLINE and X2APIC MSRs.
|
|
+ */
|
|
+static inline void weak_wrmsr_fence(void)
|
|
+{
|
|
+ asm volatile("mfence; lfence" : : : "memory");
|
|
+}
|
|
+
|
|
#endif /* _ASM_X86_BARRIER_H */
|
|
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
|
|
index 06fa808d72032..3dca7b8642e9c 100644
|
|
--- a/arch/x86/kernel/apic/apic.c
|
|
+++ b/arch/x86/kernel/apic/apic.c
|
|
@@ -42,6 +42,7 @@
|
|
#include <asm/x86_init.h>
|
|
#include <asm/pgalloc.h>
|
|
#include <linux/atomic.h>
|
|
+#include <asm/barrier.h>
|
|
#include <asm/mpspec.h>
|
|
#include <asm/i8259.h>
|
|
#include <asm/proto.h>
|
|
@@ -472,6 +473,9 @@ static int lapic_next_deadline(unsigned long delta,
|
|
{
|
|
u64 tsc;
|
|
|
|
+ /* This MSR is special and need a special fence: */
|
|
+ weak_wrmsr_fence();
|
|
+
|
|
tsc = rdtsc();
|
|
wrmsrl(MSR_IA32_TSC_DEADLINE, tsc + (((u64) delta) * TSC_DIVISOR));
|
|
return 0;
|
|
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c
|
|
index b0889c48a2ac5..7eec3c154fa24 100644
|
|
--- a/arch/x86/kernel/apic/x2apic_cluster.c
|
|
+++ b/arch/x86/kernel/apic/x2apic_cluster.c
|
|
@@ -29,7 +29,8 @@ static void x2apic_send_IPI(int cpu, int vector)
|
|
{
|
|
u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
|
|
|
|
- x2apic_wrmsr_fence();
|
|
+ /* x2apic MSRs are special and need a special fence: */
|
|
+ weak_wrmsr_fence();
|
|
__x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
|
|
}
|
|
|
|
@@ -41,7 +42,8 @@ __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
|
|
unsigned long flags;
|
|
u32 dest;
|
|
|
|
- x2apic_wrmsr_fence();
|
|
+ /* x2apic MSRs are special and need a special fence: */
|
|
+ weak_wrmsr_fence();
|
|
local_irq_save(flags);
|
|
|
|
tmpmsk = this_cpu_cpumask_var_ptr(ipi_mask);
|
|
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
|
|
index e14eae6d6ea71..032a00e5d9fa6 100644
|
|
--- a/arch/x86/kernel/apic/x2apic_phys.c
|
|
+++ b/arch/x86/kernel/apic/x2apic_phys.c
|
|
@@ -43,7 +43,8 @@ static void x2apic_send_IPI(int cpu, int vector)
|
|
{
|
|
u32 dest = per_cpu(x86_cpu_to_apicid, cpu);
|
|
|
|
- x2apic_wrmsr_fence();
|
|
+ /* x2apic MSRs are special and need a special fence: */
|
|
+ weak_wrmsr_fence();
|
|
__x2apic_send_IPI_dest(dest, vector, APIC_DEST_PHYSICAL);
|
|
}
|
|
|
|
@@ -54,7 +55,8 @@ __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
|
|
unsigned long this_cpu;
|
|
unsigned long flags;
|
|
|
|
- x2apic_wrmsr_fence();
|
|
+ /* x2apic MSRs are special and need a special fence: */
|
|
+ weak_wrmsr_fence();
|
|
|
|
local_irq_save(flags);
|
|
|
|
@@ -125,7 +127,8 @@ void __x2apic_send_IPI_shorthand(int vector, u32 which)
|
|
{
|
|
unsigned long cfg = __prepare_ICR(which, vector, 0);
|
|
|
|
- x2apic_wrmsr_fence();
|
|
+ /* x2apic MSRs are special and need a special fence: */
|
|
+ weak_wrmsr_fence();
|
|
native_x2apic_icr_write(cfg, 0);
|
|
}
|
|
|
|
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
|
|
index 39265b55929d2..60c8dcb907a50 100644
|
|
--- a/arch/x86/kvm/emulate.c
|
|
+++ b/arch/x86/kvm/emulate.c
|
|
@@ -2890,6 +2890,8 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
|
|
ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data);
|
|
*reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data :
|
|
(u32)msr_data;
|
|
+ if (efer & EFER_LMA)
|
|
+ ctxt->mode = X86EMUL_MODE_PROT64;
|
|
|
|
return X86EMUL_CONTINUE;
|
|
}
|
|
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
|
|
index 2b506904be024..4906e480b5bb6 100644
|
|
--- a/arch/x86/kvm/svm.c
|
|
+++ b/arch/x86/kvm/svm.c
|
|
@@ -889,6 +889,11 @@ static int has_svm(void)
|
|
return 0;
|
|
}
|
|
|
|
+ if (sev_active()) {
|
|
+ pr_info("KVM is unsupported when running as an SEV guest\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
return 1;
|
|
}
|
|
|
|
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
|
|
index 9268c12458c84..dfa01bcdc3694 100644
|
|
--- a/arch/x86/mm/mem_encrypt.c
|
|
+++ b/arch/x86/mm/mem_encrypt.c
|
|
@@ -375,6 +375,7 @@ bool force_dma_unencrypted(struct device *dev)
|
|
|
|
return false;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(sev_active);
|
|
|
|
/* Architecture __weak replacement functions */
|
|
void __init mem_encrypt_free_decrypted_mem(void)
|
|
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
|
|
index d2dd387c95d86..de06ee7d2ad46 100644
|
|
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
|
|
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
|
|
@@ -1434,8 +1434,6 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
|
|
|
|
drm_connector_update_edid_property(connector,
|
|
aconnector->edid);
|
|
- drm_add_edid_modes(connector, aconnector->edid);
|
|
-
|
|
if (aconnector->dc_link->aux_mode)
|
|
drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
|
|
aconnector->edid);
|
|
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
|
|
index 8c73377ac82ca..3d004ca76b6ed 100644
|
|
--- a/drivers/input/joystick/xpad.c
|
|
+++ b/drivers/input/joystick/xpad.c
|
|
@@ -215,9 +215,17 @@ static const struct xpad_device {
|
|
{ 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
|
|
{ 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
|
|
{ 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE },
|
|
- { 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02a0, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02a1, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02a2, "PDP Wired Controller for Xbox One - Crimson Red", 0, XTYPE_XBOXONE },
|
|
{ 0x0e6f, 0x02a4, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE },
|
|
{ 0x0e6f, 0x02a6, "PDP Wired Controller for Xbox One - Camo Series", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02a7, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02a8, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02ad, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02b3, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x0e6f, 0x02b8, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE },
|
|
{ 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE },
|
|
{ 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 },
|
|
@@ -296,6 +304,9 @@ static const struct xpad_device {
|
|
{ 0x1bad, 0xfa01, "MadCatz GamePad", 0, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
|
|
{ 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
|
|
+ { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
|
|
+ { 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 },
|
|
+ { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE },
|
|
{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
|
{ 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
|
|
{ 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
|
|
@@ -429,8 +440,12 @@ static const struct usb_device_id xpad_table[] = {
|
|
XPAD_XBOX360_VENDOR(0x162e), /* Joytech X-Box 360 controllers */
|
|
XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */
|
|
XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */
|
|
+ XPAD_XBOX360_VENDOR(0x20d6), /* PowerA Controllers */
|
|
+ XPAD_XBOXONE_VENDOR(0x20d6), /* PowerA Controllers */
|
|
XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */
|
|
XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */
|
|
+ XPAD_XBOXONE_VENDOR(0x2e24), /* Hyperkin Duke X-Box One pad */
|
|
+ XPAD_XBOX360_VENDOR(0x2f24), /* GameSir Controllers */
|
|
{ }
|
|
};
|
|
|
|
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
|
|
index eca931da76c3a..b7dbcbac3a1a5 100644
|
|
--- a/drivers/input/serio/i8042-x86ia64io.h
|
|
+++ b/drivers/input/serio/i8042-x86ia64io.h
|
|
@@ -219,6 +219,8 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = {
|
|
DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"),
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "C15B"),
|
|
},
|
|
+ },
|
|
+ {
|
|
.matches = {
|
|
DMI_MATCH(DMI_SYS_VENDOR, "ByteSpeed LLC"),
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "ByteSpeed Laptop C15B"),
|
|
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
|
|
index 984c7a6ea4fe8..953d86ca6d2b2 100644
|
|
--- a/drivers/iommu/intel-iommu.c
|
|
+++ b/drivers/iommu/intel-iommu.c
|
|
@@ -3285,6 +3285,12 @@ static int __init init_dmars(void)
|
|
|
|
if (!ecap_pass_through(iommu->ecap))
|
|
hw_pass_through = 0;
|
|
+
|
|
+ if (!intel_iommu_strict && cap_caching_mode(iommu->cap)) {
|
|
+ pr_info("Disable batched IOTLB flush due to virtualization");
|
|
+ intel_iommu_strict = 1;
|
|
+ }
|
|
+
|
|
#ifdef CONFIG_INTEL_IOMMU_SVM
|
|
if (pasid_supported(iommu))
|
|
intel_svm_init(iommu);
|
|
diff --git a/drivers/md/md.c b/drivers/md/md.c
|
|
index ec5dfb7ae4e16..cc38530804c90 100644
|
|
--- a/drivers/md/md.c
|
|
+++ b/drivers/md/md.c
|
|
@@ -538,8 +538,10 @@ static void md_submit_flush_data(struct work_struct *ws)
|
|
* could wait for this and below md_handle_request could wait for those
|
|
* bios because of suspend check
|
|
*/
|
|
+ spin_lock_irq(&mddev->lock);
|
|
mddev->last_flush = mddev->start_flush;
|
|
mddev->flush_bio = NULL;
|
|
+ spin_unlock_irq(&mddev->lock);
|
|
wake_up(&mddev->sb_wait);
|
|
|
|
if (bio->bi_iter.bi_size == 0) {
|
|
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
|
|
index 3efaa9534a777..9a5aaac29099b 100644
|
|
--- a/drivers/mmc/core/sdio_cis.c
|
|
+++ b/drivers/mmc/core/sdio_cis.c
|
|
@@ -20,6 +20,8 @@
|
|
#include "sdio_cis.h"
|
|
#include "sdio_ops.h"
|
|
|
|
+#define SDIO_READ_CIS_TIMEOUT_MS (10 * 1000) /* 10s */
|
|
+
|
|
static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
|
|
const unsigned char *buf, unsigned size)
|
|
{
|
|
@@ -266,6 +268,8 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
|
|
|
|
do {
|
|
unsigned char tpl_code, tpl_link;
|
|
+ unsigned long timeout = jiffies +
|
|
+ msecs_to_jiffies(SDIO_READ_CIS_TIMEOUT_MS);
|
|
|
|
ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
|
|
if (ret)
|
|
@@ -318,6 +322,8 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
|
|
prev = &this->next;
|
|
|
|
if (ret == -ENOENT) {
|
|
+ if (time_after(jiffies, timeout))
|
|
+ break;
|
|
/* warn about unknown tuples */
|
|
pr_warn_ratelimited("%s: queuing unknown"
|
|
" CIS tuple 0x%02x (%u bytes)\n",
|
|
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
|
|
index 469b155df4885..1af09fd3fed1c 100644
|
|
--- a/drivers/net/dsa/mv88e6xxx/chip.c
|
|
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
|
|
@@ -1517,7 +1517,11 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
|
|
if (!entry.portvec)
|
|
entry.state = 0;
|
|
} else {
|
|
- entry.portvec |= BIT(port);
|
|
+ if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC)
|
|
+ entry.portvec = BIT(port);
|
|
+ else
|
|
+ entry.portvec |= BIT(port);
|
|
+
|
|
entry.state = state;
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
|
|
index c20dc689698ed..5acd599d6b9af 100644
|
|
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
|
|
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
|
|
@@ -55,12 +55,7 @@ static void i40e_vc_notify_vf_link_state(struct i40e_vf *vf)
|
|
|
|
pfe.event = VIRTCHNL_EVENT_LINK_CHANGE;
|
|
pfe.severity = PF_EVENT_SEVERITY_INFO;
|
|
-
|
|
- /* Always report link is down if the VF queues aren't enabled */
|
|
- if (!vf->queues_enabled) {
|
|
- pfe.event_data.link_event.link_status = false;
|
|
- pfe.event_data.link_event.link_speed = 0;
|
|
- } else if (vf->link_forced) {
|
|
+ if (vf->link_forced) {
|
|
pfe.event_data.link_event.link_status = vf->link_up;
|
|
pfe.event_data.link_event.link_speed =
|
|
(vf->link_up ? VIRTCHNL_LINK_SPEED_40GB : 0);
|
|
@@ -70,7 +65,6 @@ static void i40e_vc_notify_vf_link_state(struct i40e_vf *vf)
|
|
pfe.event_data.link_event.link_speed =
|
|
i40e_virtchnl_link_speed(ls->link_speed);
|
|
}
|
|
-
|
|
i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT,
|
|
0, (u8 *)&pfe, sizeof(pfe), NULL);
|
|
}
|
|
@@ -2393,8 +2387,6 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg)
|
|
}
|
|
}
|
|
|
|
- vf->queues_enabled = true;
|
|
-
|
|
error_param:
|
|
/* send the response to the VF */
|
|
return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES,
|
|
@@ -2416,9 +2408,6 @@ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg)
|
|
struct i40e_pf *pf = vf->pf;
|
|
i40e_status aq_ret = 0;
|
|
|
|
- /* Immediately mark queues as disabled */
|
|
- vf->queues_enabled = false;
|
|
-
|
|
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
|
|
aq_ret = I40E_ERR_PARAM;
|
|
goto error_param;
|
|
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
|
|
index 7164b9bb294ff..f65cc0c165502 100644
|
|
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
|
|
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
|
|
@@ -99,7 +99,6 @@ struct i40e_vf {
|
|
unsigned int tx_rate; /* Tx bandwidth limit in Mbps */
|
|
bool link_forced;
|
|
bool link_up; /* only valid if VF link is forced */
|
|
- bool queues_enabled; /* true if the VF queues are enabled */
|
|
bool spoofchk;
|
|
u16 num_mac;
|
|
u16 num_vlan;
|
|
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
|
|
index 0303eeb760505..0365bf2b480e3 100644
|
|
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
|
|
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
|
|
@@ -1709,7 +1709,8 @@ static int igc_get_link_ksettings(struct net_device *netdev,
|
|
Asym_Pause);
|
|
}
|
|
|
|
- status = rd32(IGC_STATUS);
|
|
+ status = pm_runtime_suspended(&adapter->pdev->dev) ?
|
|
+ 0 : rd32(IGC_STATUS);
|
|
|
|
if (status & IGC_STATUS_LU) {
|
|
if (status & IGC_STATUS_SPEED_1000) {
|
|
diff --git a/drivers/net/ethernet/intel/igc/igc_i225.c b/drivers/net/ethernet/intel/igc/igc_i225.c
|
|
index c25f555aaf822..ed5d09c11c389 100644
|
|
--- a/drivers/net/ethernet/intel/igc/igc_i225.c
|
|
+++ b/drivers/net/ethernet/intel/igc/igc_i225.c
|
|
@@ -219,9 +219,9 @@ static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
|
|
u16 *data)
|
|
{
|
|
struct igc_nvm_info *nvm = &hw->nvm;
|
|
+ s32 ret_val = -IGC_ERR_NVM;
|
|
u32 attempts = 100000;
|
|
u32 i, k, eewr = 0;
|
|
- s32 ret_val = 0;
|
|
|
|
/* A check for invalid values: offset too large, too many words,
|
|
* too many words for the offset, and not enough words.
|
|
@@ -229,7 +229,6 @@ static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
|
|
if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) ||
|
|
words == 0) {
|
|
hw_dbg("nvm parameter(s) out of bounds\n");
|
|
- ret_val = -IGC_ERR_NVM;
|
|
goto out;
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c
|
|
index 5eeb4c8caf4ae..08adf103e90b4 100644
|
|
--- a/drivers/net/ethernet/intel/igc/igc_mac.c
|
|
+++ b/drivers/net/ethernet/intel/igc/igc_mac.c
|
|
@@ -647,7 +647,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
|
|
}
|
|
|
|
out:
|
|
- return 0;
|
|
+ return ret_val;
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
|
|
index a30eb90ba3d28..dd590086fe6a5 100644
|
|
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
|
|
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
|
|
@@ -29,16 +29,16 @@ static int mvpp2_prs_hw_write(struct mvpp2 *priv, struct mvpp2_prs_entry *pe)
|
|
/* Clear entry invalidation bit */
|
|
pe->tcam[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
|
|
|
|
- /* Write tcam index - indirect access */
|
|
- mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
|
|
- for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
|
|
- mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam[i]);
|
|
-
|
|
/* Write sram index - indirect access */
|
|
mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
|
|
for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
|
|
mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram[i]);
|
|
|
|
+ /* Write tcam index - indirect access */
|
|
+ mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
|
|
+ for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
|
|
+ mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam[i]);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
index 4944c40436f08..11e12761b0a6e 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
@@ -1697,6 +1697,7 @@ search_again_locked:
|
|
if (!fte_tmp)
|
|
continue;
|
|
rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte_tmp);
|
|
+ /* No error check needed here, because insert_fte() is not called */
|
|
up_write_ref_node(&fte_tmp->node, false);
|
|
tree_put_node(&fte_tmp->node, false);
|
|
kmem_cache_free(steering->ftes_cache, fte);
|
|
@@ -1745,6 +1746,8 @@ skip_search:
|
|
up_write_ref_node(&g->node, false);
|
|
rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
|
|
up_write_ref_node(&fte->node, false);
|
|
+ if (IS_ERR(rule))
|
|
+ tree_put_node(&fte->node, false);
|
|
return rule;
|
|
}
|
|
rule = ERR_PTR(-ENOENT);
|
|
@@ -1844,6 +1847,8 @@ search_again_locked:
|
|
up_write_ref_node(&g->node, false);
|
|
rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
|
|
up_write_ref_node(&fte->node, false);
|
|
+ if (IS_ERR(rule))
|
|
+ tree_put_node(&fte->node, false);
|
|
tree_put_node(&g->node, false);
|
|
return rule;
|
|
|
|
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
|
|
index 366ca1b5da5cc..1e8244ec5b332 100644
|
|
--- a/drivers/net/ethernet/realtek/r8169_main.c
|
|
+++ b/drivers/net/ethernet/realtek/r8169_main.c
|
|
@@ -6419,10 +6419,10 @@ static int rtl8169_close(struct net_device *dev)
|
|
|
|
cancel_work_sync(&tp->wk.work);
|
|
|
|
- phy_disconnect(tp->phydev);
|
|
-
|
|
free_irq(pci_irq_vector(pdev, 0), tp);
|
|
|
|
+ phy_disconnect(tp->phydev);
|
|
+
|
|
dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
|
|
tp->RxPhyAddr);
|
|
dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
|
|
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
|
|
index c54fe6650018e..7272d8522a9e9 100644
|
|
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
|
|
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
|
|
@@ -134,7 +134,14 @@ static int iwl_configure_rxq(struct iwl_mvm *mvm)
|
|
.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
|
|
};
|
|
|
|
- /* Do not configure default queue, it is configured via context info */
|
|
+ /*
|
|
+ * The default queue is configured via context info, so if we
|
|
+ * have a single queue, there's nothing to do here.
|
|
+ */
|
|
+ if (mvm->trans->num_rx_queues == 1)
|
|
+ return 0;
|
|
+
|
|
+ /* skip the default queue */
|
|
num_queues = mvm->trans->num_rx_queues - 1;
|
|
|
|
size = struct_size(cmd, data, num_queues);
|
|
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
|
|
index 196aa44c4936a..e0f411021c59d 100644
|
|
--- a/drivers/nvdimm/dimm_devs.c
|
|
+++ b/drivers/nvdimm/dimm_devs.c
|
|
@@ -344,16 +344,16 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
|
|
}
|
|
static DEVICE_ATTR_RO(state);
|
|
|
|
-static ssize_t available_slots_show(struct device *dev,
|
|
- struct device_attribute *attr, char *buf)
|
|
+static ssize_t __available_slots_show(struct nvdimm_drvdata *ndd, char *buf)
|
|
{
|
|
- struct nvdimm_drvdata *ndd = dev_get_drvdata(dev);
|
|
+ struct device *dev;
|
|
ssize_t rc;
|
|
u32 nfree;
|
|
|
|
if (!ndd)
|
|
return -ENXIO;
|
|
|
|
+ dev = ndd->dev;
|
|
nvdimm_bus_lock(dev);
|
|
nfree = nd_label_nfree(ndd);
|
|
if (nfree - 1 > nfree) {
|
|
@@ -365,6 +365,18 @@ static ssize_t available_slots_show(struct device *dev,
|
|
nvdimm_bus_unlock(dev);
|
|
return rc;
|
|
}
|
|
+
|
|
+static ssize_t available_slots_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ ssize_t rc;
|
|
+
|
|
+ nd_device_lock(dev);
|
|
+ rc = __available_slots_show(dev_get_drvdata(dev), buf);
|
|
+ nd_device_unlock(dev);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
static DEVICE_ATTR_RO(available_slots);
|
|
|
|
__weak ssize_t security_show(struct device *dev,
|
|
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
|
|
index ef93bd3ed339c..434d3f21f0e13 100644
|
|
--- a/drivers/nvme/host/pci.c
|
|
+++ b/drivers/nvme/host/pci.c
|
|
@@ -3161,6 +3161,8 @@ static const struct pci_device_id nvme_id_table[] = {
|
|
{ PCI_DEVICE(0x1c5c, 0x1504), /* SK Hynix PC400 */
|
|
.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
|
|
{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) },
|
|
+ { PCI_DEVICE(0x2646, 0x2263), /* KINGSTON A2000 NVMe SSD */
|
|
+ .driver_data = NVME_QUIRK_NO_DEEPEST_PS, },
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
|
|
.driver_data = NVME_QUIRK_SINGLE_VECTOR },
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) },
|
|
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
|
|
index e31823f19a0fa..9242224156f5b 100644
|
|
--- a/drivers/nvme/target/tcp.c
|
|
+++ b/drivers/nvme/target/tcp.c
|
|
@@ -292,7 +292,7 @@ static void nvmet_tcp_map_pdu_iovec(struct nvmet_tcp_cmd *cmd)
|
|
length = cmd->pdu_len;
|
|
cmd->nr_mapped = DIV_ROUND_UP(length, PAGE_SIZE);
|
|
offset = cmd->rbytes_done;
|
|
- cmd->sg_idx = DIV_ROUND_UP(offset, PAGE_SIZE);
|
|
+ cmd->sg_idx = offset / PAGE_SIZE;
|
|
sg_offset = offset % PAGE_SIZE;
|
|
sg = &cmd->req.sg[cmd->sg_idx];
|
|
|
|
@@ -305,6 +305,7 @@ static void nvmet_tcp_map_pdu_iovec(struct nvmet_tcp_cmd *cmd)
|
|
length -= iov_len;
|
|
sg = sg_next(sg);
|
|
iov++;
|
|
+ sg_offset = 0;
|
|
}
|
|
|
|
iov_iter_kvec(&cmd->recv_msg.msg_iter, READ, cmd->iov,
|
|
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
|
|
index 134dc2005ce97..c9f6e97582885 100644
|
|
--- a/drivers/usb/class/usblp.c
|
|
+++ b/drivers/usb/class/usblp.c
|
|
@@ -1329,14 +1329,17 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol)
|
|
if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL)
|
|
return -EINVAL;
|
|
|
|
- alts = usblp->protocol[protocol].alt_setting;
|
|
- if (alts < 0)
|
|
- return -EINVAL;
|
|
- r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
|
|
- if (r < 0) {
|
|
- printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
|
|
- alts, usblp->ifnum);
|
|
- return r;
|
|
+ /* Don't unnecessarily set the interface if there's a single alt. */
|
|
+ if (usblp->intf->num_altsetting > 1) {
|
|
+ alts = usblp->protocol[protocol].alt_setting;
|
|
+ if (alts < 0)
|
|
+ return -EINVAL;
|
|
+ r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
|
|
+ if (r < 0) {
|
|
+ printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
|
|
+ alts, usblp->ifnum);
|
|
+ return r;
|
|
+ }
|
|
}
|
|
|
|
usblp->bidir = (usblp->protocol[protocol].epread != NULL);
|
|
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
|
|
index 70ac47a341ac2..e3f1f20c49221 100644
|
|
--- a/drivers/usb/dwc2/gadget.c
|
|
+++ b/drivers/usb/dwc2/gadget.c
|
|
@@ -1543,7 +1543,6 @@ static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep,
|
|
static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
|
|
u32 windex)
|
|
{
|
|
- struct dwc2_hsotg_ep *ep;
|
|
int dir = (windex & USB_DIR_IN) ? 1 : 0;
|
|
int idx = windex & 0x7F;
|
|
|
|
@@ -1553,12 +1552,7 @@ static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
|
|
if (idx > hsotg->num_of_eps)
|
|
return NULL;
|
|
|
|
- ep = index_to_ep(hsotg, idx, dir);
|
|
-
|
|
- if (idx && ep->dir_in != dir)
|
|
- return NULL;
|
|
-
|
|
- return ep;
|
|
+ return index_to_ep(hsotg, idx, dir);
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
|
|
index 440dbf55ddf70..90ec65d31059f 100644
|
|
--- a/drivers/usb/dwc3/core.c
|
|
+++ b/drivers/usb/dwc3/core.c
|
|
@@ -1718,7 +1718,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
|
if (PMSG_IS_AUTO(msg))
|
|
break;
|
|
|
|
- ret = dwc3_core_init(dwc);
|
|
+ ret = dwc3_core_init_for_resume(dwc);
|
|
if (ret)
|
|
return ret;
|
|
|
|
diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget/legacy/ether.c
|
|
index 30313b233680d..99c7fc0d1d597 100644
|
|
--- a/drivers/usb/gadget/legacy/ether.c
|
|
+++ b/drivers/usb/gadget/legacy/ether.c
|
|
@@ -403,8 +403,10 @@ static int eth_bind(struct usb_composite_dev *cdev)
|
|
struct usb_descriptor_header *usb_desc;
|
|
|
|
usb_desc = usb_otg_descriptor_alloc(gadget);
|
|
- if (!usb_desc)
|
|
+ if (!usb_desc) {
|
|
+ status = -ENOMEM;
|
|
goto fail1;
|
|
+ }
|
|
usb_otg_descriptor_init(gadget, usb_desc);
|
|
otg_desc[0] = usb_desc;
|
|
otg_desc[1] = NULL;
|
|
diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
|
|
index 45c54d56ecbd5..b45e5bf089979 100644
|
|
--- a/drivers/usb/host/xhci-mtk-sch.c
|
|
+++ b/drivers/usb/host/xhci-mtk-sch.c
|
|
@@ -200,6 +200,8 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev,
|
|
|
|
sch_ep->sch_tt = tt;
|
|
sch_ep->ep = ep;
|
|
+ INIT_LIST_HEAD(&sch_ep->endpoint);
|
|
+ INIT_LIST_HEAD(&sch_ep->tt_endpoint);
|
|
|
|
return sch_ep;
|
|
}
|
|
@@ -373,6 +375,7 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
|
|
sch_ep->bw_budget_table[j];
|
|
}
|
|
}
|
|
+ sch_ep->allocated = used;
|
|
}
|
|
|
|
static int check_sch_tt(struct usb_device *udev,
|
|
@@ -541,6 +544,22 @@ static int check_sch_bw(struct usb_device *udev,
|
|
return 0;
|
|
}
|
|
|
|
+static void destroy_sch_ep(struct usb_device *udev,
|
|
+ struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep)
|
|
+{
|
|
+ /* only release ep bw check passed by check_sch_bw() */
|
|
+ if (sch_ep->allocated)
|
|
+ update_bus_bw(sch_bw, sch_ep, 0);
|
|
+
|
|
+ list_del(&sch_ep->endpoint);
|
|
+
|
|
+ if (sch_ep->sch_tt) {
|
|
+ list_del(&sch_ep->tt_endpoint);
|
|
+ drop_tt(udev);
|
|
+ }
|
|
+ kfree(sch_ep);
|
|
+}
|
|
+
|
|
static bool need_bw_sch(struct usb_host_endpoint *ep,
|
|
enum usb_device_speed speed, int has_tt)
|
|
{
|
|
@@ -583,6 +602,8 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
|
|
|
|
mtk->sch_array = sch_array;
|
|
|
|
+ INIT_LIST_HEAD(&mtk->bw_ep_chk_list);
|
|
+
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
|
|
@@ -601,19 +622,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
|
|
struct xhci_ep_ctx *ep_ctx;
|
|
struct xhci_slot_ctx *slot_ctx;
|
|
struct xhci_virt_device *virt_dev;
|
|
- struct mu3h_sch_bw_info *sch_bw;
|
|
struct mu3h_sch_ep_info *sch_ep;
|
|
- struct mu3h_sch_bw_info *sch_array;
|
|
unsigned int ep_index;
|
|
- int bw_index;
|
|
- int ret = 0;
|
|
|
|
xhci = hcd_to_xhci(hcd);
|
|
virt_dev = xhci->devs[udev->slot_id];
|
|
ep_index = xhci_get_endpoint_index(&ep->desc);
|
|
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
|
|
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
|
|
- sch_array = mtk->sch_array;
|
|
|
|
xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
|
|
__func__, usb_endpoint_type(&ep->desc), udev->speed,
|
|
@@ -632,35 +648,13 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
|
|
return 0;
|
|
}
|
|
|
|
- bw_index = get_bw_index(xhci, udev, ep);
|
|
- sch_bw = &sch_array[bw_index];
|
|
-
|
|
sch_ep = create_sch_ep(udev, ep, ep_ctx);
|
|
if (IS_ERR_OR_NULL(sch_ep))
|
|
return -ENOMEM;
|
|
|
|
setup_sch_info(udev, ep_ctx, sch_ep);
|
|
|
|
- ret = check_sch_bw(udev, sch_bw, sch_ep);
|
|
- if (ret) {
|
|
- xhci_err(xhci, "Not enough bandwidth!\n");
|
|
- if (is_fs_or_ls(udev->speed))
|
|
- drop_tt(udev);
|
|
-
|
|
- kfree(sch_ep);
|
|
- return -ENOSPC;
|
|
- }
|
|
-
|
|
- list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
|
|
-
|
|
- ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
|
|
- | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
|
|
- ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
|
|
- | EP_BREPEAT(sch_ep->repeat));
|
|
-
|
|
- xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
|
|
- sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
|
|
- sch_ep->offset, sch_ep->repeat);
|
|
+ list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_chk_list);
|
|
|
|
return 0;
|
|
}
|
|
@@ -675,7 +669,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
|
|
struct xhci_virt_device *virt_dev;
|
|
struct mu3h_sch_bw_info *sch_array;
|
|
struct mu3h_sch_bw_info *sch_bw;
|
|
- struct mu3h_sch_ep_info *sch_ep;
|
|
+ struct mu3h_sch_ep_info *sch_ep, *tmp;
|
|
int bw_index;
|
|
|
|
xhci = hcd_to_xhci(hcd);
|
|
@@ -694,17 +688,79 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
|
|
bw_index = get_bw_index(xhci, udev, ep);
|
|
sch_bw = &sch_array[bw_index];
|
|
|
|
- list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) {
|
|
+ list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) {
|
|
if (sch_ep->ep == ep) {
|
|
- update_bus_bw(sch_bw, sch_ep, 0);
|
|
- list_del(&sch_ep->endpoint);
|
|
- if (is_fs_or_ls(udev->speed)) {
|
|
- list_del(&sch_ep->tt_endpoint);
|
|
- drop_tt(udev);
|
|
- }
|
|
- kfree(sch_ep);
|
|
+ destroy_sch_ep(udev, sch_bw, sch_ep);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);
|
|
+
|
|
+int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|
+{
|
|
+ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
|
|
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
|
+ struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id];
|
|
+ struct mu3h_sch_bw_info *sch_bw;
|
|
+ struct mu3h_sch_ep_info *sch_ep, *tmp;
|
|
+ int bw_index, ret;
|
|
+
|
|
+ xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev));
|
|
+
|
|
+ list_for_each_entry(sch_ep, &mtk->bw_ep_chk_list, endpoint) {
|
|
+ bw_index = get_bw_index(xhci, udev, sch_ep->ep);
|
|
+ sch_bw = &mtk->sch_array[bw_index];
|
|
+
|
|
+ ret = check_sch_bw(udev, sch_bw, sch_ep);
|
|
+ if (ret) {
|
|
+ xhci_err(xhci, "Not enough bandwidth!\n");
|
|
+ return -ENOSPC;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) {
|
|
+ struct xhci_ep_ctx *ep_ctx;
|
|
+ struct usb_host_endpoint *ep = sch_ep->ep;
|
|
+ unsigned int ep_index = xhci_get_endpoint_index(&ep->desc);
|
|
+
|
|
+ bw_index = get_bw_index(xhci, udev, ep);
|
|
+ sch_bw = &mtk->sch_array[bw_index];
|
|
+
|
|
+ list_move_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
|
|
+
|
|
+ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
|
|
+ ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
|
|
+ | EP_BCSCOUNT(sch_ep->cs_count)
|
|
+ | EP_BBM(sch_ep->burst_mode));
|
|
+ ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
|
|
+ | EP_BREPEAT(sch_ep->repeat));
|
|
+
|
|
+ xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
|
|
+ sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
|
|
+ sch_ep->offset, sch_ep->repeat);
|
|
+ }
|
|
+
|
|
+ return xhci_check_bandwidth(hcd, udev);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(xhci_mtk_check_bandwidth);
|
|
+
|
|
+void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|
+{
|
|
+ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
|
|
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
|
+ struct mu3h_sch_bw_info *sch_bw;
|
|
+ struct mu3h_sch_ep_info *sch_ep, *tmp;
|
|
+ int bw_index;
|
|
+
|
|
+ xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev));
|
|
+
|
|
+ list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) {
|
|
+ bw_index = get_bw_index(xhci, udev, sch_ep->ep);
|
|
+ sch_bw = &mtk->sch_array[bw_index];
|
|
+ destroy_sch_ep(udev, sch_bw, sch_ep);
|
|
+ }
|
|
+
|
|
+ xhci_reset_bandwidth(hcd, udev);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(xhci_mtk_reset_bandwidth);
|
|
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
|
|
index 85f1ff0399a9c..09b67219fd146 100644
|
|
--- a/drivers/usb/host/xhci-mtk.c
|
|
+++ b/drivers/usb/host/xhci-mtk.c
|
|
@@ -347,6 +347,8 @@ static void usb_wakeup_set(struct xhci_hcd_mtk *mtk, bool enable)
|
|
static int xhci_mtk_setup(struct usb_hcd *hcd);
|
|
static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
|
|
.reset = xhci_mtk_setup,
|
|
+ .check_bandwidth = xhci_mtk_check_bandwidth,
|
|
+ .reset_bandwidth = xhci_mtk_reset_bandwidth,
|
|
};
|
|
|
|
static struct hc_driver __read_mostly xhci_mtk_hc_driver;
|
|
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
|
|
index 5ac458b7d2e0e..734c5513aa1bf 100644
|
|
--- a/drivers/usb/host/xhci-mtk.h
|
|
+++ b/drivers/usb/host/xhci-mtk.h
|
|
@@ -59,6 +59,7 @@ struct mu3h_sch_bw_info {
|
|
* @ep_type: endpoint type
|
|
* @maxpkt: max packet size of endpoint
|
|
* @ep: address of usb_host_endpoint struct
|
|
+ * @allocated: the bandwidth is aready allocated from bus_bw
|
|
* @offset: which uframe of the interval that transfer should be
|
|
* scheduled first time within the interval
|
|
* @repeat: the time gap between two uframes that transfers are
|
|
@@ -86,6 +87,7 @@ struct mu3h_sch_ep_info {
|
|
u32 ep_type;
|
|
u32 maxpkt;
|
|
void *ep;
|
|
+ bool allocated;
|
|
/*
|
|
* mtk xHCI scheduling information put into reserved DWs
|
|
* in ep context
|
|
@@ -131,6 +133,7 @@ struct xhci_hcd_mtk {
|
|
struct device *dev;
|
|
struct usb_hcd *hcd;
|
|
struct mu3h_sch_bw_info *sch_array;
|
|
+ struct list_head bw_ep_chk_list;
|
|
struct mu3c_ippc_regs __iomem *ippc_regs;
|
|
bool has_ippc;
|
|
int num_u2_ports;
|
|
@@ -166,6 +169,8 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
|
|
struct usb_host_endpoint *ep);
|
|
void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
|
|
struct usb_host_endpoint *ep);
|
|
+int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
|
+void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
|
|
|
#else
|
|
static inline int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd,
|
|
@@ -179,6 +184,16 @@ static inline void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd,
|
|
{
|
|
}
|
|
|
|
+static inline int xhci_mtk_check_bandwidth(struct usb_hcd *hcd,
|
|
+ struct usb_device *udev)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd,
|
|
+ struct usb_device *udev)
|
|
+{
|
|
+}
|
|
#endif
|
|
|
|
#endif /* _XHCI_MTK_H_ */
|
|
diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c
|
|
index 60651a50770f9..f27d5c2c42f31 100644
|
|
--- a/drivers/usb/host/xhci-mvebu.c
|
|
+++ b/drivers/usb/host/xhci-mvebu.c
|
|
@@ -8,6 +8,7 @@
|
|
#include <linux/mbus.h>
|
|
#include <linux/of.h>
|
|
#include <linux/platform_device.h>
|
|
+#include <linux/phy/phy.h>
|
|
|
|
#include <linux/usb.h>
|
|
#include <linux/usb/hcd.h>
|
|
@@ -74,6 +75,47 @@ int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
|
|
return 0;
|
|
}
|
|
|
|
+int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
|
|
+{
|
|
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
|
+ struct device *dev = hcd->self.controller;
|
|
+ struct phy *phy;
|
|
+ int ret;
|
|
+
|
|
+ /* Old bindings miss the PHY handle */
|
|
+ phy = of_phy_get(dev->of_node, "usb3-phy");
|
|
+ if (IS_ERR(phy) && PTR_ERR(phy) == -EPROBE_DEFER)
|
|
+ return -EPROBE_DEFER;
|
|
+ else if (IS_ERR(phy))
|
|
+ goto phy_out;
|
|
+
|
|
+ ret = phy_init(phy);
|
|
+ if (ret)
|
|
+ goto phy_put;
|
|
+
|
|
+ ret = phy_set_mode(phy, PHY_MODE_USB_HOST_SS);
|
|
+ if (ret)
|
|
+ goto phy_exit;
|
|
+
|
|
+ ret = phy_power_on(phy);
|
|
+ if (ret == -EOPNOTSUPP) {
|
|
+ /* Skip initializatin of XHCI PHY when it is unsupported by firmware */
|
|
+ dev_warn(dev, "PHY unsupported by firmware\n");
|
|
+ xhci->quirks |= XHCI_SKIP_PHY_INIT;
|
|
+ }
|
|
+ if (ret)
|
|
+ goto phy_exit;
|
|
+
|
|
+ phy_power_off(phy);
|
|
+phy_exit:
|
|
+ phy_exit(phy);
|
|
+phy_put:
|
|
+ phy_put(phy);
|
|
+phy_out:
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
|
|
{
|
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
|
diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h
|
|
index ca0a3a5721dd7..74b4d21a498a0 100644
|
|
--- a/drivers/usb/host/xhci-mvebu.h
|
|
+++ b/drivers/usb/host/xhci-mvebu.h
|
|
@@ -12,6 +12,7 @@ struct usb_hcd;
|
|
|
|
#if IS_ENABLED(CONFIG_USB_XHCI_MVEBU)
|
|
int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd);
|
|
+int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd);
|
|
int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd);
|
|
#else
|
|
static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
|
|
@@ -19,6 +20,11 @@ static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
|
|
return 0;
|
|
}
|
|
|
|
+static inline int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
|
|
{
|
|
return 0;
|
|
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
|
|
index 52c625c023410..84cfa85442852 100644
|
|
--- a/drivers/usb/host/xhci-plat.c
|
|
+++ b/drivers/usb/host/xhci-plat.c
|
|
@@ -44,6 +44,16 @@ static void xhci_priv_plat_start(struct usb_hcd *hcd)
|
|
priv->plat_start(hcd);
|
|
}
|
|
|
|
+static int xhci_priv_plat_setup(struct usb_hcd *hcd)
|
|
+{
|
|
+ struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
|
+
|
|
+ if (!priv->plat_setup)
|
|
+ return 0;
|
|
+
|
|
+ return priv->plat_setup(hcd);
|
|
+}
|
|
+
|
|
static int xhci_priv_init_quirk(struct usb_hcd *hcd)
|
|
{
|
|
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
|
@@ -101,6 +111,7 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada = {
|
|
};
|
|
|
|
static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = {
|
|
+ .plat_setup = xhci_mvebu_a3700_plat_setup,
|
|
.init_quirk = xhci_mvebu_a3700_init_quirk,
|
|
};
|
|
|
|
@@ -163,6 +174,8 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|
struct usb_hcd *hcd;
|
|
int ret;
|
|
int irq;
|
|
+ struct xhci_plat_priv *priv = NULL;
|
|
+
|
|
|
|
if (usb_disabled())
|
|
return -ENODEV;
|
|
@@ -257,8 +270,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|
|
|
priv_match = of_device_get_match_data(&pdev->dev);
|
|
if (priv_match) {
|
|
- struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
|
-
|
|
+ priv = hcd_to_xhci_priv(hcd);
|
|
/* Just copy data for now */
|
|
if (priv_match)
|
|
*priv = *priv_match;
|
|
@@ -307,6 +319,16 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|
|
|
hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
|
|
xhci->shared_hcd->tpl_support = hcd->tpl_support;
|
|
+
|
|
+ if (priv) {
|
|
+ ret = xhci_priv_plat_setup(hcd);
|
|
+ if (ret)
|
|
+ goto disable_usb_phy;
|
|
+ }
|
|
+
|
|
+ if ((xhci->quirks & XHCI_SKIP_PHY_INIT) || (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)))
|
|
+ hcd->skip_phy_initialization = 1;
|
|
+
|
|
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
|
if (ret)
|
|
goto disable_usb_phy;
|
|
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
|
|
index 5681723fc9cd7..b7749151bdfb8 100644
|
|
--- a/drivers/usb/host/xhci-plat.h
|
|
+++ b/drivers/usb/host/xhci-plat.h
|
|
@@ -13,6 +13,7 @@
|
|
struct xhci_plat_priv {
|
|
const char *firmware_name;
|
|
unsigned long long quirks;
|
|
+ int (*plat_setup)(struct usb_hcd *);
|
|
void (*plat_start)(struct usb_hcd *);
|
|
int (*init_quirk)(struct usb_hcd *);
|
|
int (*resume_quirk)(struct usb_hcd *);
|
|
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
|
|
index 52e156c018042..900ea91fb3c6b 100644
|
|
--- a/drivers/usb/host/xhci-ring.c
|
|
+++ b/drivers/usb/host/xhci-ring.c
|
|
@@ -695,11 +695,16 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci,
|
|
dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len,
|
|
DMA_FROM_DEVICE);
|
|
/* for in tranfers we need to copy the data from bounce to sg */
|
|
- len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf,
|
|
- seg->bounce_len, seg->bounce_offs);
|
|
- if (len != seg->bounce_len)
|
|
- xhci_warn(xhci, "WARN Wrong bounce buffer read length: %zu != %d\n",
|
|
- len, seg->bounce_len);
|
|
+ if (urb->num_sgs) {
|
|
+ len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf,
|
|
+ seg->bounce_len, seg->bounce_offs);
|
|
+ if (len != seg->bounce_len)
|
|
+ xhci_warn(xhci, "WARN Wrong bounce buffer read length: %zu != %d\n",
|
|
+ len, seg->bounce_len);
|
|
+ } else {
|
|
+ memcpy(urb->transfer_buffer + seg->bounce_offs, seg->bounce_buf,
|
|
+ seg->bounce_len);
|
|
+ }
|
|
seg->bounce_len = 0;
|
|
seg->bounce_offs = 0;
|
|
}
|
|
@@ -3263,12 +3268,16 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
|
|
|
|
/* create a max max_pkt sized bounce buffer pointed to by last trb */
|
|
if (usb_urb_dir_out(urb)) {
|
|
- len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
|
|
- seg->bounce_buf, new_buff_len, enqd_len);
|
|
- if (len != new_buff_len)
|
|
- xhci_warn(xhci,
|
|
- "WARN Wrong bounce buffer write length: %zu != %d\n",
|
|
- len, new_buff_len);
|
|
+ if (urb->num_sgs) {
|
|
+ len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
|
|
+ seg->bounce_buf, new_buff_len, enqd_len);
|
|
+ if (len != new_buff_len)
|
|
+ xhci_warn(xhci, "WARN Wrong bounce buffer write length: %zu != %d\n",
|
|
+ len, new_buff_len);
|
|
+ } else {
|
|
+ memcpy(seg->bounce_buf, urb->transfer_buffer + enqd_len, new_buff_len);
|
|
+ }
|
|
+
|
|
seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
|
|
max_pkt, DMA_TO_DEVICE);
|
|
} else {
|
|
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
|
|
index 70aa3055c41e7..91330517444e7 100644
|
|
--- a/drivers/usb/host/xhci.c
|
|
+++ b/drivers/usb/host/xhci.c
|
|
@@ -2861,7 +2861,7 @@ static void xhci_check_bw_drop_ep_streams(struct xhci_hcd *xhci,
|
|
* else should be touching the xhci->devs[slot_id] structure, so we
|
|
* don't need to take the xhci->lock for manipulating that.
|
|
*/
|
|
-static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|
+int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|
{
|
|
int i;
|
|
int ret = 0;
|
|
@@ -2959,7 +2959,7 @@ command_cleanup:
|
|
return ret;
|
|
}
|
|
|
|
-static void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|
+void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|
{
|
|
struct xhci_hcd *xhci;
|
|
struct xhci_virt_device *virt_dev;
|
|
@@ -5380,6 +5380,10 @@ void xhci_init_driver(struct hc_driver *drv,
|
|
drv->reset = over->reset;
|
|
if (over->start)
|
|
drv->start = over->start;
|
|
+ if (over->check_bandwidth)
|
|
+ drv->check_bandwidth = over->check_bandwidth;
|
|
+ if (over->reset_bandwidth)
|
|
+ drv->reset_bandwidth = over->reset_bandwidth;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(xhci_init_driver);
|
|
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
|
|
index b483317bcb17b..1ad1d6e9e9979 100644
|
|
--- a/drivers/usb/host/xhci.h
|
|
+++ b/drivers/usb/host/xhci.h
|
|
@@ -1873,6 +1873,7 @@ struct xhci_hcd {
|
|
#define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
|
|
#define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
|
|
#define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
|
|
+#define XHCI_SKIP_PHY_INIT BIT_ULL(37)
|
|
#define XHCI_DISABLE_SPARSE BIT_ULL(38)
|
|
|
|
unsigned int num_active_eps;
|
|
@@ -1911,6 +1912,8 @@ struct xhci_driver_overrides {
|
|
size_t extra_priv_size;
|
|
int (*reset)(struct usb_hcd *hcd);
|
|
int (*start)(struct usb_hcd *hcd);
|
|
+ int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
|
|
+ void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
|
|
};
|
|
|
|
#define XHCI_CFC_DELAY 10
|
|
@@ -2063,6 +2066,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
|
|
void xhci_shutdown(struct usb_hcd *hcd);
|
|
void xhci_init_driver(struct hc_driver *drv,
|
|
const struct xhci_driver_overrides *over);
|
|
+int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
|
+void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
|
int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
|
|
int xhci_ext_cap_init(struct xhci_hcd *xhci);
|
|
|
|
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
|
|
index 05cdad13933b1..cfc16943979d5 100644
|
|
--- a/drivers/usb/renesas_usbhs/fifo.c
|
|
+++ b/drivers/usb/renesas_usbhs/fifo.c
|
|
@@ -126,6 +126,7 @@ struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
|
|
}
|
|
|
|
usbhs_pipe_clear_without_sequence(pipe, 0, 0);
|
|
+ usbhs_pipe_running(pipe, 0);
|
|
|
|
__usbhsf_pkt_del(pkt);
|
|
}
|
|
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
|
|
index a90801ef00554..361a2e3ccad8d 100644
|
|
--- a/drivers/usb/serial/cp210x.c
|
|
+++ b/drivers/usb/serial/cp210x.c
|
|
@@ -61,6 +61,7 @@ static const struct usb_device_id id_table[] = {
|
|
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
|
|
{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
|
|
{ USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */
|
|
+ { USB_DEVICE(0x0988, 0x0578) }, /* Teraoka AD2000 */
|
|
{ USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */
|
|
{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
|
|
{ USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
|
|
@@ -201,6 +202,7 @@ static const struct usb_device_id id_table[] = {
|
|
{ USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */
|
|
{ USB_DEVICE(0x1901, 0x0195) }, /* GE B850/B650/B450 CP2104 DP UART interface */
|
|
{ USB_DEVICE(0x1901, 0x0196) }, /* GE B850 CP2105 DP UART interface */
|
|
+ { USB_DEVICE(0x199B, 0xBA30) }, /* LORD WSDA-200-USB */
|
|
{ USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */
|
|
{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
|
|
{ USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
|
|
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
|
|
index fd41b07b5aaf1..f49eae18500cc 100644
|
|
--- a/drivers/usb/serial/option.c
|
|
+++ b/drivers/usb/serial/option.c
|
|
@@ -425,6 +425,8 @@ static void option_instat_callback(struct urb *urb);
|
|
#define CINTERION_PRODUCT_AHXX_2RMNET 0x0084
|
|
#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085
|
|
#define CINTERION_PRODUCT_CLS8 0x00b0
|
|
+#define CINTERION_PRODUCT_MV31_MBIM 0x00b3
|
|
+#define CINTERION_PRODUCT_MV31_RMNET 0x00b7
|
|
|
|
/* Olivetti products */
|
|
#define OLIVETTI_VENDOR_ID 0x0b3c
|
|
@@ -1914,6 +1916,10 @@ static const struct usb_device_id option_ids[] = {
|
|
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) },
|
|
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */
|
|
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
|
|
+ { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV31_MBIM, 0xff),
|
|
+ .driver_info = RSVD(3)},
|
|
+ { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV31_RMNET, 0xff),
|
|
+ .driver_info = RSVD(0)},
|
|
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100),
|
|
.driver_info = RSVD(4) },
|
|
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120),
|
|
diff --git a/fs/afs/main.c b/fs/afs/main.c
|
|
index c9c45d7078bd1..5cd26af2464c9 100644
|
|
--- a/fs/afs/main.c
|
|
+++ b/fs/afs/main.c
|
|
@@ -186,7 +186,7 @@ static int __init afs_init(void)
|
|
goto error_cache;
|
|
#endif
|
|
|
|
- ret = register_pernet_subsys(&afs_net_ops);
|
|
+ ret = register_pernet_device(&afs_net_ops);
|
|
if (ret < 0)
|
|
goto error_net;
|
|
|
|
@@ -206,7 +206,7 @@ static int __init afs_init(void)
|
|
error_proc:
|
|
afs_fs_exit();
|
|
error_fs:
|
|
- unregister_pernet_subsys(&afs_net_ops);
|
|
+ unregister_pernet_device(&afs_net_ops);
|
|
error_net:
|
|
#ifdef CONFIG_AFS_FSCACHE
|
|
fscache_unregister_netfs(&afs_cache_netfs);
|
|
@@ -237,7 +237,7 @@ static void __exit afs_exit(void)
|
|
|
|
proc_remove(afs_proc_symlink);
|
|
afs_fs_exit();
|
|
- unregister_pernet_subsys(&afs_net_ops);
|
|
+ unregister_pernet_device(&afs_net_ops);
|
|
#ifdef CONFIG_AFS_FSCACHE
|
|
fscache_unregister_netfs(&afs_cache_netfs);
|
|
#endif
|
|
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
|
|
index 5a35850ccb1ab..9ae9a514676c3 100644
|
|
--- a/fs/cifs/dir.c
|
|
+++ b/fs/cifs/dir.c
|
|
@@ -738,6 +738,7 @@ static int
|
|
cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
|
|
{
|
|
struct inode *inode;
|
|
+ int rc;
|
|
|
|
if (flags & LOOKUP_RCU)
|
|
return -ECHILD;
|
|
@@ -747,8 +748,25 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
|
|
if ((flags & LOOKUP_REVAL) && !CIFS_CACHE_READ(CIFS_I(inode)))
|
|
CIFS_I(inode)->time = 0; /* force reval */
|
|
|
|
- if (cifs_revalidate_dentry(direntry))
|
|
- return 0;
|
|
+ rc = cifs_revalidate_dentry(direntry);
|
|
+ if (rc) {
|
|
+ cifs_dbg(FYI, "cifs_revalidate_dentry failed with rc=%d", rc);
|
|
+ switch (rc) {
|
|
+ case -ENOENT:
|
|
+ case -ESTALE:
|
|
+ /*
|
|
+ * Those errors mean the dentry is invalid
|
|
+ * (file was deleted or recreated)
|
|
+ */
|
|
+ return 0;
|
|
+ default:
|
|
+ /*
|
|
+ * Otherwise some unexpected error happened
|
|
+ * report it as-is to VFS layer
|
|
+ */
|
|
+ return rc;
|
|
+ }
|
|
+ }
|
|
else {
|
|
/*
|
|
* If the inode wasn't known to be a dfs entry when
|
|
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
|
|
index 2482978f09486..739556e385be8 100644
|
|
--- a/fs/cifs/smb2pdu.h
|
|
+++ b/fs/cifs/smb2pdu.h
|
|
@@ -227,7 +227,7 @@ struct smb2_negotiate_req {
|
|
__le32 NegotiateContextOffset; /* SMB3.1.1 only. MBZ earlier */
|
|
__le16 NegotiateContextCount; /* SMB3.1.1 only. MBZ earlier */
|
|
__le16 Reserved2;
|
|
- __le16 Dialects[1]; /* One dialect (vers=) at a time for now */
|
|
+ __le16 Dialects[4]; /* BB expand this if autonegotiate > 4 dialects */
|
|
} __packed;
|
|
|
|
/* Dialects */
|
|
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
|
|
index 4ffbf8f965814..eab7940bfebef 100644
|
|
--- a/fs/cifs/transport.c
|
|
+++ b/fs/cifs/transport.c
|
|
@@ -659,10 +659,22 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num,
|
|
spin_lock(&server->req_lock);
|
|
if (*credits < num) {
|
|
/*
|
|
- * Return immediately if not too many requests in flight since
|
|
- * we will likely be stuck on waiting for credits.
|
|
+ * If the server is tight on resources or just gives us less
|
|
+ * credits for other reasons (e.g. requests are coming out of
|
|
+ * order and the server delays granting more credits until it
|
|
+ * processes a missing mid) and we exhausted most available
|
|
+ * credits there may be situations when we try to send
|
|
+ * a compound request but we don't have enough credits. At this
|
|
+ * point the client needs to decide if it should wait for
|
|
+ * additional credits or fail the request. If at least one
|
|
+ * request is in flight there is a high probability that the
|
|
+ * server will return enough credits to satisfy this compound
|
|
+ * request.
|
|
+ *
|
|
+ * Return immediately if no requests in flight since we will be
|
|
+ * stuck on waiting for credits.
|
|
*/
|
|
- if (server->in_flight < num - *credits) {
|
|
+ if (server->in_flight == 0) {
|
|
spin_unlock(&server->req_lock);
|
|
return -ENOTSUPP;
|
|
}
|
|
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
|
|
index 5fff7cb3582f0..cf3af2140c3d8 100644
|
|
--- a/fs/hugetlbfs/inode.c
|
|
+++ b/fs/hugetlbfs/inode.c
|
|
@@ -675,9 +675,10 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
|
|
|
|
mutex_unlock(&hugetlb_fault_mutex_table[hash]);
|
|
|
|
+ set_page_huge_active(page);
|
|
/*
|
|
* unlock_page because locked by add_to_page_cache()
|
|
- * page_put due to reference from alloc_huge_page()
|
|
+ * put_page() due to reference from alloc_huge_page()
|
|
*/
|
|
unlock_page(page);
|
|
put_page(page);
|
|
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
|
|
index 29abdb1d3b5c6..6509ec3cb3730 100644
|
|
--- a/fs/overlayfs/dir.c
|
|
+++ b/fs/overlayfs/dir.c
|
|
@@ -940,8 +940,8 @@ static char *ovl_get_redirect(struct dentry *dentry, bool abs_redirect)
|
|
|
|
buflen -= thislen;
|
|
memcpy(&buf[buflen], name, thislen);
|
|
- tmp = dget_dlock(d->d_parent);
|
|
spin_unlock(&d->d_lock);
|
|
+ tmp = dget_parent(d);
|
|
|
|
dput(d);
|
|
d = tmp;
|
|
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
|
|
index 8a03f392f3680..0e080ba5efbcc 100644
|
|
--- a/include/linux/hugetlb.h
|
|
+++ b/include/linux/hugetlb.h
|
|
@@ -590,6 +590,8 @@ static inline void huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
|
|
}
|
|
#endif
|
|
|
|
+void set_page_huge_active(struct page *page);
|
|
+
|
|
#else /* CONFIG_HUGETLB_PAGE */
|
|
struct hstate {};
|
|
|
|
diff --git a/include/linux/msi.h b/include/linux/msi.h
|
|
index 8ad679e9d9c04..d695e2eb2092d 100644
|
|
--- a/include/linux/msi.h
|
|
+++ b/include/linux/msi.h
|
|
@@ -139,6 +139,12 @@ struct msi_desc {
|
|
list_for_each_entry((desc), dev_to_msi_list((dev)), list)
|
|
#define for_each_msi_entry_safe(desc, tmp, dev) \
|
|
list_for_each_entry_safe((desc), (tmp), dev_to_msi_list((dev)), list)
|
|
+#define for_each_msi_vector(desc, __irq, dev) \
|
|
+ for_each_msi_entry((desc), (dev)) \
|
|
+ if ((desc)->irq) \
|
|
+ for (__irq = (desc)->irq; \
|
|
+ __irq < ((desc)->irq + (desc)->nvec_used); \
|
|
+ __irq++)
|
|
|
|
#ifdef CONFIG_IRQ_MSI_IOMMU
|
|
static inline const void *msi_desc_get_iommu_cookie(struct msi_desc *desc)
|
|
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
|
|
index 3d03756e10699..b2ceec7b280d4 100644
|
|
--- a/include/net/sch_generic.h
|
|
+++ b/include/net/sch_generic.h
|
|
@@ -1158,7 +1158,7 @@ static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
|
|
old = *pold;
|
|
*pold = new;
|
|
if (old != NULL)
|
|
- qdisc_tree_flush_backlog(old);
|
|
+ qdisc_purge_queue(old);
|
|
sch_tree_unlock(sch);
|
|
|
|
return old;
|
|
diff --git a/init/init_task.c b/init/init_task.c
|
|
index df7041be96fca..5d8359c44564a 100644
|
|
--- a/init/init_task.c
|
|
+++ b/init/init_task.c
|
|
@@ -171,7 +171,8 @@ struct task_struct init_task
|
|
.lockdep_recursion = 0,
|
|
#endif
|
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
|
- .ret_stack = NULL,
|
|
+ .ret_stack = NULL,
|
|
+ .tracing_graph_pause = ATOMIC_INIT(0),
|
|
#endif
|
|
#if defined(CONFIG_TRACING) && defined(CONFIG_PREEMPTION)
|
|
.trace_recursion = 0,
|
|
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
|
|
index 5a8b4dfdb1419..c2f0aa818b7af 100644
|
|
--- a/kernel/bpf/cgroup.c
|
|
+++ b/kernel/bpf/cgroup.c
|
|
@@ -1109,6 +1109,11 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
|
|
goto out;
|
|
}
|
|
|
|
+ if (ctx.optlen < 0) {
|
|
+ ret = -EFAULT;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
if (copy_from_user(ctx.optval, optval,
|
|
min(ctx.optlen, max_optlen)) != 0) {
|
|
ret = -EFAULT;
|
|
@@ -1126,7 +1131,7 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
|
|
goto out;
|
|
}
|
|
|
|
- if (ctx.optlen > max_optlen) {
|
|
+ if (ctx.optlen > max_optlen || ctx.optlen < 0) {
|
|
ret = -EFAULT;
|
|
goto out;
|
|
}
|
|
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
|
|
index eb95f6106a1ee..5d3da0db092ff 100644
|
|
--- a/kernel/irq/msi.c
|
|
+++ b/kernel/irq/msi.c
|
|
@@ -437,22 +437,22 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
|
|
|
|
can_reserve = msi_check_reservation_mode(domain, info, dev);
|
|
|
|
- for_each_msi_entry(desc, dev) {
|
|
- virq = desc->irq;
|
|
- if (desc->nvec_used == 1)
|
|
- dev_dbg(dev, "irq %d for MSI\n", virq);
|
|
- else
|
|
+ /*
|
|
+ * This flag is set by the PCI layer as we need to activate
|
|
+ * the MSI entries before the PCI layer enables MSI in the
|
|
+ * card. Otherwise the card latches a random msi message.
|
|
+ */
|
|
+ if (!(info->flags & MSI_FLAG_ACTIVATE_EARLY))
|
|
+ goto skip_activate;
|
|
+
|
|
+ for_each_msi_vector(desc, i, dev) {
|
|
+ if (desc->irq == i) {
|
|
+ virq = desc->irq;
|
|
dev_dbg(dev, "irq [%d-%d] for MSI\n",
|
|
virq, virq + desc->nvec_used - 1);
|
|
- /*
|
|
- * This flag is set by the PCI layer as we need to activate
|
|
- * the MSI entries before the PCI layer enables MSI in the
|
|
- * card. Otherwise the card latches a random msi message.
|
|
- */
|
|
- if (!(info->flags & MSI_FLAG_ACTIVATE_EARLY))
|
|
- continue;
|
|
+ }
|
|
|
|
- irq_data = irq_domain_get_irq_data(domain, desc->irq);
|
|
+ irq_data = irq_domain_get_irq_data(domain, i);
|
|
if (!can_reserve) {
|
|
irqd_clr_can_reserve(irq_data);
|
|
if (domain->flags & IRQ_DOMAIN_MSI_NOMASK_QUIRK)
|
|
@@ -463,28 +463,24 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
|
|
goto cleanup;
|
|
}
|
|
|
|
+skip_activate:
|
|
/*
|
|
* If these interrupts use reservation mode, clear the activated bit
|
|
* so request_irq() will assign the final vector.
|
|
*/
|
|
if (can_reserve) {
|
|
- for_each_msi_entry(desc, dev) {
|
|
- irq_data = irq_domain_get_irq_data(domain, desc->irq);
|
|
+ for_each_msi_vector(desc, i, dev) {
|
|
+ irq_data = irq_domain_get_irq_data(domain, i);
|
|
irqd_clr_activated(irq_data);
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
cleanup:
|
|
- for_each_msi_entry(desc, dev) {
|
|
- struct irq_data *irqd;
|
|
-
|
|
- if (desc->irq == virq)
|
|
- break;
|
|
-
|
|
- irqd = irq_domain_get_irq_data(domain, desc->irq);
|
|
- if (irqd_is_activated(irqd))
|
|
- irq_domain_deactivate_irq(irqd);
|
|
+ for_each_msi_vector(desc, i, dev) {
|
|
+ irq_data = irq_domain_get_irq_data(domain, i);
|
|
+ if (irqd_is_activated(irq_data))
|
|
+ irq_domain_deactivate_irq(irq_data);
|
|
}
|
|
msi_domain_free_irqs(domain, dev);
|
|
return ret;
|
|
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
|
|
index 283c8b01ce789..26ae92c12fc22 100644
|
|
--- a/kernel/kprobes.c
|
|
+++ b/kernel/kprobes.c
|
|
@@ -1972,6 +1972,10 @@ int register_kretprobe(struct kretprobe *rp)
|
|
if (!kprobe_on_func_entry(rp->kp.addr, rp->kp.symbol_name, rp->kp.offset))
|
|
return -EINVAL;
|
|
|
|
+ /* If only rp->kp.addr is specified, check reregistering kprobes */
|
|
+ if (rp->kp.addr && check_kprobe_rereg(&rp->kp))
|
|
+ return -EINVAL;
|
|
+
|
|
if (kretprobe_blacklist_size) {
|
|
addr = kprobe_addr(&rp->kp);
|
|
if (IS_ERR(addr))
|
|
diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
|
|
index 7950a0356042a..888cd00174fe3 100644
|
|
--- a/kernel/trace/fgraph.c
|
|
+++ b/kernel/trace/fgraph.c
|
|
@@ -367,7 +367,6 @@ static int alloc_retstack_tasklist(struct ftrace_ret_stack **ret_stack_list)
|
|
}
|
|
|
|
if (t->ret_stack == NULL) {
|
|
- atomic_set(&t->tracing_graph_pause, 0);
|
|
atomic_set(&t->trace_overrun, 0);
|
|
t->curr_ret_stack = -1;
|
|
t->curr_ret_depth = -1;
|
|
@@ -462,7 +461,6 @@ static DEFINE_PER_CPU(struct ftrace_ret_stack *, idle_ret_stack);
|
|
static void
|
|
graph_init_task(struct task_struct *t, struct ftrace_ret_stack *ret_stack)
|
|
{
|
|
- atomic_set(&t->tracing_graph_pause, 0);
|
|
atomic_set(&t->trace_overrun, 0);
|
|
t->ftrace_timestamp = 0;
|
|
/* make curr_ret_stack visible before we add the ret_stack */
|
|
diff --git a/mm/compaction.c b/mm/compaction.c
|
|
index 92470625f0b1e..88c3f6bad1aba 100644
|
|
--- a/mm/compaction.c
|
|
+++ b/mm/compaction.c
|
|
@@ -1276,7 +1276,7 @@ fast_isolate_freepages(struct compact_control *cc)
|
|
{
|
|
unsigned int limit = min(1U, freelist_scan_limit(cc) >> 1);
|
|
unsigned int nr_scanned = 0;
|
|
- unsigned long low_pfn, min_pfn, high_pfn = 0, highest = 0;
|
|
+ unsigned long low_pfn, min_pfn, highest = 0;
|
|
unsigned long nr_isolated = 0;
|
|
unsigned long distance;
|
|
struct page *page = NULL;
|
|
@@ -1321,6 +1321,7 @@ fast_isolate_freepages(struct compact_control *cc)
|
|
struct page *freepage;
|
|
unsigned long flags;
|
|
unsigned int order_scanned = 0;
|
|
+ unsigned long high_pfn = 0;
|
|
|
|
if (!area->nr_free)
|
|
continue;
|
|
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
|
|
index 11aa763a31440..7bbf419bb86d6 100644
|
|
--- a/mm/huge_memory.c
|
|
+++ b/mm/huge_memory.c
|
|
@@ -2306,7 +2306,7 @@ void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
|
|
{
|
|
spinlock_t *ptl;
|
|
struct mmu_notifier_range range;
|
|
- bool was_locked = false;
|
|
+ bool do_unlock_page = false;
|
|
pmd_t _pmd;
|
|
|
|
mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
|
|
@@ -2322,7 +2322,6 @@ void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
|
|
VM_BUG_ON(freeze && !page);
|
|
if (page) {
|
|
VM_WARN_ON_ONCE(!PageLocked(page));
|
|
- was_locked = true;
|
|
if (page != pmd_page(*pmd))
|
|
goto out;
|
|
}
|
|
@@ -2331,19 +2330,29 @@ repeat:
|
|
if (pmd_trans_huge(*pmd)) {
|
|
if (!page) {
|
|
page = pmd_page(*pmd);
|
|
- if (unlikely(!trylock_page(page))) {
|
|
- get_page(page);
|
|
- _pmd = *pmd;
|
|
- spin_unlock(ptl);
|
|
- lock_page(page);
|
|
- spin_lock(ptl);
|
|
- if (unlikely(!pmd_same(*pmd, _pmd))) {
|
|
- unlock_page(page);
|
|
+ /*
|
|
+ * An anonymous page must be locked, to ensure that a
|
|
+ * concurrent reuse_swap_page() sees stable mapcount;
|
|
+ * but reuse_swap_page() is not used on shmem or file,
|
|
+ * and page lock must not be taken when zap_pmd_range()
|
|
+ * calls __split_huge_pmd() while i_mmap_lock is held.
|
|
+ */
|
|
+ if (PageAnon(page)) {
|
|
+ if (unlikely(!trylock_page(page))) {
|
|
+ get_page(page);
|
|
+ _pmd = *pmd;
|
|
+ spin_unlock(ptl);
|
|
+ lock_page(page);
|
|
+ spin_lock(ptl);
|
|
+ if (unlikely(!pmd_same(*pmd, _pmd))) {
|
|
+ unlock_page(page);
|
|
+ put_page(page);
|
|
+ page = NULL;
|
|
+ goto repeat;
|
|
+ }
|
|
put_page(page);
|
|
- page = NULL;
|
|
- goto repeat;
|
|
}
|
|
- put_page(page);
|
|
+ do_unlock_page = true;
|
|
}
|
|
}
|
|
if (PageMlocked(page))
|
|
@@ -2353,7 +2362,7 @@ repeat:
|
|
__split_huge_pmd_locked(vma, pmd, range.start, freeze);
|
|
out:
|
|
spin_unlock(ptl);
|
|
- if (!was_locked && page)
|
|
+ if (do_unlock_page)
|
|
unlock_page(page);
|
|
/*
|
|
* No need to double call mmu_notifier->invalidate_range() callback.
|
|
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
|
|
index 3bc33fa838177..d5b03b9262d4f 100644
|
|
--- a/mm/hugetlb.c
|
|
+++ b/mm/hugetlb.c
|
|
@@ -71,6 +71,21 @@ DEFINE_SPINLOCK(hugetlb_lock);
|
|
static int num_fault_mutexes;
|
|
struct mutex *hugetlb_fault_mutex_table ____cacheline_aligned_in_smp;
|
|
|
|
+static inline bool PageHugeFreed(struct page *head)
|
|
+{
|
|
+ return page_private(head + 4) == -1UL;
|
|
+}
|
|
+
|
|
+static inline void SetPageHugeFreed(struct page *head)
|
|
+{
|
|
+ set_page_private(head + 4, -1UL);
|
|
+}
|
|
+
|
|
+static inline void ClearPageHugeFreed(struct page *head)
|
|
+{
|
|
+ set_page_private(head + 4, 0);
|
|
+}
|
|
+
|
|
/* Forward declaration */
|
|
static int hugetlb_acct_memory(struct hstate *h, long delta);
|
|
|
|
@@ -869,6 +884,7 @@ static void enqueue_huge_page(struct hstate *h, struct page *page)
|
|
list_move(&page->lru, &h->hugepage_freelists[nid]);
|
|
h->free_huge_pages++;
|
|
h->free_huge_pages_node[nid]++;
|
|
+ SetPageHugeFreed(page);
|
|
}
|
|
|
|
static struct page *dequeue_huge_page_node_exact(struct hstate *h, int nid)
|
|
@@ -886,6 +902,7 @@ static struct page *dequeue_huge_page_node_exact(struct hstate *h, int nid)
|
|
return NULL;
|
|
list_move(&page->lru, &h->hugepage_activelist);
|
|
set_page_refcounted(page);
|
|
+ ClearPageHugeFreed(page);
|
|
h->free_huge_pages--;
|
|
h->free_huge_pages_node[nid]--;
|
|
return page;
|
|
@@ -1217,12 +1234,11 @@ struct hstate *size_to_hstate(unsigned long size)
|
|
*/
|
|
bool page_huge_active(struct page *page)
|
|
{
|
|
- VM_BUG_ON_PAGE(!PageHuge(page), page);
|
|
- return PageHead(page) && PagePrivate(&page[1]);
|
|
+ return PageHeadHuge(page) && PagePrivate(&page[1]);
|
|
}
|
|
|
|
/* never called for tail page */
|
|
-static void set_page_huge_active(struct page *page)
|
|
+void set_page_huge_active(struct page *page)
|
|
{
|
|
VM_BUG_ON_PAGE(!PageHeadHuge(page), page);
|
|
SetPagePrivate(&page[1]);
|
|
@@ -1375,6 +1391,7 @@ static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
|
|
set_hugetlb_cgroup(page, NULL);
|
|
h->nr_huge_pages++;
|
|
h->nr_huge_pages_node[nid]++;
|
|
+ ClearPageHugeFreed(page);
|
|
spin_unlock(&hugetlb_lock);
|
|
}
|
|
|
|
@@ -1602,6 +1619,7 @@ int dissolve_free_huge_page(struct page *page)
|
|
{
|
|
int rc = -EBUSY;
|
|
|
|
+retry:
|
|
/* Not to disrupt normal path by vainly holding hugetlb_lock */
|
|
if (!PageHuge(page))
|
|
return 0;
|
|
@@ -1618,6 +1636,26 @@ int dissolve_free_huge_page(struct page *page)
|
|
int nid = page_to_nid(head);
|
|
if (h->free_huge_pages - h->resv_huge_pages == 0)
|
|
goto out;
|
|
+
|
|
+ /*
|
|
+ * We should make sure that the page is already on the free list
|
|
+ * when it is dissolved.
|
|
+ */
|
|
+ if (unlikely(!PageHugeFreed(head))) {
|
|
+ spin_unlock(&hugetlb_lock);
|
|
+ cond_resched();
|
|
+
|
|
+ /*
|
|
+ * Theoretically, we should return -EBUSY when we
|
|
+ * encounter this race. In fact, we have a chance
|
|
+ * to successfully dissolve the page if we do a
|
|
+ * retry. Because the race window is quite small.
|
|
+ * If we seize this opportunity, it is an optimization
|
|
+ * for increasing the success rate of dissolving page.
|
|
+ */
|
|
+ goto retry;
|
|
+ }
|
|
+
|
|
/*
|
|
* Move PageHWPoison flag from head page to the raw error page,
|
|
* which makes any subpages rather than the error page reusable.
|
|
@@ -5136,9 +5174,9 @@ bool isolate_huge_page(struct page *page, struct list_head *list)
|
|
{
|
|
bool ret = true;
|
|
|
|
- VM_BUG_ON_PAGE(!PageHead(page), page);
|
|
spin_lock(&hugetlb_lock);
|
|
- if (!page_huge_active(page) || !get_page_unless_zero(page)) {
|
|
+ if (!PageHeadHuge(page) || !page_huge_active(page) ||
|
|
+ !get_page_unless_zero(page)) {
|
|
ret = false;
|
|
goto unlock;
|
|
}
|
|
diff --git a/mm/memblock.c b/mm/memblock.c
|
|
index c4b16cae2bc9b..11f6ae37d6699 100644
|
|
--- a/mm/memblock.c
|
|
+++ b/mm/memblock.c
|
|
@@ -257,14 +257,6 @@ __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end,
|
|
*
|
|
* Find @size free area aligned to @align in the specified range and node.
|
|
*
|
|
- * When allocation direction is bottom-up, the @start should be greater
|
|
- * than the end of the kernel image. Otherwise, it will be trimmed. The
|
|
- * reason is that we want the bottom-up allocation just near the kernel
|
|
- * image so it is highly likely that the allocated memory and the kernel
|
|
- * will reside in the same node.
|
|
- *
|
|
- * If bottom-up allocation failed, will try to allocate memory top-down.
|
|
- *
|
|
* Return:
|
|
* Found address on success, 0 on failure.
|
|
*/
|
|
@@ -273,8 +265,6 @@ static phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
|
|
phys_addr_t end, int nid,
|
|
enum memblock_flags flags)
|
|
{
|
|
- phys_addr_t kernel_end, ret;
|
|
-
|
|
/* pump up @end */
|
|
if (end == MEMBLOCK_ALLOC_ACCESSIBLE ||
|
|
end == MEMBLOCK_ALLOC_KASAN)
|
|
@@ -283,40 +273,13 @@ static phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
|
|
/* avoid allocating the first page */
|
|
start = max_t(phys_addr_t, start, PAGE_SIZE);
|
|
end = max(start, end);
|
|
- kernel_end = __pa_symbol(_end);
|
|
-
|
|
- /*
|
|
- * try bottom-up allocation only when bottom-up mode
|
|
- * is set and @end is above the kernel image.
|
|
- */
|
|
- if (memblock_bottom_up() && end > kernel_end) {
|
|
- phys_addr_t bottom_up_start;
|
|
-
|
|
- /* make sure we will allocate above the kernel */
|
|
- bottom_up_start = max(start, kernel_end);
|
|
|
|
- /* ok, try bottom-up allocation first */
|
|
- ret = __memblock_find_range_bottom_up(bottom_up_start, end,
|
|
- size, align, nid, flags);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- /*
|
|
- * we always limit bottom-up allocation above the kernel,
|
|
- * but top-down allocation doesn't have the limit, so
|
|
- * retrying top-down allocation may succeed when bottom-up
|
|
- * allocation failed.
|
|
- *
|
|
- * bottom-up allocation is expected to be fail very rarely,
|
|
- * so we use WARN_ONCE() here to see the stack trace if
|
|
- * fail happens.
|
|
- */
|
|
- WARN_ONCE(IS_ENABLED(CONFIG_MEMORY_HOTREMOVE),
|
|
- "memblock: bottom-up allocation failed, memory hotremove may be affected\n");
|
|
- }
|
|
-
|
|
- return __memblock_find_range_top_down(start, end, size, align, nid,
|
|
- flags);
|
|
+ if (memblock_bottom_up())
|
|
+ return __memblock_find_range_bottom_up(start, end, size, align,
|
|
+ nid, flags);
|
|
+ else
|
|
+ return __memblock_find_range_top_down(start, end, size, align,
|
|
+ nid, flags);
|
|
}
|
|
|
|
/**
|
|
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
|
|
index 6c270fce200f4..7080d708b7d08 100644
|
|
--- a/net/core/neighbour.c
|
|
+++ b/net/core/neighbour.c
|
|
@@ -1244,13 +1244,14 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
|
|
old = neigh->nud_state;
|
|
err = -EPERM;
|
|
|
|
- if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
|
|
- (old & (NUD_NOARP | NUD_PERMANENT)))
|
|
- goto out;
|
|
if (neigh->dead) {
|
|
NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
|
|
+ new = old;
|
|
goto out;
|
|
}
|
|
+ if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
|
|
+ (old & (NUD_NOARP | NUD_PERMANENT)))
|
|
+ goto out;
|
|
|
|
ext_learn_change = neigh_update_ext_learned(neigh, flags, ¬ify);
|
|
|
|
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
|
|
index ca525cf681a4e..f64d1743b86d6 100644
|
|
--- a/net/ipv4/ip_tunnel.c
|
|
+++ b/net/ipv4/ip_tunnel.c
|
|
@@ -317,7 +317,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
|
|
}
|
|
|
|
dev->needed_headroom = t_hlen + hlen;
|
|
- mtu -= (dev->hard_header_len + t_hlen);
|
|
+ mtu -= t_hlen;
|
|
|
|
if (mtu < IPV4_MIN_MTU)
|
|
mtu = IPV4_MIN_MTU;
|
|
@@ -347,7 +347,7 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net,
|
|
nt = netdev_priv(dev);
|
|
t_hlen = nt->hlen + sizeof(struct iphdr);
|
|
dev->min_mtu = ETH_MIN_MTU;
|
|
- dev->max_mtu = IP_MAX_MTU - dev->hard_header_len - t_hlen;
|
|
+ dev->max_mtu = IP_MAX_MTU - t_hlen;
|
|
ip_tunnel_add(itn, nt);
|
|
return nt;
|
|
|
|
@@ -494,11 +494,10 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
|
|
int mtu;
|
|
|
|
tunnel_hlen = md ? tunnel_hlen : tunnel->hlen;
|
|
- pkt_size = skb->len - tunnel_hlen - dev->hard_header_len;
|
|
+ pkt_size = skb->len - tunnel_hlen;
|
|
|
|
if (df)
|
|
- mtu = dst_mtu(&rt->dst) - dev->hard_header_len
|
|
- - sizeof(struct iphdr) - tunnel_hlen;
|
|
+ mtu = dst_mtu(&rt->dst) - (sizeof(struct iphdr) + tunnel_hlen);
|
|
else
|
|
mtu = skb_valid_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
|
|
|
|
@@ -964,7 +963,7 @@ int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
|
|
{
|
|
struct ip_tunnel *tunnel = netdev_priv(dev);
|
|
int t_hlen = tunnel->hlen + sizeof(struct iphdr);
|
|
- int max_mtu = IP_MAX_MTU - dev->hard_header_len - t_hlen;
|
|
+ int max_mtu = IP_MAX_MTU - t_hlen;
|
|
|
|
if (new_mtu < ETH_MIN_MTU)
|
|
return -EINVAL;
|
|
@@ -1141,10 +1140,9 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
|
|
|
|
mtu = ip_tunnel_bind_dev(dev);
|
|
if (tb[IFLA_MTU]) {
|
|
- unsigned int max = IP_MAX_MTU - dev->hard_header_len - nt->hlen;
|
|
+ unsigned int max = IP_MAX_MTU - (nt->hlen + sizeof(struct iphdr));
|
|
|
|
- mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU,
|
|
- (unsigned int)(max - sizeof(struct iphdr)));
|
|
+ mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, max);
|
|
}
|
|
|
|
err = dev_set_mtu(dev, mtu);
|
|
diff --git a/net/lapb/lapb_out.c b/net/lapb/lapb_out.c
|
|
index 7a4d0715d1c32..a966d29c772d9 100644
|
|
--- a/net/lapb/lapb_out.c
|
|
+++ b/net/lapb/lapb_out.c
|
|
@@ -82,7 +82,8 @@ void lapb_kick(struct lapb_cb *lapb)
|
|
skb = skb_dequeue(&lapb->write_queue);
|
|
|
|
do {
|
|
- if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
|
|
+ skbn = skb_copy(skb, GFP_ATOMIC);
|
|
+ if (!skbn) {
|
|
skb_queue_head(&lapb->write_queue, skb);
|
|
break;
|
|
}
|
|
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c
|
|
index c9a8a2433e8ac..48322e45e7ddb 100644
|
|
--- a/net/mac80211/driver-ops.c
|
|
+++ b/net/mac80211/driver-ops.c
|
|
@@ -125,8 +125,11 @@ int drv_sta_state(struct ieee80211_local *local,
|
|
} else if (old_state == IEEE80211_STA_AUTH &&
|
|
new_state == IEEE80211_STA_ASSOC) {
|
|
ret = drv_sta_add(local, sdata, &sta->sta);
|
|
- if (ret == 0)
|
|
+ if (ret == 0) {
|
|
sta->uploaded = true;
|
|
+ if (rcu_access_pointer(sta->sta.rates))
|
|
+ drv_sta_rate_tbl_update(local, sdata, &sta->sta);
|
|
+ }
|
|
} else if (old_state == IEEE80211_STA_ASSOC &&
|
|
new_state == IEEE80211_STA_AUTH) {
|
|
drv_sta_remove(local, sdata, &sta->sta);
|
|
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
|
|
index b051f125d3af2..9841db84bce0a 100644
|
|
--- a/net/mac80211/rate.c
|
|
+++ b/net/mac80211/rate.c
|
|
@@ -934,7 +934,8 @@ int rate_control_set_rates(struct ieee80211_hw *hw,
|
|
if (old)
|
|
kfree_rcu(old, rcu_head);
|
|
|
|
- drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta);
|
|
+ if (sta->uploaded)
|
|
+ drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta);
|
|
|
|
ieee80211_sta_set_expected_throughput(pubsta, sta_get_expected_throughput(sta));
|
|
|
|
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
|
|
index 2921fc2767134..9bacec6653bac 100644
|
|
--- a/net/rxrpc/af_rxrpc.c
|
|
+++ b/net/rxrpc/af_rxrpc.c
|
|
@@ -976,7 +976,7 @@ static int __init af_rxrpc_init(void)
|
|
goto error_security;
|
|
}
|
|
|
|
- ret = register_pernet_subsys(&rxrpc_net_ops);
|
|
+ ret = register_pernet_device(&rxrpc_net_ops);
|
|
if (ret)
|
|
goto error_pernet;
|
|
|
|
@@ -1021,7 +1021,7 @@ error_key_type:
|
|
error_sock:
|
|
proto_unregister(&rxrpc_proto);
|
|
error_proto:
|
|
- unregister_pernet_subsys(&rxrpc_net_ops);
|
|
+ unregister_pernet_device(&rxrpc_net_ops);
|
|
error_pernet:
|
|
rxrpc_exit_security();
|
|
error_security:
|
|
@@ -1043,7 +1043,7 @@ static void __exit af_rxrpc_exit(void)
|
|
unregister_key_type(&key_type_rxrpc);
|
|
sock_unregister(PF_RXRPC);
|
|
proto_unregister(&rxrpc_proto);
|
|
- unregister_pernet_subsys(&rxrpc_net_ops);
|
|
+ unregister_pernet_device(&rxrpc_net_ops);
|
|
ASSERTCMP(atomic_read(&rxrpc_n_tx_skbs), ==, 0);
|
|
ASSERTCMP(atomic_read(&rxrpc_n_rx_skbs), ==, 0);
|
|
|