mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-26 08:41:54 +00:00
8311 lines
262 KiB
Diff
8311 lines
262 KiB
Diff
diff --git a/Documentation/x86/mds.rst b/Documentation/x86/mds.rst
|
|
index 534e9baa4e1d..5d4330be200f 100644
|
|
--- a/Documentation/x86/mds.rst
|
|
+++ b/Documentation/x86/mds.rst
|
|
@@ -142,45 +142,13 @@ Mitigation points
|
|
mds_user_clear.
|
|
|
|
The mitigation is invoked in prepare_exit_to_usermode() which covers
|
|
- most of the kernel to user space transitions. There are a few exceptions
|
|
- which are not invoking prepare_exit_to_usermode() on return to user
|
|
- space. These exceptions use the paranoid exit code.
|
|
+ all but one of the kernel to user space transitions. The exception
|
|
+ is when we return from a Non Maskable Interrupt (NMI), which is
|
|
+ handled directly in do_nmi().
|
|
|
|
- - Non Maskable Interrupt (NMI):
|
|
-
|
|
- Access to sensible data like keys, credentials in the NMI context is
|
|
- mostly theoretical: The CPU can do prefetching or execute a
|
|
- misspeculated code path and thereby fetching data which might end up
|
|
- leaking through a buffer.
|
|
-
|
|
- But for mounting other attacks the kernel stack address of the task is
|
|
- already valuable information. So in full mitigation mode, the NMI is
|
|
- mitigated on the return from do_nmi() to provide almost complete
|
|
- coverage.
|
|
-
|
|
- - Double fault (#DF):
|
|
-
|
|
- A double fault is usually fatal, but the ESPFIX workaround, which can
|
|
- be triggered from user space through modify_ldt(2) is a recoverable
|
|
- double fault. #DF uses the paranoid exit path, so explicit mitigation
|
|
- in the double fault handler is required.
|
|
-
|
|
- - Machine Check Exception (#MC):
|
|
-
|
|
- Another corner case is a #MC which hits between the CPU buffer clear
|
|
- invocation and the actual return to user. As this still is in kernel
|
|
- space it takes the paranoid exit path which does not clear the CPU
|
|
- buffers. So the #MC handler repopulates the buffers to some
|
|
- extent. Machine checks are not reliably controllable and the window is
|
|
- extremly small so mitigation would just tick a checkbox that this
|
|
- theoretical corner case is covered. To keep the amount of special
|
|
- cases small, ignore #MC.
|
|
-
|
|
- - Debug Exception (#DB):
|
|
-
|
|
- This takes the paranoid exit path only when the INT1 breakpoint is in
|
|
- kernel space. #DB on a user space address takes the regular exit path,
|
|
- so no extra mitigation required.
|
|
+ (The reason that NMI is special is that prepare_exit_to_usermode() can
|
|
+ enable IRQs. In NMI context, NMIs are blocked, and we don't want to
|
|
+ enable IRQs with NMIs blocked.)
|
|
|
|
|
|
2. C-State transition
|
|
diff --git a/Makefile b/Makefile
|
|
index 6023a9dbad59..b33f3ecf84fc 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,6 +1,6 @@
|
|
VERSION = 4
|
|
PATCHLEVEL = 4
|
|
-SUBLEVEL = 180
|
|
+SUBLEVEL = 181
|
|
EXTRAVERSION =
|
|
NAME = Blurry Fish Butt
|
|
|
|
diff --git a/arch/arm/crypto/aesbs-glue.c b/arch/arm/crypto/aesbs-glue.c
|
|
index 648d5fac9cbf..3271c836e1a1 100644
|
|
--- a/arch/arm/crypto/aesbs-glue.c
|
|
+++ b/arch/arm/crypto/aesbs-glue.c
|
|
@@ -259,6 +259,8 @@ static int aesbs_xts_encrypt(struct blkcipher_desc *desc,
|
|
|
|
blkcipher_walk_init(&walk, dst, src, nbytes);
|
|
err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
|
|
+ if (err)
|
|
+ return err;
|
|
|
|
/* generate the initial tweak */
|
|
AES_encrypt(walk.iv, walk.iv, &ctx->twkey);
|
|
@@ -283,6 +285,8 @@ static int aesbs_xts_decrypt(struct blkcipher_desc *desc,
|
|
|
|
blkcipher_walk_init(&walk, dst, src, nbytes);
|
|
err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
|
|
+ if (err)
|
|
+ return err;
|
|
|
|
/* generate the initial tweak */
|
|
AES_encrypt(walk.iv, walk.iv, &ctx->twkey);
|
|
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
|
|
index d7bef2144760..e96ddc599c30 100644
|
|
--- a/arch/arm/kvm/arm.c
|
|
+++ b/arch/arm/kvm/arm.c
|
|
@@ -744,7 +744,7 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
|
|
static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
|
|
const struct kvm_vcpu_init *init)
|
|
{
|
|
- unsigned int i;
|
|
+ unsigned int i, ret;
|
|
int phys_target = kvm_target_cpu();
|
|
|
|
if (init->target != phys_target)
|
|
@@ -779,9 +779,14 @@ static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
|
|
vcpu->arch.target = phys_target;
|
|
|
|
/* Now we know what it is, we can reset it. */
|
|
- return kvm_reset_vcpu(vcpu);
|
|
-}
|
|
+ ret = kvm_reset_vcpu(vcpu);
|
|
+ if (ret) {
|
|
+ vcpu->arch.target = -1;
|
|
+ bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES);
|
|
+ }
|
|
|
|
+ return ret;
|
|
+}
|
|
|
|
static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
|
|
struct kvm_vcpu_init *init)
|
|
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
|
|
index 111cfbf66fdb..7bfe2bd17400 100644
|
|
--- a/arch/arm/mach-exynos/firmware.c
|
|
+++ b/arch/arm/mach-exynos/firmware.c
|
|
@@ -207,6 +207,7 @@ void __init exynos_firmware_init(void)
|
|
return;
|
|
|
|
addr = of_get_address(nd, 0, NULL, NULL);
|
|
+ of_node_put(nd);
|
|
if (!addr) {
|
|
pr_err("%s: No address specified.\n", __func__);
|
|
return;
|
|
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c
|
|
index e8adb428dddb..a003833ac112 100644
|
|
--- a/arch/arm/mach-exynos/suspend.c
|
|
+++ b/arch/arm/mach-exynos/suspend.c
|
|
@@ -725,8 +725,10 @@ void __init exynos_pm_init(void)
|
|
|
|
if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
|
|
pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
|
|
+ of_node_put(np);
|
|
return;
|
|
}
|
|
+ of_node_put(np);
|
|
|
|
pm_data = (const struct exynos_pm_data *) match->data;
|
|
|
|
diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c
|
|
index b6bd7d447768..fbd6aead48e1 100644
|
|
--- a/arch/arm64/kernel/cpu_ops.c
|
|
+++ b/arch/arm64/kernel/cpu_ops.c
|
|
@@ -73,6 +73,7 @@ static const char *__init cpu_read_enable_method(int cpu)
|
|
pr_err("%s: missing enable-method property\n",
|
|
dn->full_name);
|
|
}
|
|
+ of_node_put(dn);
|
|
} else {
|
|
enable_method = acpi_get_enable_method(cpu);
|
|
if (!enable_method)
|
|
diff --git a/arch/mips/pistachio/Platform b/arch/mips/pistachio/Platform
|
|
index d80cd612df1f..c3592b374ad2 100644
|
|
--- a/arch/mips/pistachio/Platform
|
|
+++ b/arch/mips/pistachio/Platform
|
|
@@ -6,3 +6,4 @@ cflags-$(CONFIG_MACH_PISTACHIO) += \
|
|
-I$(srctree)/arch/mips/include/asm/mach-pistachio
|
|
load-$(CONFIG_MACH_PISTACHIO) += 0xffffffff80400000
|
|
zload-$(CONFIG_MACH_PISTACHIO) += 0xffffffff81000000
|
|
+all-$(CONFIG_MACH_PISTACHIO) := uImage.gz
|
|
diff --git a/arch/powerpc/boot/addnote.c b/arch/powerpc/boot/addnote.c
|
|
index 9d9f6f334d3c..3da3e2b1b51b 100644
|
|
--- a/arch/powerpc/boot/addnote.c
|
|
+++ b/arch/powerpc/boot/addnote.c
|
|
@@ -223,7 +223,11 @@ main(int ac, char **av)
|
|
PUT_16(E_PHNUM, np + 2);
|
|
|
|
/* write back */
|
|
- lseek(fd, (long) 0, SEEK_SET);
|
|
+ i = lseek(fd, (long) 0, SEEK_SET);
|
|
+ if (i < 0) {
|
|
+ perror("lseek");
|
|
+ exit(1);
|
|
+ }
|
|
i = write(fd, buf, n);
|
|
if (i < 0) {
|
|
perror("write");
|
|
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
|
|
index bb3df222ae71..215bff2b8470 100644
|
|
--- a/arch/powerpc/mm/numa.c
|
|
+++ b/arch/powerpc/mm/numa.c
|
|
@@ -1611,6 +1611,9 @@ int start_topology_update(void)
|
|
{
|
|
int rc = 0;
|
|
|
|
+ if (!topology_updates_enabled)
|
|
+ return 0;
|
|
+
|
|
if (firmware_has_feature(FW_FEATURE_PRRN)) {
|
|
if (!prrn_enabled) {
|
|
prrn_enabled = 1;
|
|
@@ -1640,6 +1643,9 @@ int stop_topology_update(void)
|
|
{
|
|
int rc = 0;
|
|
|
|
+ if (!topology_updates_enabled)
|
|
+ return 0;
|
|
+
|
|
if (prrn_enabled) {
|
|
prrn_enabled = 0;
|
|
#ifdef CONFIG_SMP
|
|
@@ -1685,11 +1691,13 @@ static ssize_t topology_write(struct file *file, const char __user *buf,
|
|
|
|
kbuf[read_len] = '\0';
|
|
|
|
- if (!strncmp(kbuf, "on", 2))
|
|
+ if (!strncmp(kbuf, "on", 2)) {
|
|
+ topology_updates_enabled = true;
|
|
start_topology_update();
|
|
- else if (!strncmp(kbuf, "off", 3))
|
|
+ } else if (!strncmp(kbuf, "off", 3)) {
|
|
stop_topology_update();
|
|
- else
|
|
+ topology_updates_enabled = false;
|
|
+ } else
|
|
return -EINVAL;
|
|
|
|
return count;
|
|
@@ -1704,9 +1712,7 @@ static const struct file_operations topology_ops = {
|
|
|
|
static int topology_update_init(void)
|
|
{
|
|
- /* Do not poll for changes if disabled at boot */
|
|
- if (topology_updates_enabled)
|
|
- start_topology_update();
|
|
+ start_topology_update();
|
|
|
|
if (!proc_create("powerpc/topology_updates", 0644, NULL, &topology_ops))
|
|
return -ENOMEM;
|
|
diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S
|
|
index fcf4d27a38fb..e09f7b440b8c 100644
|
|
--- a/arch/sparc/mm/ultra.S
|
|
+++ b/arch/sparc/mm/ultra.S
|
|
@@ -586,7 +586,7 @@ xcall_flush_tlb_kernel_range: /* 44 insns */
|
|
sub %g7, %g1, %g3
|
|
srlx %g3, 18, %g2
|
|
brnz,pn %g2, 2f
|
|
- add %g2, 1, %g2
|
|
+ sethi %hi(PAGE_SIZE), %g2
|
|
sub %g3, %g2, %g3
|
|
or %g1, 0x20, %g1 ! Nucleus
|
|
1: stxa %g0, [%g1 + %g3] ASI_DMMU_DEMAP
|
|
@@ -750,7 +750,7 @@ __cheetah_xcall_flush_tlb_kernel_range: /* 44 insns */
|
|
sub %g7, %g1, %g3
|
|
srlx %g3, 18, %g2
|
|
brnz,pn %g2, 2f
|
|
- add %g2, 1, %g2
|
|
+ sethi %hi(PAGE_SIZE), %g2
|
|
sub %g3, %g2, %g3
|
|
or %g1, 0x20, %g1 ! Nucleus
|
|
1: stxa %g0, [%g1 + %g3] ASI_DMMU_DEMAP
|
|
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
|
|
index e26560cd1844..00e0226634fa 100644
|
|
--- a/arch/x86/Makefile
|
|
+++ b/arch/x86/Makefile
|
|
@@ -47,7 +47,7 @@ export REALMODE_CFLAGS
|
|
export BITS
|
|
|
|
ifdef CONFIG_X86_NEED_RELOCS
|
|
- LDFLAGS_vmlinux := --emit-relocs
|
|
+ LDFLAGS_vmlinux := --emit-relocs --discard-none
|
|
endif
|
|
|
|
#
|
|
diff --git a/arch/x86/crypto/crct10dif-pclmul_glue.c b/arch/x86/crypto/crct10dif-pclmul_glue.c
|
|
index cd4df9322501..7bbfe7d35da7 100644
|
|
--- a/arch/x86/crypto/crct10dif-pclmul_glue.c
|
|
+++ b/arch/x86/crypto/crct10dif-pclmul_glue.c
|
|
@@ -76,15 +76,14 @@ static int chksum_final(struct shash_desc *desc, u8 *out)
|
|
return 0;
|
|
}
|
|
|
|
-static int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len,
|
|
- u8 *out)
|
|
+static int __chksum_finup(__u16 crc, const u8 *data, unsigned int len, u8 *out)
|
|
{
|
|
if (irq_fpu_usable()) {
|
|
kernel_fpu_begin();
|
|
- *(__u16 *)out = crc_t10dif_pcl(*crcp, data, len);
|
|
+ *(__u16 *)out = crc_t10dif_pcl(crc, data, len);
|
|
kernel_fpu_end();
|
|
} else
|
|
- *(__u16 *)out = crc_t10dif_generic(*crcp, data, len);
|
|
+ *(__u16 *)out = crc_t10dif_generic(crc, data, len);
|
|
return 0;
|
|
}
|
|
|
|
@@ -93,15 +92,13 @@ static int chksum_finup(struct shash_desc *desc, const u8 *data,
|
|
{
|
|
struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
|
|
|
|
- return __chksum_finup(&ctx->crc, data, len, out);
|
|
+ return __chksum_finup(ctx->crc, data, len, out);
|
|
}
|
|
|
|
static int chksum_digest(struct shash_desc *desc, const u8 *data,
|
|
unsigned int length, u8 *out)
|
|
{
|
|
- struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
|
|
-
|
|
- return __chksum_finup(&ctx->crc, data, length, out);
|
|
+ return __chksum_finup(0, data, length, out);
|
|
}
|
|
|
|
static struct shash_alg alg = {
|
|
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
|
|
index 0552884da18d..a7b9acd709db 100644
|
|
--- a/arch/x86/ia32/ia32_signal.c
|
|
+++ b/arch/x86/ia32/ia32_signal.c
|
|
@@ -60,9 +60,8 @@
|
|
} while (0)
|
|
|
|
#define RELOAD_SEG(seg) { \
|
|
- unsigned int pre = GET_SEG(seg); \
|
|
+ unsigned int pre = (seg) | 3; \
|
|
unsigned int cur = get_user_seg(seg); \
|
|
- pre |= 3; \
|
|
if (pre != cur) \
|
|
set_user_seg(seg, pre); \
|
|
}
|
|
@@ -71,6 +70,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
|
|
struct sigcontext_32 __user *sc)
|
|
{
|
|
unsigned int tmpflags, err = 0;
|
|
+ u16 gs, fs, es, ds;
|
|
void __user *buf;
|
|
u32 tmp;
|
|
|
|
@@ -78,16 +78,10 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
|
|
current->restart_block.fn = do_no_restart_syscall;
|
|
|
|
get_user_try {
|
|
- /*
|
|
- * Reload fs and gs if they have changed in the signal
|
|
- * handler. This does not handle long fs/gs base changes in
|
|
- * the handler, but does not clobber them at least in the
|
|
- * normal case.
|
|
- */
|
|
- RELOAD_SEG(gs);
|
|
- RELOAD_SEG(fs);
|
|
- RELOAD_SEG(ds);
|
|
- RELOAD_SEG(es);
|
|
+ gs = GET_SEG(gs);
|
|
+ fs = GET_SEG(fs);
|
|
+ ds = GET_SEG(ds);
|
|
+ es = GET_SEG(es);
|
|
|
|
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
|
|
COPY(dx); COPY(cx); COPY(ip); COPY(ax);
|
|
@@ -105,6 +99,17 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
|
|
buf = compat_ptr(tmp);
|
|
} get_user_catch(err);
|
|
|
|
+ /*
|
|
+ * Reload fs and gs if they have changed in the signal
|
|
+ * handler. This does not handle long fs/gs base changes in
|
|
+ * the handler, but does not clobber them at least in the
|
|
+ * normal case.
|
|
+ */
|
|
+ RELOAD_SEG(gs);
|
|
+ RELOAD_SEG(fs);
|
|
+ RELOAD_SEG(ds);
|
|
+ RELOAD_SEG(es);
|
|
+
|
|
err |= fpu__restore_sig(buf, 1);
|
|
|
|
force_iret();
|
|
diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c
|
|
index 206d0b90a3ab..e39d7197f9fb 100644
|
|
--- a/arch/x86/kernel/irq_64.c
|
|
+++ b/arch/x86/kernel/irq_64.c
|
|
@@ -25,9 +25,18 @@ int sysctl_panic_on_stackoverflow;
|
|
/*
|
|
* Probabilistic stack overflow check:
|
|
*
|
|
- * Only check the stack in process context, because everything else
|
|
- * runs on the big interrupt stacks. Checking reliably is too expensive,
|
|
- * so we just check from interrupts.
|
|
+ * Regular device interrupts can enter on the following stacks:
|
|
+ *
|
|
+ * - User stack
|
|
+ *
|
|
+ * - Kernel task stack
|
|
+ *
|
|
+ * - Interrupt stack if a device driver reenables interrupts
|
|
+ * which should only happen in really old drivers.
|
|
+ *
|
|
+ * - Debug IST stack
|
|
+ *
|
|
+ * All other contexts are invalid.
|
|
*/
|
|
static inline void stack_overflow_check(struct pt_regs *regs)
|
|
{
|
|
@@ -53,8 +62,8 @@ static inline void stack_overflow_check(struct pt_regs *regs)
|
|
return;
|
|
|
|
oist = this_cpu_ptr(&orig_ist);
|
|
- estack_top = (u64)oist->ist[0] - EXCEPTION_STKSZ + STACK_TOP_MARGIN;
|
|
- estack_bottom = (u64)oist->ist[N_EXCEPTION_STACKS - 1];
|
|
+ estack_bottom = (u64)oist->ist[DEBUG_STACK];
|
|
+ estack_top = estack_bottom - DEBUG_STKSZ + STACK_TOP_MARGIN;
|
|
if (regs->sp >= estack_top && regs->sp <= estack_bottom)
|
|
return;
|
|
|
|
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
|
|
index 6223929fc621..8c73bf1492b8 100644
|
|
--- a/arch/x86/kernel/traps.c
|
|
+++ b/arch/x86/kernel/traps.c
|
|
@@ -61,7 +61,6 @@
|
|
#include <asm/alternative.h>
|
|
#include <asm/fpu/xstate.h>
|
|
#include <asm/trace/mpx.h>
|
|
-#include <asm/nospec-branch.h>
|
|
#include <asm/mpx.h>
|
|
#include <asm/vm86.h>
|
|
|
|
@@ -338,13 +337,6 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
|
|
regs->ip = (unsigned long)general_protection;
|
|
regs->sp = (unsigned long)&normal_regs->orig_ax;
|
|
|
|
- /*
|
|
- * This situation can be triggered by userspace via
|
|
- * modify_ldt(2) and the return does not take the regular
|
|
- * user space exit, so a CPU buffer clear is required when
|
|
- * MDS mitigation is enabled.
|
|
- */
|
|
- mds_user_clear_cpu_buffers();
|
|
return;
|
|
}
|
|
#endif
|
|
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
|
|
index d830a0d60ba4..516d8b1562c8 100644
|
|
--- a/arch/x86/kvm/x86.c
|
|
+++ b/arch/x86/kvm/x86.c
|
|
@@ -990,11 +990,8 @@ static u32 emulated_msrs[] = {
|
|
|
|
static unsigned num_emulated_msrs;
|
|
|
|
-bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
|
|
+static bool __kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
|
|
{
|
|
- if (efer & efer_reserved_bits)
|
|
- return false;
|
|
-
|
|
if (efer & EFER_FFXSR) {
|
|
struct kvm_cpuid_entry2 *feat;
|
|
|
|
@@ -1012,19 +1009,33 @@ bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
|
|
}
|
|
|
|
return true;
|
|
+
|
|
+}
|
|
+bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
|
|
+{
|
|
+ if (efer & efer_reserved_bits)
|
|
+ return false;
|
|
+
|
|
+ return __kvm_valid_efer(vcpu, efer);
|
|
}
|
|
EXPORT_SYMBOL_GPL(kvm_valid_efer);
|
|
|
|
-static int set_efer(struct kvm_vcpu *vcpu, u64 efer)
|
|
+static int set_efer(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|
{
|
|
u64 old_efer = vcpu->arch.efer;
|
|
+ u64 efer = msr_info->data;
|
|
|
|
- if (!kvm_valid_efer(vcpu, efer))
|
|
+ if (efer & efer_reserved_bits)
|
|
return 1;
|
|
|
|
- if (is_paging(vcpu)
|
|
- && (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME))
|
|
- return 1;
|
|
+ if (!msr_info->host_initiated) {
|
|
+ if (!__kvm_valid_efer(vcpu, efer))
|
|
+ return 1;
|
|
+
|
|
+ if (is_paging(vcpu) &&
|
|
+ (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME))
|
|
+ return 1;
|
|
+ }
|
|
|
|
efer &= ~EFER_LMA;
|
|
efer |= vcpu->arch.efer & EFER_LMA;
|
|
@@ -2055,7 +2066,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|
break;
|
|
|
|
case MSR_EFER:
|
|
- return set_efer(vcpu, data);
|
|
+ return set_efer(vcpu, msr_info);
|
|
case MSR_K7_HWCR:
|
|
data &= ~(u64)0x40; /* ignore flush filter disable */
|
|
data &= ~(u64)0x100; /* ignore ignne emulation enable */
|
|
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
|
|
index c4dffae5d939..462c5c30b9a2 100644
|
|
--- a/arch/x86/mm/fault.c
|
|
+++ b/arch/x86/mm/fault.c
|
|
@@ -373,8 +373,6 @@ static noinline int vmalloc_fault(unsigned long address)
|
|
if (!(address >= VMALLOC_START && address < VMALLOC_END))
|
|
return -1;
|
|
|
|
- WARN_ON_ONCE(in_nmi());
|
|
-
|
|
/*
|
|
* Copy kernel mappings over when needed. This can also
|
|
* happen within a race in page table update. In the later
|
|
diff --git a/crypto/chacha20poly1305.c b/crypto/chacha20poly1305.c
|
|
index 0214600ba071..6c4724222e3a 100644
|
|
--- a/crypto/chacha20poly1305.c
|
|
+++ b/crypto/chacha20poly1305.c
|
|
@@ -637,8 +637,8 @@ static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb,
|
|
|
|
err = -ENAMETOOLONG;
|
|
if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
|
|
- "%s(%s,%s)", name, chacha_name,
|
|
- poly_name) >= CRYPTO_MAX_ALG_NAME)
|
|
+ "%s(%s,%s)", name, chacha->cra_name,
|
|
+ poly->cra_name) >= CRYPTO_MAX_ALG_NAME)
|
|
goto out_drop_chacha;
|
|
if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
|
|
"%s(%s,%s)", name, chacha->cra_driver_name,
|
|
diff --git a/crypto/crct10dif_generic.c b/crypto/crct10dif_generic.c
|
|
index c1229614c7e3..eed577714975 100644
|
|
--- a/crypto/crct10dif_generic.c
|
|
+++ b/crypto/crct10dif_generic.c
|
|
@@ -65,10 +65,9 @@ static int chksum_final(struct shash_desc *desc, u8 *out)
|
|
return 0;
|
|
}
|
|
|
|
-static int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len,
|
|
- u8 *out)
|
|
+static int __chksum_finup(__u16 crc, const u8 *data, unsigned int len, u8 *out)
|
|
{
|
|
- *(__u16 *)out = crc_t10dif_generic(*crcp, data, len);
|
|
+ *(__u16 *)out = crc_t10dif_generic(crc, data, len);
|
|
return 0;
|
|
}
|
|
|
|
@@ -77,15 +76,13 @@ static int chksum_finup(struct shash_desc *desc, const u8 *data,
|
|
{
|
|
struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
|
|
|
|
- return __chksum_finup(&ctx->crc, data, len, out);
|
|
+ return __chksum_finup(ctx->crc, data, len, out);
|
|
}
|
|
|
|
static int chksum_digest(struct shash_desc *desc, const u8 *data,
|
|
unsigned int length, u8 *out)
|
|
{
|
|
- struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
|
|
-
|
|
- return __chksum_finup(&ctx->crc, data, length, out);
|
|
+ return __chksum_finup(0, data, length, out);
|
|
}
|
|
|
|
static struct shash_alg alg = {
|
|
diff --git a/crypto/gcm.c b/crypto/gcm.c
|
|
index 0a12c09d7cb2..9d3bffc0238f 100644
|
|
--- a/crypto/gcm.c
|
|
+++ b/crypto/gcm.c
|
|
@@ -616,7 +616,6 @@ static void crypto_gcm_free(struct aead_instance *inst)
|
|
|
|
static int crypto_gcm_create_common(struct crypto_template *tmpl,
|
|
struct rtattr **tb,
|
|
- const char *full_name,
|
|
const char *ctr_name,
|
|
const char *ghash_name)
|
|
{
|
|
@@ -657,7 +656,8 @@ static int crypto_gcm_create_common(struct crypto_template *tmpl,
|
|
goto err_free_inst;
|
|
|
|
err = -EINVAL;
|
|
- if (ghash->digestsize != 16)
|
|
+ if (strcmp(ghash->base.cra_name, "ghash") != 0 ||
|
|
+ ghash->digestsize != 16)
|
|
goto err_drop_ghash;
|
|
|
|
crypto_set_skcipher_spawn(&ctx->ctr, aead_crypto_instance(inst));
|
|
@@ -669,24 +669,24 @@ static int crypto_gcm_create_common(struct crypto_template *tmpl,
|
|
|
|
ctr = crypto_skcipher_spawn_alg(&ctx->ctr);
|
|
|
|
- /* We only support 16-byte blocks. */
|
|
- if (ctr->cra_ablkcipher.ivsize != 16)
|
|
- goto out_put_ctr;
|
|
-
|
|
- /* Not a stream cipher? */
|
|
+ /* The skcipher algorithm must be CTR mode, using 16-byte blocks. */
|
|
err = -EINVAL;
|
|
- if (ctr->cra_blocksize != 1)
|
|
+ if (strncmp(ctr->cra_name, "ctr(", 4) != 0 ||
|
|
+ ctr->cra_ablkcipher.ivsize != 16 ||
|
|
+ ctr->cra_blocksize != 1)
|
|
goto out_put_ctr;
|
|
|
|
err = -ENAMETOOLONG;
|
|
+ if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
|
|
+ "gcm(%s", ctr->cra_name + 4) >= CRYPTO_MAX_ALG_NAME)
|
|
+ goto out_put_ctr;
|
|
+
|
|
if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
|
|
"gcm_base(%s,%s)", ctr->cra_driver_name,
|
|
ghash_alg->cra_driver_name) >=
|
|
CRYPTO_MAX_ALG_NAME)
|
|
goto out_put_ctr;
|
|
|
|
- memcpy(inst->alg.base.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
|
|
-
|
|
inst->alg.base.cra_flags = (ghash->base.cra_flags | ctr->cra_flags) &
|
|
CRYPTO_ALG_ASYNC;
|
|
inst->alg.base.cra_priority = (ghash->base.cra_priority +
|
|
@@ -727,7 +727,6 @@ static int crypto_gcm_create(struct crypto_template *tmpl, struct rtattr **tb)
|
|
{
|
|
const char *cipher_name;
|
|
char ctr_name[CRYPTO_MAX_ALG_NAME];
|
|
- char full_name[CRYPTO_MAX_ALG_NAME];
|
|
|
|
cipher_name = crypto_attr_alg_name(tb[1]);
|
|
if (IS_ERR(cipher_name))
|
|
@@ -737,12 +736,7 @@ static int crypto_gcm_create(struct crypto_template *tmpl, struct rtattr **tb)
|
|
CRYPTO_MAX_ALG_NAME)
|
|
return -ENAMETOOLONG;
|
|
|
|
- if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >=
|
|
- CRYPTO_MAX_ALG_NAME)
|
|
- return -ENAMETOOLONG;
|
|
-
|
|
- return crypto_gcm_create_common(tmpl, tb, full_name,
|
|
- ctr_name, "ghash");
|
|
+ return crypto_gcm_create_common(tmpl, tb, ctr_name, "ghash");
|
|
}
|
|
|
|
static struct crypto_template crypto_gcm_tmpl = {
|
|
@@ -756,7 +750,6 @@ static int crypto_gcm_base_create(struct crypto_template *tmpl,
|
|
{
|
|
const char *ctr_name;
|
|
const char *ghash_name;
|
|
- char full_name[CRYPTO_MAX_ALG_NAME];
|
|
|
|
ctr_name = crypto_attr_alg_name(tb[1]);
|
|
if (IS_ERR(ctr_name))
|
|
@@ -766,12 +759,7 @@ static int crypto_gcm_base_create(struct crypto_template *tmpl,
|
|
if (IS_ERR(ghash_name))
|
|
return PTR_ERR(ghash_name);
|
|
|
|
- if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s,%s)",
|
|
- ctr_name, ghash_name) >= CRYPTO_MAX_ALG_NAME)
|
|
- return -ENAMETOOLONG;
|
|
-
|
|
- return crypto_gcm_create_common(tmpl, tb, full_name,
|
|
- ctr_name, ghash_name);
|
|
+ return crypto_gcm_create_common(tmpl, tb, ctr_name, ghash_name);
|
|
}
|
|
|
|
static struct crypto_template crypto_gcm_base_tmpl = {
|
|
diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c
|
|
index d7da0eea5622..319d9962552e 100644
|
|
--- a/crypto/salsa20_generic.c
|
|
+++ b/crypto/salsa20_generic.c
|
|
@@ -186,7 +186,7 @@ static int encrypt(struct blkcipher_desc *desc,
|
|
blkcipher_walk_init(&walk, dst, src, nbytes);
|
|
err = blkcipher_walk_virt_block(desc, &walk, 64);
|
|
|
|
- salsa20_ivsetup(ctx, walk.iv);
|
|
+ salsa20_ivsetup(ctx, desc->info);
|
|
|
|
while (walk.nbytes >= 64) {
|
|
salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
|
|
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
|
|
index 05409141ec07..8efdb823826c 100644
|
|
--- a/drivers/base/power/main.c
|
|
+++ b/drivers/base/power/main.c
|
|
@@ -1378,6 +1378,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
|
if (dev->power.syscore)
|
|
goto Complete;
|
|
|
|
+ /* Avoid direct_complete to let wakeup_path propagate. */
|
|
+ if (device_may_wakeup(dev) || dev->power.wakeup_path)
|
|
+ dev->power.direct_complete = false;
|
|
+
|
|
if (dev->power.direct_complete) {
|
|
if (pm_runtime_status_suspended(dev)) {
|
|
pm_runtime_disable(dev);
|
|
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
|
|
index b2da2382d544..67d23ed2d1a0 100644
|
|
--- a/drivers/char/ipmi/ipmi_ssif.c
|
|
+++ b/drivers/char/ipmi/ipmi_ssif.c
|
|
@@ -695,12 +695,16 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
|
/* End of read */
|
|
len = ssif_info->multi_len;
|
|
data = ssif_info->data;
|
|
- } else if (blocknum != ssif_info->multi_pos) {
|
|
+ } else if (blocknum + 1 != ssif_info->multi_pos) {
|
|
/*
|
|
* Out of sequence block, just abort. Block
|
|
* numbers start at zero for the second block,
|
|
* but multi_pos starts at one, so the +1.
|
|
*/
|
|
+ if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
|
|
+ dev_dbg(&ssif_info->client->dev,
|
|
+ "Received message out of sequence, expected %u, got %u\n",
|
|
+ ssif_info->multi_pos - 1, blocknum);
|
|
result = -EIO;
|
|
} else {
|
|
ssif_inc_stat(ssif_info, received_message_parts);
|
|
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
|
|
index 2aca689061e1..df9eab91c2d2 100644
|
|
--- a/drivers/char/virtio_console.c
|
|
+++ b/drivers/char/virtio_console.c
|
|
@@ -76,7 +76,7 @@ struct ports_driver_data {
|
|
/* All the console devices handled by this driver */
|
|
struct list_head consoles;
|
|
};
|
|
-static struct ports_driver_data pdrvdata;
|
|
+static struct ports_driver_data pdrvdata = { .next_vtermno = 1};
|
|
|
|
static DEFINE_SPINLOCK(pdrvdata_lock);
|
|
static DECLARE_COMPLETION(early_console_added);
|
|
@@ -1419,6 +1419,7 @@ static int add_port(struct ports_device *portdev, u32 id)
|
|
port->async_queue = NULL;
|
|
|
|
port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
|
|
+ port->cons.vtermno = 0;
|
|
|
|
port->host_connected = port->guest_connected = false;
|
|
port->stats = (struct port_stats) { 0 };
|
|
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
|
|
index d6d4ecb88e94..311f6e62264f 100644
|
|
--- a/drivers/clk/tegra/clk-pll.c
|
|
+++ b/drivers/clk/tegra/clk-pll.c
|
|
@@ -492,8 +492,8 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,
|
|
pll_override_writel(val, params->pmc_divp_reg, pll);
|
|
|
|
val = pll_override_readl(params->pmc_divnm_reg, pll);
|
|
- val &= ~(divm_mask(pll) << div_nmp->override_divm_shift) |
|
|
- ~(divn_mask(pll) << div_nmp->override_divn_shift);
|
|
+ val &= ~((divm_mask(pll) << div_nmp->override_divm_shift) |
|
|
+ (divn_mask(pll) << div_nmp->override_divn_shift));
|
|
val |= (cfg->m << div_nmp->override_divm_shift) |
|
|
(cfg->n << div_nmp->override_divn_shift);
|
|
pll_override_writel(val, params->pmc_divnm_reg, pll);
|
|
diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c
|
|
index 35dd4d7ffee0..58c933f48300 100644
|
|
--- a/drivers/cpufreq/pasemi-cpufreq.c
|
|
+++ b/drivers/cpufreq/pasemi-cpufreq.c
|
|
@@ -146,6 +146,7 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|
|
|
cpu = of_get_cpu_node(policy->cpu, NULL);
|
|
|
|
+ of_node_put(cpu);
|
|
if (!cpu)
|
|
goto out;
|
|
|
|
diff --git a/drivers/cpufreq/pmac32-cpufreq.c b/drivers/cpufreq/pmac32-cpufreq.c
|
|
index 1f49d97a70ea..14928e0dc326 100644
|
|
--- a/drivers/cpufreq/pmac32-cpufreq.c
|
|
+++ b/drivers/cpufreq/pmac32-cpufreq.c
|
|
@@ -549,6 +549,7 @@ static int pmac_cpufreq_init_7447A(struct device_node *cpunode)
|
|
volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
|
|
if (volt_gpio_np)
|
|
voltage_gpio = read_gpio(volt_gpio_np);
|
|
+ of_node_put(volt_gpio_np);
|
|
if (!voltage_gpio){
|
|
printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n");
|
|
return 1;
|
|
@@ -585,6 +586,7 @@ static int pmac_cpufreq_init_750FX(struct device_node *cpunode)
|
|
if (volt_gpio_np)
|
|
voltage_gpio = read_gpio(volt_gpio_np);
|
|
|
|
+ of_node_put(volt_gpio_np);
|
|
pvr = mfspr(SPRN_PVR);
|
|
has_cpu_l2lve = !((pvr & 0xf00) == 0x100);
|
|
|
|
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c
|
|
index 5a4c5a639f61..2eaeebcc93af 100644
|
|
--- a/drivers/cpufreq/ppc_cbe_cpufreq.c
|
|
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
|
|
@@ -86,6 +86,7 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|
if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
|
|
!cbe_get_cpu_mic_tm_regs(policy->cpu)) {
|
|
pr_info("invalid CBE regs pointers for cpufreq\n");
|
|
+ of_node_put(cpu);
|
|
return -EINVAL;
|
|
}
|
|
|
|
diff --git a/drivers/crypto/vmx/aesp8-ppc.pl b/drivers/crypto/vmx/aesp8-ppc.pl
|
|
index 228053921b3f..4277fdd037bb 100644
|
|
--- a/drivers/crypto/vmx/aesp8-ppc.pl
|
|
+++ b/drivers/crypto/vmx/aesp8-ppc.pl
|
|
@@ -1298,7 +1298,7 @@ Loop_ctr32_enc:
|
|
addi $idx,$idx,16
|
|
bdnz Loop_ctr32_enc
|
|
|
|
- vadduwm $ivec,$ivec,$one
|
|
+ vadduqm $ivec,$ivec,$one
|
|
vmr $dat,$inptail
|
|
lvx $inptail,0,$inp
|
|
addi $inp,$inp,16
|
|
@@ -1795,7 +1795,7 @@ Lctr32_enc8x_three:
|
|
stvx_u $out1,$x10,$out
|
|
stvx_u $out2,$x20,$out
|
|
addi $out,$out,0x30
|
|
- b Lcbc_dec8x_done
|
|
+ b Lctr32_enc8x_done
|
|
|
|
.align 5
|
|
Lctr32_enc8x_two:
|
|
@@ -1807,7 +1807,7 @@ Lctr32_enc8x_two:
|
|
stvx_u $out0,$x00,$out
|
|
stvx_u $out1,$x10,$out
|
|
addi $out,$out,0x20
|
|
- b Lcbc_dec8x_done
|
|
+ b Lctr32_enc8x_done
|
|
|
|
.align 5
|
|
Lctr32_enc8x_one:
|
|
diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c
|
|
index 84b9389bf1ed..d6b68cf7bba7 100644
|
|
--- a/drivers/crypto/vmx/ghash.c
|
|
+++ b/drivers/crypto/vmx/ghash.c
|
|
@@ -1,22 +1,14 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
/**
|
|
* GHASH routines supporting VMX instructions on the Power 8
|
|
*
|
|
- * Copyright (C) 2015 International Business Machines Inc.
|
|
- *
|
|
- * This program is free software; you can redistribute it and/or modify
|
|
- * it under the terms of the GNU General Public License as published by
|
|
- * the Free Software Foundation; version 2 only.
|
|
- *
|
|
- * This program is distributed in the hope that it will be useful,
|
|
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
- * GNU General Public License for more details.
|
|
- *
|
|
- * You should have received a copy of the GNU General Public License
|
|
- * along with this program; if not, write to the Free Software
|
|
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
+ * Copyright (C) 2015, 2019 International Business Machines Inc.
|
|
*
|
|
* Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com>
|
|
+ *
|
|
+ * Extended by Daniel Axtens <dja@axtens.net> to replace the fallback
|
|
+ * mechanism. The new approach is based on arm64 code, which is:
|
|
+ * Copyright (C) 2014 - 2018 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
@@ -39,71 +31,25 @@ void gcm_ghash_p8(u64 Xi[2], const u128 htable[16],
|
|
const u8 *in, size_t len);
|
|
|
|
struct p8_ghash_ctx {
|
|
+ /* key used by vector asm */
|
|
u128 htable[16];
|
|
- struct crypto_shash *fallback;
|
|
+ /* key used by software fallback */
|
|
+ be128 key;
|
|
};
|
|
|
|
struct p8_ghash_desc_ctx {
|
|
u64 shash[2];
|
|
u8 buffer[GHASH_DIGEST_SIZE];
|
|
int bytes;
|
|
- struct shash_desc fallback_desc;
|
|
};
|
|
|
|
-static int p8_ghash_init_tfm(struct crypto_tfm *tfm)
|
|
-{
|
|
- const char *alg = "ghash-generic";
|
|
- struct crypto_shash *fallback;
|
|
- struct crypto_shash *shash_tfm = __crypto_shash_cast(tfm);
|
|
- struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm);
|
|
-
|
|
- fallback = crypto_alloc_shash(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
|
|
- if (IS_ERR(fallback)) {
|
|
- printk(KERN_ERR
|
|
- "Failed to allocate transformation for '%s': %ld\n",
|
|
- alg, PTR_ERR(fallback));
|
|
- return PTR_ERR(fallback);
|
|
- }
|
|
-
|
|
- crypto_shash_set_flags(fallback,
|
|
- crypto_shash_get_flags((struct crypto_shash
|
|
- *) tfm));
|
|
-
|
|
- /* Check if the descsize defined in the algorithm is still enough. */
|
|
- if (shash_tfm->descsize < sizeof(struct p8_ghash_desc_ctx)
|
|
- + crypto_shash_descsize(fallback)) {
|
|
- printk(KERN_ERR
|
|
- "Desc size of the fallback implementation (%s) does not match the expected value: %lu vs %u\n",
|
|
- alg,
|
|
- shash_tfm->descsize - sizeof(struct p8_ghash_desc_ctx),
|
|
- crypto_shash_descsize(fallback));
|
|
- return -EINVAL;
|
|
- }
|
|
- ctx->fallback = fallback;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void p8_ghash_exit_tfm(struct crypto_tfm *tfm)
|
|
-{
|
|
- struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm);
|
|
-
|
|
- if (ctx->fallback) {
|
|
- crypto_free_shash(ctx->fallback);
|
|
- ctx->fallback = NULL;
|
|
- }
|
|
-}
|
|
-
|
|
static int p8_ghash_init(struct shash_desc *desc)
|
|
{
|
|
- struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
|
|
struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
|
|
|
|
dctx->bytes = 0;
|
|
memset(dctx->shash, 0, GHASH_DIGEST_SIZE);
|
|
- dctx->fallback_desc.tfm = ctx->fallback;
|
|
- dctx->fallback_desc.flags = desc->flags;
|
|
- return crypto_shash_init(&dctx->fallback_desc);
|
|
+ return 0;
|
|
}
|
|
|
|
static int p8_ghash_setkey(struct crypto_shash *tfm, const u8 *key,
|
|
@@ -122,7 +68,53 @@ static int p8_ghash_setkey(struct crypto_shash *tfm, const u8 *key,
|
|
gcm_init_p8(ctx->htable, (const u64 *) key);
|
|
pagefault_enable();
|
|
preempt_enable();
|
|
- return crypto_shash_setkey(ctx->fallback, key, keylen);
|
|
+
|
|
+ memcpy(&ctx->key, key, GHASH_BLOCK_SIZE);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline void __ghash_block(struct p8_ghash_ctx *ctx,
|
|
+ struct p8_ghash_desc_ctx *dctx)
|
|
+{
|
|
+ if (!IN_INTERRUPT) {
|
|
+ preempt_disable();
|
|
+ pagefault_disable();
|
|
+ enable_kernel_altivec();
|
|
+ enable_kernel_vsx();
|
|
+ enable_kernel_fp();
|
|
+ gcm_ghash_p8(dctx->shash, ctx->htable,
|
|
+ dctx->buffer, GHASH_DIGEST_SIZE);
|
|
+ pagefault_enable();
|
|
+ preempt_enable();
|
|
+ } else {
|
|
+ crypto_xor((u8 *)dctx->shash, dctx->buffer, GHASH_BLOCK_SIZE);
|
|
+ gf128mul_lle((be128 *)dctx->shash, &ctx->key);
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline void __ghash_blocks(struct p8_ghash_ctx *ctx,
|
|
+ struct p8_ghash_desc_ctx *dctx,
|
|
+ const u8 *src, unsigned int srclen)
|
|
+{
|
|
+ if (!IN_INTERRUPT) {
|
|
+ preempt_disable();
|
|
+ pagefault_disable();
|
|
+ enable_kernel_altivec();
|
|
+ enable_kernel_vsx();
|
|
+ enable_kernel_fp();
|
|
+ gcm_ghash_p8(dctx->shash, ctx->htable,
|
|
+ src, srclen);
|
|
+ pagefault_enable();
|
|
+ preempt_enable();
|
|
+ } else {
|
|
+ while (srclen >= GHASH_BLOCK_SIZE) {
|
|
+ crypto_xor((u8 *)dctx->shash, src, GHASH_BLOCK_SIZE);
|
|
+ gf128mul_lle((be128 *)dctx->shash, &ctx->key);
|
|
+ srclen -= GHASH_BLOCK_SIZE;
|
|
+ src += GHASH_BLOCK_SIZE;
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
static int p8_ghash_update(struct shash_desc *desc,
|
|
@@ -132,51 +124,33 @@ static int p8_ghash_update(struct shash_desc *desc,
|
|
struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
|
|
struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
|
|
|
|
- if (IN_INTERRUPT) {
|
|
- return crypto_shash_update(&dctx->fallback_desc, src,
|
|
- srclen);
|
|
- } else {
|
|
- if (dctx->bytes) {
|
|
- if (dctx->bytes + srclen < GHASH_DIGEST_SIZE) {
|
|
- memcpy(dctx->buffer + dctx->bytes, src,
|
|
- srclen);
|
|
- dctx->bytes += srclen;
|
|
- return 0;
|
|
- }
|
|
+ if (dctx->bytes) {
|
|
+ if (dctx->bytes + srclen < GHASH_DIGEST_SIZE) {
|
|
memcpy(dctx->buffer + dctx->bytes, src,
|
|
- GHASH_DIGEST_SIZE - dctx->bytes);
|
|
- preempt_disable();
|
|
- pagefault_disable();
|
|
- enable_kernel_altivec();
|
|
- enable_kernel_vsx();
|
|
- enable_kernel_fp();
|
|
- gcm_ghash_p8(dctx->shash, ctx->htable,
|
|
- dctx->buffer, GHASH_DIGEST_SIZE);
|
|
- pagefault_enable();
|
|
- preempt_enable();
|
|
- src += GHASH_DIGEST_SIZE - dctx->bytes;
|
|
- srclen -= GHASH_DIGEST_SIZE - dctx->bytes;
|
|
- dctx->bytes = 0;
|
|
- }
|
|
- len = srclen & ~(GHASH_DIGEST_SIZE - 1);
|
|
- if (len) {
|
|
- preempt_disable();
|
|
- pagefault_disable();
|
|
- enable_kernel_altivec();
|
|
- enable_kernel_vsx();
|
|
- enable_kernel_fp();
|
|
- gcm_ghash_p8(dctx->shash, ctx->htable, src, len);
|
|
- pagefault_enable();
|
|
- preempt_enable();
|
|
- src += len;
|
|
- srclen -= len;
|
|
- }
|
|
- if (srclen) {
|
|
- memcpy(dctx->buffer, src, srclen);
|
|
- dctx->bytes = srclen;
|
|
+ srclen);
|
|
+ dctx->bytes += srclen;
|
|
+ return 0;
|
|
}
|
|
- return 0;
|
|
+ memcpy(dctx->buffer + dctx->bytes, src,
|
|
+ GHASH_DIGEST_SIZE - dctx->bytes);
|
|
+
|
|
+ __ghash_block(ctx, dctx);
|
|
+
|
|
+ src += GHASH_DIGEST_SIZE - dctx->bytes;
|
|
+ srclen -= GHASH_DIGEST_SIZE - dctx->bytes;
|
|
+ dctx->bytes = 0;
|
|
+ }
|
|
+ len = srclen & ~(GHASH_DIGEST_SIZE - 1);
|
|
+ if (len) {
|
|
+ __ghash_blocks(ctx, dctx, src, len);
|
|
+ src += len;
|
|
+ srclen -= len;
|
|
}
|
|
+ if (srclen) {
|
|
+ memcpy(dctx->buffer, src, srclen);
|
|
+ dctx->bytes = srclen;
|
|
+ }
|
|
+ return 0;
|
|
}
|
|
|
|
static int p8_ghash_final(struct shash_desc *desc, u8 *out)
|
|
@@ -185,26 +159,14 @@ static int p8_ghash_final(struct shash_desc *desc, u8 *out)
|
|
struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
|
|
struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
|
|
|
|
- if (IN_INTERRUPT) {
|
|
- return crypto_shash_final(&dctx->fallback_desc, out);
|
|
- } else {
|
|
- if (dctx->bytes) {
|
|
- for (i = dctx->bytes; i < GHASH_DIGEST_SIZE; i++)
|
|
- dctx->buffer[i] = 0;
|
|
- preempt_disable();
|
|
- pagefault_disable();
|
|
- enable_kernel_altivec();
|
|
- enable_kernel_vsx();
|
|
- enable_kernel_fp();
|
|
- gcm_ghash_p8(dctx->shash, ctx->htable,
|
|
- dctx->buffer, GHASH_DIGEST_SIZE);
|
|
- pagefault_enable();
|
|
- preempt_enable();
|
|
- dctx->bytes = 0;
|
|
- }
|
|
- memcpy(out, dctx->shash, GHASH_DIGEST_SIZE);
|
|
- return 0;
|
|
+ if (dctx->bytes) {
|
|
+ for (i = dctx->bytes; i < GHASH_DIGEST_SIZE; i++)
|
|
+ dctx->buffer[i] = 0;
|
|
+ __ghash_block(ctx, dctx);
|
|
+ dctx->bytes = 0;
|
|
}
|
|
+ memcpy(out, dctx->shash, GHASH_DIGEST_SIZE);
|
|
+ return 0;
|
|
}
|
|
|
|
struct shash_alg p8_ghash_alg = {
|
|
@@ -219,11 +181,9 @@ struct shash_alg p8_ghash_alg = {
|
|
.cra_name = "ghash",
|
|
.cra_driver_name = "p8_ghash",
|
|
.cra_priority = 1000,
|
|
- .cra_flags = CRYPTO_ALG_TYPE_SHASH | CRYPTO_ALG_NEED_FALLBACK,
|
|
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
|
|
.cra_blocksize = GHASH_BLOCK_SIZE,
|
|
.cra_ctxsize = sizeof(struct p8_ghash_ctx),
|
|
.cra_module = THIS_MODULE,
|
|
- .cra_init = p8_ghash_init_tfm,
|
|
- .cra_exit = p8_ghash_exit_tfm,
|
|
},
|
|
};
|
|
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
|
|
index af24c5bf32d6..8aa3ccf42e55 100644
|
|
--- a/drivers/dma/at_xdmac.c
|
|
+++ b/drivers/dma/at_xdmac.c
|
|
@@ -1608,7 +1608,11 @@ static void at_xdmac_tasklet(unsigned long data)
|
|
struct at_xdmac_desc,
|
|
xfer_node);
|
|
dev_vdbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc);
|
|
- BUG_ON(!desc->active_xfer);
|
|
+ if (!desc->active_xfer) {
|
|
+ dev_err(chan2dev(&atchan->chan), "Xfer not active: exiting");
|
|
+ spin_unlock_bh(&atchan->lock);
|
|
+ return;
|
|
+ }
|
|
|
|
txd = &desc->tx_dma_desc;
|
|
|
|
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
|
|
index e4890dd4fefd..38fb212e58ee 100644
|
|
--- a/drivers/extcon/extcon-arizona.c
|
|
+++ b/drivers/extcon/extcon-arizona.c
|
|
@@ -1616,6 +1616,16 @@ static int arizona_extcon_remove(struct platform_device *pdev)
|
|
struct arizona_extcon_info *info = platform_get_drvdata(pdev);
|
|
struct arizona *arizona = info->arizona;
|
|
int jack_irq_rise, jack_irq_fall;
|
|
+ bool change;
|
|
+
|
|
+ regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
|
+ ARIZONA_MICD_ENA, 0,
|
|
+ &change);
|
|
+
|
|
+ if (change) {
|
|
+ regulator_disable(info->micvdd);
|
|
+ pm_runtime_put(info->dev);
|
|
+ }
|
|
|
|
gpiod_put(info->micd_pol_gpio);
|
|
|
|
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
|
|
index 211069b2b951..010fe3fc5ecf 100644
|
|
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
|
|
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
|
|
@@ -620,6 +620,9 @@ void cdv_intel_lvds_init(struct drm_device *dev,
|
|
int pipe;
|
|
u8 pin;
|
|
|
|
+ if (!dev_priv->lvds_enabled_in_vbt)
|
|
+ return;
|
|
+
|
|
pin = GMBUS_PORT_PANEL;
|
|
if (!lvds_is_present_in_vbt(dev, &pin)) {
|
|
DRM_DEBUG_KMS("LVDS is not present in VBT\n");
|
|
diff --git a/drivers/gpu/drm/gma500/intel_bios.c b/drivers/gpu/drm/gma500/intel_bios.c
|
|
index 63bde4e86c6a..e019ea271ffc 100644
|
|
--- a/drivers/gpu/drm/gma500/intel_bios.c
|
|
+++ b/drivers/gpu/drm/gma500/intel_bios.c
|
|
@@ -436,6 +436,9 @@ parse_driver_features(struct drm_psb_private *dev_priv,
|
|
if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
|
|
dev_priv->edp.support = 1;
|
|
|
|
+ dev_priv->lvds_enabled_in_vbt = driver->lvds_config != 0;
|
|
+ DRM_DEBUG_KMS("LVDS VBT config bits: 0x%x\n", driver->lvds_config);
|
|
+
|
|
/* This bit means to use 96Mhz for DPLL_A or not */
|
|
if (driver->primary_lfp_id)
|
|
dev_priv->dplla_96mhz = true;
|
|
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
|
|
index e21726ecac32..4c7cc8a5edbd 100644
|
|
--- a/drivers/gpu/drm/gma500/psb_drv.h
|
|
+++ b/drivers/gpu/drm/gma500/psb_drv.h
|
|
@@ -536,6 +536,7 @@ struct drm_psb_private {
|
|
int lvds_ssc_freq;
|
|
bool is_lvds_on;
|
|
bool is_mipi_on;
|
|
+ bool lvds_enabled_in_vbt;
|
|
u32 mipi_ctrl_display;
|
|
|
|
unsigned int core_freq;
|
|
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
|
|
index 6b6224dbd5bb..943eb2971c3e 100644
|
|
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
|
|
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
|
|
@@ -37,6 +37,7 @@ struct nvkm_i2c_bus {
|
|
struct mutex mutex;
|
|
struct list_head head;
|
|
struct i2c_adapter i2c;
|
|
+ u8 enabled;
|
|
};
|
|
|
|
int nvkm_i2c_bus_acquire(struct nvkm_i2c_bus *);
|
|
@@ -56,6 +57,7 @@ struct nvkm_i2c_aux {
|
|
struct mutex mutex;
|
|
struct list_head head;
|
|
struct i2c_adapter i2c;
|
|
+ u8 enabled;
|
|
|
|
u32 intr;
|
|
};
|
|
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
|
|
index f0851d57df2f..f89692cb2bc7 100644
|
|
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
|
|
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
|
|
@@ -105,9 +105,15 @@ nvkm_i2c_aux_acquire(struct nvkm_i2c_aux *aux)
|
|
{
|
|
struct nvkm_i2c_pad *pad = aux->pad;
|
|
int ret;
|
|
+
|
|
AUX_TRACE(aux, "acquire");
|
|
mutex_lock(&aux->mutex);
|
|
- ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX);
|
|
+
|
|
+ if (aux->enabled)
|
|
+ ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX);
|
|
+ else
|
|
+ ret = -EIO;
|
|
+
|
|
if (ret)
|
|
mutex_unlock(&aux->mutex);
|
|
return ret;
|
|
@@ -141,6 +147,24 @@ nvkm_i2c_aux_del(struct nvkm_i2c_aux **paux)
|
|
}
|
|
}
|
|
|
|
+void
|
|
+nvkm_i2c_aux_init(struct nvkm_i2c_aux *aux)
|
|
+{
|
|
+ AUX_TRACE(aux, "init");
|
|
+ mutex_lock(&aux->mutex);
|
|
+ aux->enabled = true;
|
|
+ mutex_unlock(&aux->mutex);
|
|
+}
|
|
+
|
|
+void
|
|
+nvkm_i2c_aux_fini(struct nvkm_i2c_aux *aux)
|
|
+{
|
|
+ AUX_TRACE(aux, "fini");
|
|
+ mutex_lock(&aux->mutex);
|
|
+ aux->enabled = false;
|
|
+ mutex_unlock(&aux->mutex);
|
|
+}
|
|
+
|
|
int
|
|
nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func,
|
|
struct nvkm_i2c_pad *pad, int id,
|
|
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h
|
|
index 35a892e4a4c3..04885c097a32 100644
|
|
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h
|
|
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h
|
|
@@ -14,6 +14,8 @@ int nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *,
|
|
int nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *,
|
|
int id, struct nvkm_i2c_aux **);
|
|
void nvkm_i2c_aux_del(struct nvkm_i2c_aux **);
|
|
+void nvkm_i2c_aux_init(struct nvkm_i2c_aux *);
|
|
+void nvkm_i2c_aux_fini(struct nvkm_i2c_aux *);
|
|
int nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *, bool retry, u8 type,
|
|
u32 addr, u8 *data, u8 size);
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
|
|
index 243a71ff0a0d..2acc5cbcb6fb 100644
|
|
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
|
|
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
|
|
@@ -160,8 +160,18 @@ nvkm_i2c_fini(struct nvkm_subdev *subdev, bool suspend)
|
|
{
|
|
struct nvkm_i2c *i2c = nvkm_i2c(subdev);
|
|
struct nvkm_i2c_pad *pad;
|
|
+ struct nvkm_i2c_bus *bus;
|
|
+ struct nvkm_i2c_aux *aux;
|
|
u32 mask;
|
|
|
|
+ list_for_each_entry(aux, &i2c->aux, head) {
|
|
+ nvkm_i2c_aux_fini(aux);
|
|
+ }
|
|
+
|
|
+ list_for_each_entry(bus, &i2c->bus, head) {
|
|
+ nvkm_i2c_bus_fini(bus);
|
|
+ }
|
|
+
|
|
if ((mask = (1 << i2c->func->aux) - 1), i2c->func->aux_stat) {
|
|
i2c->func->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
|
|
i2c->func->aux_stat(i2c, &mask, &mask, &mask, &mask);
|
|
@@ -180,6 +190,7 @@ nvkm_i2c_init(struct nvkm_subdev *subdev)
|
|
struct nvkm_i2c *i2c = nvkm_i2c(subdev);
|
|
struct nvkm_i2c_bus *bus;
|
|
struct nvkm_i2c_pad *pad;
|
|
+ struct nvkm_i2c_aux *aux;
|
|
|
|
list_for_each_entry(pad, &i2c->pad, head) {
|
|
nvkm_i2c_pad_init(pad);
|
|
@@ -189,6 +200,10 @@ nvkm_i2c_init(struct nvkm_subdev *subdev)
|
|
nvkm_i2c_bus_init(bus);
|
|
}
|
|
|
|
+ list_for_each_entry(aux, &i2c->aux, head) {
|
|
+ nvkm_i2c_aux_init(aux);
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c
|
|
index 807a2b67bd64..ed50cc3736b9 100644
|
|
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c
|
|
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c
|
|
@@ -110,6 +110,19 @@ nvkm_i2c_bus_init(struct nvkm_i2c_bus *bus)
|
|
BUS_TRACE(bus, "init");
|
|
if (bus->func->init)
|
|
bus->func->init(bus);
|
|
+
|
|
+ mutex_lock(&bus->mutex);
|
|
+ bus->enabled = true;
|
|
+ mutex_unlock(&bus->mutex);
|
|
+}
|
|
+
|
|
+void
|
|
+nvkm_i2c_bus_fini(struct nvkm_i2c_bus *bus)
|
|
+{
|
|
+ BUS_TRACE(bus, "fini");
|
|
+ mutex_lock(&bus->mutex);
|
|
+ bus->enabled = false;
|
|
+ mutex_unlock(&bus->mutex);
|
|
}
|
|
|
|
void
|
|
@@ -126,9 +139,15 @@ nvkm_i2c_bus_acquire(struct nvkm_i2c_bus *bus)
|
|
{
|
|
struct nvkm_i2c_pad *pad = bus->pad;
|
|
int ret;
|
|
+
|
|
BUS_TRACE(bus, "acquire");
|
|
mutex_lock(&bus->mutex);
|
|
- ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_I2C);
|
|
+
|
|
+ if (bus->enabled)
|
|
+ ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_I2C);
|
|
+ else
|
|
+ ret = -EIO;
|
|
+
|
|
if (ret)
|
|
mutex_unlock(&bus->mutex);
|
|
return ret;
|
|
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h
|
|
index e1be14c23e54..2fdb1b8e7164 100644
|
|
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h
|
|
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h
|
|
@@ -17,6 +17,7 @@ int nvkm_i2c_bus_new_(const struct nvkm_i2c_bus_func *, struct nvkm_i2c_pad *,
|
|
int id, struct nvkm_i2c_bus **);
|
|
void nvkm_i2c_bus_del(struct nvkm_i2c_bus **);
|
|
void nvkm_i2c_bus_init(struct nvkm_i2c_bus *);
|
|
+void nvkm_i2c_bus_fini(struct nvkm_i2c_bus *);
|
|
|
|
int nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *, struct i2c_msg *, int);
|
|
|
|
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
|
|
index 4564ecf71181..9b2b41d683de 100644
|
|
--- a/drivers/hid/hid-core.c
|
|
+++ b/drivers/hid/hid-core.c
|
|
@@ -200,13 +200,14 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
|
|
* Add a usage to the temporary parser table.
|
|
*/
|
|
|
|
-static int hid_add_usage(struct hid_parser *parser, unsigned usage)
|
|
+static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size)
|
|
{
|
|
if (parser->local.usage_index >= HID_MAX_USAGES) {
|
|
hid_err(parser->device, "usage index exceeded\n");
|
|
return -1;
|
|
}
|
|
parser->local.usage[parser->local.usage_index] = usage;
|
|
+ parser->local.usage_size[parser->local.usage_index] = size;
|
|
parser->local.collection_index[parser->local.usage_index] =
|
|
parser->collection_stack_ptr ?
|
|
parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
|
|
@@ -463,10 +464,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
|
|
return 0;
|
|
}
|
|
|
|
- if (item->size <= 2)
|
|
- data = (parser->global.usage_page << 16) + data;
|
|
-
|
|
- return hid_add_usage(parser, data);
|
|
+ return hid_add_usage(parser, data, item->size);
|
|
|
|
case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
|
|
|
|
@@ -475,9 +473,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
|
|
return 0;
|
|
}
|
|
|
|
- if (item->size <= 2)
|
|
- data = (parser->global.usage_page << 16) + data;
|
|
-
|
|
parser->local.usage_minimum = data;
|
|
return 0;
|
|
|
|
@@ -488,9 +483,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
|
|
return 0;
|
|
}
|
|
|
|
- if (item->size <= 2)
|
|
- data = (parser->global.usage_page << 16) + data;
|
|
-
|
|
count = data - parser->local.usage_minimum;
|
|
if (count + parser->local.usage_index >= HID_MAX_USAGES) {
|
|
/*
|
|
@@ -510,7 +502,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
|
|
}
|
|
|
|
for (n = parser->local.usage_minimum; n <= data; n++)
|
|
- if (hid_add_usage(parser, n)) {
|
|
+ if (hid_add_usage(parser, n, item->size)) {
|
|
dbg_hid("hid_add_usage failed\n");
|
|
return -1;
|
|
}
|
|
@@ -524,6 +516,22 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+ * Concatenate Usage Pages into Usages where relevant:
|
|
+ * As per specification, 6.2.2.8: "When the parser encounters a main item it
|
|
+ * concatenates the last declared Usage Page with a Usage to form a complete
|
|
+ * usage value."
|
|
+ */
|
|
+
|
|
+static void hid_concatenate_usage_page(struct hid_parser *parser)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < parser->local.usage_index; i++)
|
|
+ if (parser->local.usage_size[i] <= 2)
|
|
+ parser->local.usage[i] += parser->global.usage_page << 16;
|
|
+}
|
|
+
|
|
/*
|
|
* Process a main item.
|
|
*/
|
|
@@ -533,6 +541,8 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
|
|
__u32 data;
|
|
int ret;
|
|
|
|
+ hid_concatenate_usage_page(parser);
|
|
+
|
|
data = item_udata(item);
|
|
|
|
switch (item->tag) {
|
|
@@ -746,6 +756,8 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
|
|
__u32 data;
|
|
int i;
|
|
|
|
+ hid_concatenate_usage_page(parser);
|
|
+
|
|
data = item_udata(item);
|
|
|
|
switch (item->tag) {
|
|
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
|
|
index 5fd97860aec4..3666e5064d0d 100644
|
|
--- a/drivers/hid/hid-logitech-hidpp.c
|
|
+++ b/drivers/hid/hid-logitech-hidpp.c
|
|
@@ -414,13 +414,16 @@ static int hidpp_root_get_feature(struct hidpp_device *hidpp, u16 feature,
|
|
|
|
static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
|
|
{
|
|
+ const u8 ping_byte = 0x5a;
|
|
+ u8 ping_data[3] = { 0, 0, ping_byte };
|
|
struct hidpp_report response;
|
|
int ret;
|
|
|
|
- ret = hidpp_send_fap_command_sync(hidpp,
|
|
+ ret = hidpp_send_rap_command_sync(hidpp,
|
|
+ REPORT_ID_HIDPP_SHORT,
|
|
HIDPP_PAGE_ROOT_IDX,
|
|
CMD_ROOT_GET_PROTOCOL_VERSION,
|
|
- NULL, 0, &response);
|
|
+ ping_data, sizeof(ping_data), &response);
|
|
|
|
if (ret == HIDPP_ERROR_INVALID_SUBID) {
|
|
hidpp->protocol_major = 1;
|
|
@@ -440,8 +443,14 @@ static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- hidpp->protocol_major = response.fap.params[0];
|
|
- hidpp->protocol_minor = response.fap.params[1];
|
|
+ if (response.rap.params[2] != ping_byte) {
|
|
+ hid_err(hidpp->hid_dev, "%s: ping mismatch 0x%02x != 0x%02x\n",
|
|
+ __func__, response.rap.params[2], ping_byte);
|
|
+ return -EPROTO;
|
|
+ }
|
|
+
|
|
+ hidpp->protocol_major = response.rap.params[0];
|
|
+ hidpp->protocol_minor = response.rap.params[1];
|
|
|
|
return ret;
|
|
}
|
|
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
|
|
index facd05cda26d..e8c089886427 100644
|
|
--- a/drivers/hwmon/f71805f.c
|
|
+++ b/drivers/hwmon/f71805f.c
|
|
@@ -96,17 +96,23 @@ superio_select(int base, int ld)
|
|
outb(ld, base + 1);
|
|
}
|
|
|
|
-static inline void
|
|
+static inline int
|
|
superio_enter(int base)
|
|
{
|
|
+ if (!request_muxed_region(base, 2, DRVNAME))
|
|
+ return -EBUSY;
|
|
+
|
|
outb(0x87, base);
|
|
outb(0x87, base);
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
static inline void
|
|
superio_exit(int base)
|
|
{
|
|
outb(0xaa, base);
|
|
+ release_region(base, 2);
|
|
}
|
|
|
|
/*
|
|
@@ -1561,7 +1567,7 @@ exit:
|
|
static int __init f71805f_find(int sioaddr, unsigned short *address,
|
|
struct f71805f_sio_data *sio_data)
|
|
{
|
|
- int err = -ENODEV;
|
|
+ int err;
|
|
u16 devid;
|
|
|
|
static const char * const names[] = {
|
|
@@ -1569,8 +1575,11 @@ static int __init f71805f_find(int sioaddr, unsigned short *address,
|
|
"F71872F/FG or F71806F/FG",
|
|
};
|
|
|
|
- superio_enter(sioaddr);
|
|
+ err = superio_enter(sioaddr);
|
|
+ if (err)
|
|
+ return err;
|
|
|
|
+ err = -ENODEV;
|
|
devid = superio_inw(sioaddr, SIO_REG_MANID);
|
|
if (devid != SIO_FINTEK_ID)
|
|
goto exit;
|
|
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
|
|
index cb9fdd37bd0d..2b5b8c3de8fc 100644
|
|
--- a/drivers/hwmon/pc87427.c
|
|
+++ b/drivers/hwmon/pc87427.c
|
|
@@ -106,6 +106,13 @@ static const char *logdev_str[2] = { DRVNAME " FMC", DRVNAME " HMC" };
|
|
#define LD_IN 1
|
|
#define LD_TEMP 1
|
|
|
|
+static inline int superio_enter(int sioaddr)
|
|
+{
|
|
+ if (!request_muxed_region(sioaddr, 2, DRVNAME))
|
|
+ return -EBUSY;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static inline void superio_outb(int sioaddr, int reg, int val)
|
|
{
|
|
outb(reg, sioaddr);
|
|
@@ -122,6 +129,7 @@ static inline void superio_exit(int sioaddr)
|
|
{
|
|
outb(0x02, sioaddr);
|
|
outb(0x02, sioaddr + 1);
|
|
+ release_region(sioaddr, 2);
|
|
}
|
|
|
|
/*
|
|
@@ -1220,7 +1228,11 @@ static int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data)
|
|
{
|
|
u16 val;
|
|
u8 cfg, cfg_b;
|
|
- int i, err = 0;
|
|
+ int i, err;
|
|
+
|
|
+ err = superio_enter(sioaddr);
|
|
+ if (err)
|
|
+ return err;
|
|
|
|
/* Identify device */
|
|
val = force_id ? force_id : superio_inb(sioaddr, SIOREG_DEVID);
|
|
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
|
|
index 6bd200756560..cbdb5c4991ae 100644
|
|
--- a/drivers/hwmon/smsc47b397.c
|
|
+++ b/drivers/hwmon/smsc47b397.c
|
|
@@ -72,14 +72,19 @@ static inline void superio_select(int ld)
|
|
superio_outb(0x07, ld);
|
|
}
|
|
|
|
-static inline void superio_enter(void)
|
|
+static inline int superio_enter(void)
|
|
{
|
|
+ if (!request_muxed_region(REG, 2, DRVNAME))
|
|
+ return -EBUSY;
|
|
+
|
|
outb(0x55, REG);
|
|
+ return 0;
|
|
}
|
|
|
|
static inline void superio_exit(void)
|
|
{
|
|
outb(0xAA, REG);
|
|
+ release_region(REG, 2);
|
|
}
|
|
|
|
#define SUPERIO_REG_DEVID 0x20
|
|
@@ -300,8 +305,12 @@ static int __init smsc47b397_find(void)
|
|
u8 id, rev;
|
|
char *name;
|
|
unsigned short addr;
|
|
+ int err;
|
|
+
|
|
+ err = superio_enter();
|
|
+ if (err)
|
|
+ return err;
|
|
|
|
- superio_enter();
|
|
id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
|
|
|
|
switch (id) {
|
|
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
|
|
index 5d323186d2c1..d24df0c50bea 100644
|
|
--- a/drivers/hwmon/smsc47m1.c
|
|
+++ b/drivers/hwmon/smsc47m1.c
|
|
@@ -73,16 +73,21 @@ superio_inb(int reg)
|
|
/* logical device for fans is 0x0A */
|
|
#define superio_select() superio_outb(0x07, 0x0A)
|
|
|
|
-static inline void
|
|
+static inline int
|
|
superio_enter(void)
|
|
{
|
|
+ if (!request_muxed_region(REG, 2, DRVNAME))
|
|
+ return -EBUSY;
|
|
+
|
|
outb(0x55, REG);
|
|
+ return 0;
|
|
}
|
|
|
|
static inline void
|
|
superio_exit(void)
|
|
{
|
|
outb(0xAA, REG);
|
|
+ release_region(REG, 2);
|
|
}
|
|
|
|
#define SUPERIO_REG_ACT 0x30
|
|
@@ -531,8 +536,12 @@ static int __init smsc47m1_find(struct smsc47m1_sio_data *sio_data)
|
|
{
|
|
u8 val;
|
|
unsigned short addr;
|
|
+ int err;
|
|
+
|
|
+ err = superio_enter();
|
|
+ if (err)
|
|
+ return err;
|
|
|
|
- superio_enter();
|
|
val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
|
|
|
|
/*
|
|
@@ -608,13 +617,14 @@ static int __init smsc47m1_find(struct smsc47m1_sio_data *sio_data)
|
|
static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
|
|
{
|
|
if ((sio_data->activate & 0x01) == 0) {
|
|
- superio_enter();
|
|
- superio_select();
|
|
-
|
|
- pr_info("Disabling device\n");
|
|
- superio_outb(SUPERIO_REG_ACT, sio_data->activate);
|
|
-
|
|
- superio_exit();
|
|
+ if (!superio_enter()) {
|
|
+ superio_select();
|
|
+ pr_info("Disabling device\n");
|
|
+ superio_outb(SUPERIO_REG_ACT, sio_data->activate);
|
|
+ superio_exit();
|
|
+ } else {
|
|
+ pr_warn("Failed to disable device\n");
|
|
+ }
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
|
|
index 3a6bfa51cb94..95d5e8ec8b7f 100644
|
|
--- a/drivers/hwmon/vt1211.c
|
|
+++ b/drivers/hwmon/vt1211.c
|
|
@@ -226,15 +226,21 @@ static inline void superio_select(int sio_cip, int ldn)
|
|
outb(ldn, sio_cip + 1);
|
|
}
|
|
|
|
-static inline void superio_enter(int sio_cip)
|
|
+static inline int superio_enter(int sio_cip)
|
|
{
|
|
+ if (!request_muxed_region(sio_cip, 2, DRVNAME))
|
|
+ return -EBUSY;
|
|
+
|
|
outb(0x87, sio_cip);
|
|
outb(0x87, sio_cip);
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
static inline void superio_exit(int sio_cip)
|
|
{
|
|
outb(0xaa, sio_cip);
|
|
+ release_region(sio_cip, 2);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
@@ -1282,11 +1288,14 @@ EXIT:
|
|
|
|
static int __init vt1211_find(int sio_cip, unsigned short *address)
|
|
{
|
|
- int err = -ENODEV;
|
|
+ int err;
|
|
int devid;
|
|
|
|
- superio_enter(sio_cip);
|
|
+ err = superio_enter(sio_cip);
|
|
+ if (err)
|
|
+ return err;
|
|
|
|
+ err = -ENODEV;
|
|
devid = force_id ? force_id : superio_inb(sio_cip, SIO_VT1211_DEVID);
|
|
if (devid != SIO_VT1211_ID)
|
|
goto EXIT;
|
|
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
|
|
index 9d9e47eb0842..7d5c53a1abe4 100644
|
|
--- a/drivers/hwtracing/intel_th/msu.c
|
|
+++ b/drivers/hwtracing/intel_th/msu.c
|
|
@@ -90,6 +90,7 @@ struct msc_iter {
|
|
* @reg_base: register window base address
|
|
* @thdev: intel_th_device pointer
|
|
* @win_list: list of windows in multiblock mode
|
|
+ * @single_sgt: single mode buffer
|
|
* @nr_pages: total number of pages allocated for this buffer
|
|
* @single_sz: amount of data in single mode
|
|
* @single_wrap: single mode wrap occurred
|
|
@@ -110,6 +111,7 @@ struct msc {
|
|
struct intel_th_device *thdev;
|
|
|
|
struct list_head win_list;
|
|
+ struct sg_table single_sgt;
|
|
unsigned long nr_pages;
|
|
unsigned long single_sz;
|
|
unsigned int single_wrap : 1;
|
|
@@ -610,22 +612,45 @@ static void intel_th_msc_deactivate(struct intel_th_device *thdev)
|
|
*/
|
|
static int msc_buffer_contig_alloc(struct msc *msc, unsigned long size)
|
|
{
|
|
+ unsigned long nr_pages = size >> PAGE_SHIFT;
|
|
unsigned int order = get_order(size);
|
|
struct page *page;
|
|
+ int ret;
|
|
|
|
if (!size)
|
|
return 0;
|
|
|
|
+ ret = sg_alloc_table(&msc->single_sgt, 1, GFP_KERNEL);
|
|
+ if (ret)
|
|
+ goto err_out;
|
|
+
|
|
+ ret = -ENOMEM;
|
|
page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
|
|
if (!page)
|
|
- return -ENOMEM;
|
|
+ goto err_free_sgt;
|
|
|
|
split_page(page, order);
|
|
- msc->nr_pages = size >> PAGE_SHIFT;
|
|
+ sg_set_buf(msc->single_sgt.sgl, page_address(page), size);
|
|
+
|
|
+ ret = dma_map_sg(msc_dev(msc)->parent->parent, msc->single_sgt.sgl, 1,
|
|
+ DMA_FROM_DEVICE);
|
|
+ if (ret < 0)
|
|
+ goto err_free_pages;
|
|
+
|
|
+ msc->nr_pages = nr_pages;
|
|
msc->base = page_address(page);
|
|
- msc->base_addr = page_to_phys(page);
|
|
+ msc->base_addr = sg_dma_address(msc->single_sgt.sgl);
|
|
|
|
return 0;
|
|
+
|
|
+err_free_pages:
|
|
+ __free_pages(page, order);
|
|
+
|
|
+err_free_sgt:
|
|
+ sg_free_table(&msc->single_sgt);
|
|
+
|
|
+err_out:
|
|
+ return ret;
|
|
}
|
|
|
|
/**
|
|
@@ -636,6 +661,10 @@ static void msc_buffer_contig_free(struct msc *msc)
|
|
{
|
|
unsigned long off;
|
|
|
|
+ dma_unmap_sg(msc_dev(msc)->parent->parent, msc->single_sgt.sgl,
|
|
+ 1, DMA_FROM_DEVICE);
|
|
+ sg_free_table(&msc->single_sgt);
|
|
+
|
|
for (off = 0; off < msc->nr_pages << PAGE_SHIFT; off += PAGE_SIZE) {
|
|
struct page *page = virt_to_page(msc->base + off);
|
|
|
|
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
|
|
index b6cc841de79d..e880702a3784 100644
|
|
--- a/drivers/hwtracing/stm/core.c
|
|
+++ b/drivers/hwtracing/stm/core.c
|
|
@@ -210,8 +210,8 @@ stm_output_disclaim(struct stm_device *stm, struct stm_output *output)
|
|
bitmap_release_region(&master->chan_map[0], output->channel,
|
|
ilog2(output->nr_chans));
|
|
|
|
- output->nr_chans = 0;
|
|
master->nr_free += output->nr_chans;
|
|
+ output->nr_chans = 0;
|
|
}
|
|
|
|
/*
|
|
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
|
|
index a1d072ecb717..30f200ad6b97 100644
|
|
--- a/drivers/iio/adc/ad_sigma_delta.c
|
|
+++ b/drivers/iio/adc/ad_sigma_delta.c
|
|
@@ -62,7 +62,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
|
|
struct spi_transfer t = {
|
|
.tx_buf = data,
|
|
.len = size + 1,
|
|
- .cs_change = sigma_delta->bus_locked,
|
|
+ .cs_change = sigma_delta->keep_cs_asserted,
|
|
};
|
|
struct spi_message m;
|
|
int ret;
|
|
@@ -217,6 +217,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
|
|
|
|
spi_bus_lock(sigma_delta->spi->master);
|
|
sigma_delta->bus_locked = true;
|
|
+ sigma_delta->keep_cs_asserted = true;
|
|
reinit_completion(&sigma_delta->completion);
|
|
|
|
ret = ad_sigma_delta_set_mode(sigma_delta, mode);
|
|
@@ -234,9 +235,10 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
|
|
ret = 0;
|
|
}
|
|
out:
|
|
+ sigma_delta->keep_cs_asserted = false;
|
|
+ ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
|
sigma_delta->bus_locked = false;
|
|
spi_bus_unlock(sigma_delta->spi->master);
|
|
- ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
|
|
|
return ret;
|
|
}
|
|
@@ -288,6 +290,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
|
|
|
|
spi_bus_lock(sigma_delta->spi->master);
|
|
sigma_delta->bus_locked = true;
|
|
+ sigma_delta->keep_cs_asserted = true;
|
|
reinit_completion(&sigma_delta->completion);
|
|
|
|
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
|
|
@@ -297,9 +300,6 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
|
|
ret = wait_for_completion_interruptible_timeout(
|
|
&sigma_delta->completion, HZ);
|
|
|
|
- sigma_delta->bus_locked = false;
|
|
- spi_bus_unlock(sigma_delta->spi->master);
|
|
-
|
|
if (ret == 0)
|
|
ret = -EIO;
|
|
if (ret < 0)
|
|
@@ -315,7 +315,10 @@ out:
|
|
sigma_delta->irq_dis = true;
|
|
}
|
|
|
|
+ sigma_delta->keep_cs_asserted = false;
|
|
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
|
+ sigma_delta->bus_locked = false;
|
|
+ spi_bus_unlock(sigma_delta->spi->master);
|
|
mutex_unlock(&indio_dev->mlock);
|
|
|
|
if (ret)
|
|
@@ -352,6 +355,8 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
|
|
|
|
spi_bus_lock(sigma_delta->spi->master);
|
|
sigma_delta->bus_locked = true;
|
|
+ sigma_delta->keep_cs_asserted = true;
|
|
+
|
|
ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
|
|
if (ret)
|
|
goto err_unlock;
|
|
@@ -380,6 +385,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
|
|
sigma_delta->irq_dis = true;
|
|
}
|
|
|
|
+ sigma_delta->keep_cs_asserted = false;
|
|
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
|
|
|
sigma_delta->bus_locked = false;
|
|
diff --git a/drivers/iio/common/ssp_sensors/ssp_iio.c b/drivers/iio/common/ssp_sensors/ssp_iio.c
|
|
index a3ae165f8d9f..16180e6321bd 100644
|
|
--- a/drivers/iio/common/ssp_sensors/ssp_iio.c
|
|
+++ b/drivers/iio/common/ssp_sensors/ssp_iio.c
|
|
@@ -80,7 +80,7 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf,
|
|
unsigned int len, int64_t timestamp)
|
|
{
|
|
__le32 time;
|
|
- int64_t calculated_time;
|
|
+ int64_t calculated_time = 0;
|
|
struct ssp_sensor_data *spd = iio_priv(indio_dev);
|
|
|
|
if (indio_dev->scan_bytes == 0)
|
|
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
|
|
index c9cffced00ca..54fd4d81a3f1 100644
|
|
--- a/drivers/infiniband/hw/cxgb4/cm.c
|
|
+++ b/drivers/infiniband/hw/cxgb4/cm.c
|
|
@@ -360,6 +360,8 @@ static struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp)
|
|
skb_reset_transport_header(skb);
|
|
} else {
|
|
skb = alloc_skb(len, gfp);
|
|
+ if (!skb)
|
|
+ return NULL;
|
|
}
|
|
t4_set_arp_err_handler(skb, NULL, NULL);
|
|
return skb;
|
|
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
|
|
index 9305964250ac..c4eb293b1524 100644
|
|
--- a/drivers/iommu/tegra-smmu.c
|
|
+++ b/drivers/iommu/tegra-smmu.c
|
|
@@ -91,7 +91,6 @@ static inline u32 smmu_readl(struct tegra_smmu *smmu, unsigned long offset)
|
|
#define SMMU_TLB_FLUSH_VA_MATCH_ALL (0 << 0)
|
|
#define SMMU_TLB_FLUSH_VA_MATCH_SECTION (2 << 0)
|
|
#define SMMU_TLB_FLUSH_VA_MATCH_GROUP (3 << 0)
|
|
-#define SMMU_TLB_FLUSH_ASID(x) (((x) & 0x7f) << 24)
|
|
#define SMMU_TLB_FLUSH_VA_SECTION(addr) ((((addr) & 0xffc00000) >> 12) | \
|
|
SMMU_TLB_FLUSH_VA_MATCH_SECTION)
|
|
#define SMMU_TLB_FLUSH_VA_GROUP(addr) ((((addr) & 0xffffc000) >> 12) | \
|
|
@@ -194,8 +193,12 @@ static inline void smmu_flush_tlb_asid(struct tegra_smmu *smmu,
|
|
{
|
|
u32 value;
|
|
|
|
- value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
|
|
- SMMU_TLB_FLUSH_VA_MATCH_ALL;
|
|
+ if (smmu->soc->num_asids == 4)
|
|
+ value = (asid & 0x3) << 29;
|
|
+ else
|
|
+ value = (asid & 0x7f) << 24;
|
|
+
|
|
+ value |= SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_VA_MATCH_ALL;
|
|
smmu_writel(smmu, value, SMMU_TLB_FLUSH);
|
|
}
|
|
|
|
@@ -205,8 +208,12 @@ static inline void smmu_flush_tlb_section(struct tegra_smmu *smmu,
|
|
{
|
|
u32 value;
|
|
|
|
- value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
|
|
- SMMU_TLB_FLUSH_VA_SECTION(iova);
|
|
+ if (smmu->soc->num_asids == 4)
|
|
+ value = (asid & 0x3) << 29;
|
|
+ else
|
|
+ value = (asid & 0x7f) << 24;
|
|
+
|
|
+ value |= SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_VA_SECTION(iova);
|
|
smmu_writel(smmu, value, SMMU_TLB_FLUSH);
|
|
}
|
|
|
|
@@ -216,8 +223,12 @@ static inline void smmu_flush_tlb_group(struct tegra_smmu *smmu,
|
|
{
|
|
u32 value;
|
|
|
|
- value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
|
|
- SMMU_TLB_FLUSH_VA_GROUP(iova);
|
|
+ if (smmu->soc->num_asids == 4)
|
|
+ value = (asid & 0x3) << 29;
|
|
+ else
|
|
+ value = (asid & 0x7f) << 24;
|
|
+
|
|
+ value |= SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_VA_GROUP(iova);
|
|
smmu_writel(smmu, value, SMMU_TLB_FLUSH);
|
|
}
|
|
|
|
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
|
|
index 16c3390e5d9f..d82ae445c9ee 100644
|
|
--- a/drivers/md/bcache/alloc.c
|
|
+++ b/drivers/md/bcache/alloc.c
|
|
@@ -324,10 +324,11 @@ static int bch_allocator_thread(void *arg)
|
|
* possibly issue discards to them, then we add the bucket to
|
|
* the free list:
|
|
*/
|
|
- while (!fifo_empty(&ca->free_inc)) {
|
|
+ while (1) {
|
|
long bucket;
|
|
|
|
- fifo_pop(&ca->free_inc, bucket);
|
|
+ if (!fifo_pop(&ca->free_inc, bucket))
|
|
+ break;
|
|
|
|
if (ca->discard) {
|
|
mutex_unlock(&ca->set->bucket_lock);
|
|
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
|
|
index 6ed066a0e7c0..6f9db98f2dfd 100644
|
|
--- a/drivers/md/bcache/journal.c
|
|
+++ b/drivers/md/bcache/journal.c
|
|
@@ -309,6 +309,18 @@ void bch_journal_mark(struct cache_set *c, struct list_head *list)
|
|
}
|
|
}
|
|
|
|
+bool is_discard_enabled(struct cache_set *s)
|
|
+{
|
|
+ struct cache *ca;
|
|
+ unsigned int i;
|
|
+
|
|
+ for_each_cache(ca, s, i)
|
|
+ if (ca->discard)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
int bch_journal_replay(struct cache_set *s, struct list_head *list)
|
|
{
|
|
int ret = 0, keys = 0, entries = 0;
|
|
@@ -322,9 +334,17 @@ int bch_journal_replay(struct cache_set *s, struct list_head *list)
|
|
list_for_each_entry(i, list, list) {
|
|
BUG_ON(i->pin && atomic_read(i->pin) != 1);
|
|
|
|
- cache_set_err_on(n != i->j.seq, s,
|
|
-"bcache: journal entries %llu-%llu missing! (replaying %llu-%llu)",
|
|
- n, i->j.seq - 1, start, end);
|
|
+ if (n != i->j.seq) {
|
|
+ if (n == start && is_discard_enabled(s))
|
|
+ pr_info("bcache: journal entries %llu-%llu may be discarded! (replaying %llu-%llu)",
|
|
+ n, i->j.seq - 1, start, end);
|
|
+ else {
|
|
+ pr_err("bcache: journal entries %llu-%llu missing! (replaying %llu-%llu)",
|
|
+ n, i->j.seq - 1, start, end);
|
|
+ ret = -EIO;
|
|
+ goto err;
|
|
+ }
|
|
+ }
|
|
|
|
for (k = i->j.start;
|
|
k < bset_bkey_last(&i->j);
|
|
@@ -513,11 +533,11 @@ static void journal_reclaim(struct cache_set *c)
|
|
ca->sb.nr_this_dev);
|
|
}
|
|
|
|
- bkey_init(k);
|
|
- SET_KEY_PTRS(k, n);
|
|
-
|
|
- if (n)
|
|
+ if (n) {
|
|
+ bkey_init(k);
|
|
+ SET_KEY_PTRS(k, n);
|
|
c->journal.blocks_free = c->sb.bucket_size >> c->block_bits;
|
|
+ }
|
|
out:
|
|
if (!journal_full(&c->journal))
|
|
__closure_wake_up(&c->journal.wait);
|
|
@@ -641,6 +661,9 @@ static void journal_write_unlocked(struct closure *cl)
|
|
ca->journal.seq[ca->journal.cur_idx] = w->data->seq;
|
|
}
|
|
|
|
+ /* If KEY_PTRS(k) == 0, this jset gets lost in air */
|
|
+ BUG_ON(i == 0);
|
|
+
|
|
atomic_dec_bug(&fifo_back(&c->journal.pin));
|
|
bch_journal_next(&c->journal);
|
|
journal_reclaim(c);
|
|
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
|
|
index ef28ddfff7c6..02757b90e402 100644
|
|
--- a/drivers/md/bcache/super.c
|
|
+++ b/drivers/md/bcache/super.c
|
|
@@ -1355,6 +1355,7 @@ static void cache_set_free(struct closure *cl)
|
|
bch_btree_cache_free(c);
|
|
bch_journal_free(c);
|
|
|
|
+ mutex_lock(&bch_register_lock);
|
|
for_each_cache(ca, c, i)
|
|
if (ca) {
|
|
ca->set = NULL;
|
|
@@ -1377,7 +1378,6 @@ static void cache_set_free(struct closure *cl)
|
|
mempool_destroy(c->search);
|
|
kfree(c->devices);
|
|
|
|
- mutex_lock(&bch_register_lock);
|
|
list_del(&c->list);
|
|
mutex_unlock(&bch_register_lock);
|
|
|
|
@@ -1558,7 +1558,7 @@ err:
|
|
return NULL;
|
|
}
|
|
|
|
-static void run_cache_set(struct cache_set *c)
|
|
+static int run_cache_set(struct cache_set *c)
|
|
{
|
|
const char *err = "cannot allocate memory";
|
|
struct cached_dev *dc, *t;
|
|
@@ -1650,7 +1650,9 @@ static void run_cache_set(struct cache_set *c)
|
|
if (j->version < BCACHE_JSET_VERSION_UUID)
|
|
__uuid_write(c);
|
|
|
|
- bch_journal_replay(c, &journal);
|
|
+ err = "bcache: replay journal failed";
|
|
+ if (bch_journal_replay(c, &journal))
|
|
+ goto err;
|
|
} else {
|
|
pr_notice("invalidating existing data");
|
|
|
|
@@ -1718,11 +1720,13 @@ static void run_cache_set(struct cache_set *c)
|
|
flash_devs_run(c);
|
|
|
|
set_bit(CACHE_SET_RUNNING, &c->flags);
|
|
- return;
|
|
+ return 0;
|
|
err:
|
|
closure_sync(&cl);
|
|
/* XXX: test this, it's broken */
|
|
bch_cache_set_error(c, "%s", err);
|
|
+
|
|
+ return -EIO;
|
|
}
|
|
|
|
static bool can_attach_cache(struct cache *ca, struct cache_set *c)
|
|
@@ -1786,8 +1790,11 @@ found:
|
|
ca->set->cache[ca->sb.nr_this_dev] = ca;
|
|
c->cache_by_alloc[c->caches_loaded++] = ca;
|
|
|
|
- if (c->caches_loaded == c->sb.nr_in_set)
|
|
- run_cache_set(c);
|
|
+ if (c->caches_loaded == c->sb.nr_in_set) {
|
|
+ err = "failed to run cache set";
|
|
+ if (run_cache_set(c) < 0)
|
|
+ goto err;
|
|
+ }
|
|
|
|
return NULL;
|
|
err:
|
|
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
|
|
index b4c356a21123..e789a4aae4e7 100644
|
|
--- a/drivers/md/dm-delay.c
|
|
+++ b/drivers/md/dm-delay.c
|
|
@@ -222,7 +222,8 @@ static void delay_dtr(struct dm_target *ti)
|
|
{
|
|
struct delay_c *dc = ti->private;
|
|
|
|
- destroy_workqueue(dc->kdelayd_wq);
|
|
+ if (dc->kdelayd_wq)
|
|
+ destroy_workqueue(dc->kdelayd_wq);
|
|
|
|
dm_put_device(ti, dc->dev_read);
|
|
|
|
diff --git a/drivers/md/md.c b/drivers/md/md.c
|
|
index 07f307402351..f71cca28ddda 100644
|
|
--- a/drivers/md/md.c
|
|
+++ b/drivers/md/md.c
|
|
@@ -2690,8 +2690,10 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
|
|
err = 0;
|
|
}
|
|
} else if (cmd_match(buf, "re-add")) {
|
|
- if (test_bit(Faulty, &rdev->flags) && (rdev->raid_disk == -1) &&
|
|
- rdev->saved_raid_disk >= 0) {
|
|
+ if (!rdev->mddev->pers)
|
|
+ err = -EINVAL;
|
|
+ else if (test_bit(Faulty, &rdev->flags) && (rdev->raid_disk == -1) &&
|
|
+ rdev->saved_raid_disk >= 0) {
|
|
/* clear_bit is performed _after_ all the devices
|
|
* have their local Faulty bit cleared. If any writes
|
|
* happen in the meantime in the local node, they
|
|
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
|
|
index 17517889d46b..764e0e155ae2 100644
|
|
--- a/drivers/md/raid5.c
|
|
+++ b/drivers/md/raid5.c
|
|
@@ -3861,7 +3861,7 @@ static void handle_parity_checks6(struct r5conf *conf, struct stripe_head *sh,
|
|
/* now write out any block on a failed drive,
|
|
* or P or Q if they were recomputed
|
|
*/
|
|
- BUG_ON(s->uptodate < disks - 1); /* We don't need Q to recover */
|
|
+ dev = NULL;
|
|
if (s->failed == 2) {
|
|
dev = &sh->dev[s->failed_num[1]];
|
|
s->locked++;
|
|
@@ -3886,6 +3886,14 @@ static void handle_parity_checks6(struct r5conf *conf, struct stripe_head *sh,
|
|
set_bit(R5_LOCKED, &dev->flags);
|
|
set_bit(R5_Wantwrite, &dev->flags);
|
|
}
|
|
+ if (WARN_ONCE(dev && !test_bit(R5_UPTODATE, &dev->flags),
|
|
+ "%s: disk%td not up to date\n",
|
|
+ mdname(conf->mddev),
|
|
+ dev - (struct r5dev *) &sh->dev)) {
|
|
+ clear_bit(R5_LOCKED, &dev->flags);
|
|
+ clear_bit(R5_Wantwrite, &dev->flags);
|
|
+ s->locked--;
|
|
+ }
|
|
clear_bit(STRIPE_DEGRADED, &sh->state);
|
|
|
|
set_bit(STRIPE_INSYNC, &sh->state);
|
|
@@ -3897,15 +3905,26 @@ static void handle_parity_checks6(struct r5conf *conf, struct stripe_head *sh,
|
|
case check_state_check_result:
|
|
sh->check_state = check_state_idle;
|
|
|
|
- if (s->failed > 1)
|
|
- break;
|
|
/* handle a successful check operation, if parity is correct
|
|
* we are done. Otherwise update the mismatch count and repair
|
|
* parity if !MD_RECOVERY_CHECK
|
|
*/
|
|
if (sh->ops.zero_sum_result == 0) {
|
|
- /* Any parity checked was correct */
|
|
- set_bit(STRIPE_INSYNC, &sh->state);
|
|
+ /* both parities are correct */
|
|
+ if (!s->failed)
|
|
+ set_bit(STRIPE_INSYNC, &sh->state);
|
|
+ else {
|
|
+ /* in contrast to the raid5 case we can validate
|
|
+ * parity, but still have a failure to write
|
|
+ * back
|
|
+ */
|
|
+ sh->check_state = check_state_compute_result;
|
|
+ /* Returning at this point means that we may go
|
|
+ * off and bring p and/or q uptodate again so
|
|
+ * we make sure to check zero_sum_result again
|
|
+ * to verify if p or q need writeback
|
|
+ */
|
|
+ }
|
|
} else {
|
|
atomic64_add(STRIPE_SECTORS, &conf->mddev->resync_mismatches);
|
|
if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
|
|
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
|
|
index d14d075ab1d6..9f0956e739a4 100644
|
|
--- a/drivers/media/dvb-frontends/m88ds3103.c
|
|
+++ b/drivers/media/dvb-frontends/m88ds3103.c
|
|
@@ -309,6 +309,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
u16 u16tmp, divide_ratio = 0;
|
|
u32 tuner_frequency, target_mclk;
|
|
s32 s32tmp;
|
|
+ static const struct reg_sequence reset_buf[] = {
|
|
+ {0x07, 0x80}, {0x07, 0x00}
|
|
+ };
|
|
|
|
dev_dbg(&client->dev,
|
|
"delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
|
|
@@ -321,11 +324,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
}
|
|
|
|
/* reset */
|
|
- ret = regmap_write(dev->regmap, 0x07, 0x80);
|
|
- if (ret)
|
|
- goto err;
|
|
-
|
|
- ret = regmap_write(dev->regmap, 0x07, 0x00);
|
|
+ ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2);
|
|
if (ret)
|
|
goto err;
|
|
|
|
diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c
|
|
index 49109f4f5bb4..fadec1d70582 100644
|
|
--- a/drivers/media/i2c/ov2659.c
|
|
+++ b/drivers/media/i2c/ov2659.c
|
|
@@ -1117,8 +1117,10 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd,
|
|
if (ov2659_formats[index].code == mf->code)
|
|
break;
|
|
|
|
- if (index < 0)
|
|
- return -EINVAL;
|
|
+ if (index < 0) {
|
|
+ index = 0;
|
|
+ mf->code = ov2659_formats[index].code;
|
|
+ }
|
|
|
|
mf->colorspace = V4L2_COLORSPACE_SRGB;
|
|
mf->code = ov2659_formats[index].code;
|
|
diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c
|
|
index 1e4783b51a35..4e19f5e5d8cf 100644
|
|
--- a/drivers/media/i2c/soc_camera/ov6650.c
|
|
+++ b/drivers/media/i2c/soc_camera/ov6650.c
|
|
@@ -839,9 +839,18 @@ static int ov6650_video_probe(struct i2c_client *client)
|
|
u8 pidh, pidl, midh, midl;
|
|
int ret;
|
|
|
|
+ priv->clk = v4l2_clk_get(&client->dev, NULL);
|
|
+ if (IS_ERR(priv->clk)) {
|
|
+ ret = PTR_ERR(priv->clk);
|
|
+ dev_err(&client->dev, "v4l2_clk request err: %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
ret = ov6650_s_power(&priv->subdev, 1);
|
|
if (ret < 0)
|
|
- return ret;
|
|
+ goto eclkput;
|
|
+
|
|
+ msleep(20);
|
|
|
|
/*
|
|
* check and show product ID and manufacturer ID
|
|
@@ -876,6 +885,11 @@ static int ov6650_video_probe(struct i2c_client *client)
|
|
|
|
done:
|
|
ov6650_s_power(&priv->subdev, 0);
|
|
+ if (!ret)
|
|
+ return 0;
|
|
+eclkput:
|
|
+ v4l2_clk_put(priv->clk);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
@@ -1033,18 +1047,9 @@ static int ov6650_probe(struct i2c_client *client,
|
|
priv->code = MEDIA_BUS_FMT_YUYV8_2X8;
|
|
priv->colorspace = V4L2_COLORSPACE_JPEG;
|
|
|
|
- priv->clk = v4l2_clk_get(&client->dev, NULL);
|
|
- if (IS_ERR(priv->clk)) {
|
|
- ret = PTR_ERR(priv->clk);
|
|
- goto eclkget;
|
|
- }
|
|
-
|
|
ret = ov6650_video_probe(client);
|
|
- if (ret) {
|
|
- v4l2_clk_put(priv->clk);
|
|
-eclkget:
|
|
+ if (ret)
|
|
v4l2_ctrl_handler_free(&priv->hdl);
|
|
- }
|
|
|
|
return ret;
|
|
}
|
|
diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c
|
|
index 03cbcd2095c6..d4b3ce828285 100644
|
|
--- a/drivers/media/pci/saa7146/hexium_gemini.c
|
|
+++ b/drivers/media/pci/saa7146/hexium_gemini.c
|
|
@@ -270,9 +270,8 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
|
|
/* enable i2c-port pins */
|
|
saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
|
|
|
|
- hexium->i2c_adapter = (struct i2c_adapter) {
|
|
- .name = "hexium gemini",
|
|
- };
|
|
+ strscpy(hexium->i2c_adapter.name, "hexium gemini",
|
|
+ sizeof(hexium->i2c_adapter.name));
|
|
saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
|
|
if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
|
|
DEB_S("cannot register i2c-device. skipping.\n");
|
|
diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c
|
|
index 15f0d66ff78a..214396b1ca73 100644
|
|
--- a/drivers/media/pci/saa7146/hexium_orion.c
|
|
+++ b/drivers/media/pci/saa7146/hexium_orion.c
|
|
@@ -232,9 +232,8 @@ static int hexium_probe(struct saa7146_dev *dev)
|
|
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
|
|
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
|
|
|
|
- hexium->i2c_adapter = (struct i2c_adapter) {
|
|
- .name = "hexium orion",
|
|
- };
|
|
+ strscpy(hexium->i2c_adapter.name, "hexium orion",
|
|
+ sizeof(hexium->i2c_adapter.name));
|
|
saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
|
|
if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
|
|
DEB_S("cannot register i2c-device. skipping.\n");
|
|
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
|
|
index d76511c1c1e3..a4639813cf35 100644
|
|
--- a/drivers/media/platform/coda/coda-bit.c
|
|
+++ b/drivers/media/platform/coda/coda-bit.c
|
|
@@ -1829,6 +1829,9 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
|
|
/* Clear decode success flag */
|
|
coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS);
|
|
|
|
+ /* Clear error return value */
|
|
+ coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB);
|
|
+
|
|
trace_coda_dec_pic_run(ctx, meta);
|
|
|
|
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
|
|
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
|
|
index a84954f1be34..9eb0bc4a8d97 100644
|
|
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
|
|
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
|
|
@@ -993,7 +993,7 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
|
|
rect_map_inside(&s->r, &dev->fmt_cap_rect);
|
|
if (dev->bitmap_cap && (compose->width != s->r.width ||
|
|
compose->height != s->r.height)) {
|
|
- kfree(dev->bitmap_cap);
|
|
+ vfree(dev->bitmap_cap);
|
|
dev->bitmap_cap = NULL;
|
|
}
|
|
*compose = s->r;
|
|
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
|
|
index ebc73b034249..51639a3f7abe 100644
|
|
--- a/drivers/media/radio/wl128x/fmdrv_common.c
|
|
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
|
|
@@ -494,7 +494,8 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
|
|
return -EIO;
|
|
}
|
|
/* Send response data to caller */
|
|
- if (response != NULL && response_len != NULL && evt_hdr->dlen) {
|
|
+ if (response != NULL && response_len != NULL && evt_hdr->dlen &&
|
|
+ evt_hdr->dlen <= payload_len) {
|
|
/* Skip header info and copy only response data */
|
|
skb_pull(skb, sizeof(struct fm_event_msg_hdr));
|
|
memcpy(response, skb->data, evt_hdr->dlen);
|
|
@@ -590,6 +591,8 @@ static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev)
|
|
return;
|
|
|
|
fm_evt_hdr = (void *)skb->data;
|
|
+ if (fm_evt_hdr->dlen > sizeof(fmdev->irq_info.flag))
|
|
+ return;
|
|
|
|
/* Skip header info and copy only response data */
|
|
skb_pull(skb, sizeof(struct fm_event_msg_hdr));
|
|
@@ -1315,7 +1318,7 @@ static int load_default_rx_configuration(struct fmdev *fmdev)
|
|
static int fm_power_up(struct fmdev *fmdev, u8 mode)
|
|
{
|
|
u16 payload;
|
|
- __be16 asic_id, asic_ver;
|
|
+ __be16 asic_id = 0, asic_ver = 0;
|
|
int resp_len, ret;
|
|
u8 fw_name[50];
|
|
|
|
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
|
|
index 7b2fe1b56039..1df23c01ad37 100644
|
|
--- a/drivers/media/usb/au0828/au0828-video.c
|
|
+++ b/drivers/media/usb/au0828/au0828-video.c
|
|
@@ -711,6 +711,9 @@ static int au0828_analog_stream_enable(struct au0828_dev *d)
|
|
|
|
dprintk(1, "au0828_analog_stream_enable called\n");
|
|
|
|
+ if (test_bit(DEV_DISCONNECTED, &d->dev_state))
|
|
+ return -ENODEV;
|
|
+
|
|
iface = usb_ifnum_to_if(d->usbdev, 0);
|
|
if (iface && iface->cur_altsetting->desc.bAlternateSetting != 5) {
|
|
dprintk(1, "Changing intf#0 to alt 5\n");
|
|
@@ -799,9 +802,9 @@ int au0828_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
|
|
return rc;
|
|
}
|
|
|
|
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
|
|
+
|
|
if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
|
- v4l2_device_call_all(&dev->v4l2_dev, 0, video,
|
|
- s_stream, 1);
|
|
dev->vid_timeout_running = 1;
|
|
mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
|
|
} else if (vq->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
|
|
@@ -821,10 +824,11 @@ static void au0828_stop_streaming(struct vb2_queue *vq)
|
|
|
|
dprintk(1, "au0828_stop_streaming called %d\n", dev->streaming_users);
|
|
|
|
- if (dev->streaming_users-- == 1)
|
|
+ if (dev->streaming_users-- == 1) {
|
|
au0828_uninit_isoc(dev);
|
|
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
|
|
+ }
|
|
|
|
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
|
|
dev->vid_timeout_running = 0;
|
|
del_timer_sync(&dev->vid_timeout);
|
|
|
|
@@ -853,8 +857,10 @@ void au0828_stop_vbi_streaming(struct vb2_queue *vq)
|
|
dprintk(1, "au0828_stop_vbi_streaming called %d\n",
|
|
dev->streaming_users);
|
|
|
|
- if (dev->streaming_users-- == 1)
|
|
+ if (dev->streaming_users-- == 1) {
|
|
au0828_uninit_isoc(dev);
|
|
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
|
|
+ }
|
|
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
if (dev->isoc_ctl.vbi_buf != NULL) {
|
|
diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
|
|
index d793c630f1dd..05e7edb213de 100644
|
|
--- a/drivers/media/usb/cpia2/cpia2_v4l.c
|
|
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
|
|
@@ -1248,8 +1248,7 @@ static int __init cpia2_init(void)
|
|
LOG("%s v%s\n",
|
|
ABOUT, CPIA_VERSION);
|
|
check_parameters();
|
|
- cpia2_usb_init();
|
|
- return 0;
|
|
+ return cpia2_usb_init();
|
|
}
|
|
|
|
|
|
diff --git a/drivers/media/usb/go7007/go7007-fw.c b/drivers/media/usb/go7007/go7007-fw.c
|
|
index 60bf5f0644d1..a5efcd4f7b4f 100644
|
|
--- a/drivers/media/usb/go7007/go7007-fw.c
|
|
+++ b/drivers/media/usb/go7007/go7007-fw.c
|
|
@@ -1499,8 +1499,8 @@ static int modet_to_package(struct go7007 *go, __le16 *code, int space)
|
|
return cnt;
|
|
}
|
|
|
|
-static int do_special(struct go7007 *go, u16 type, __le16 *code, int space,
|
|
- int *framelen)
|
|
+static noinline_for_stack int do_special(struct go7007 *go, u16 type,
|
|
+ __le16 *code, int space, int *framelen)
|
|
{
|
|
switch (type) {
|
|
case SPECIAL_FRM_HEAD:
|
|
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
|
|
index 0533ef20decf..232b0fd3e478 100644
|
|
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
|
|
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
|
|
@@ -670,6 +670,8 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
|
|
|
|
static int ctrl_check_input(struct pvr2_ctrl *cptr,int v)
|
|
{
|
|
+ if (v < 0 || v > PVR2_CVAL_INPUT_MAX)
|
|
+ return 0;
|
|
return ((1 << v) & cptr->hdw->input_allowed_mask) != 0;
|
|
}
|
|
|
|
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
|
|
index a82a00dd7329..80869990ffbb 100644
|
|
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
|
|
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
|
|
@@ -54,6 +54,7 @@
|
|
#define PVR2_CVAL_INPUT_COMPOSITE 2
|
|
#define PVR2_CVAL_INPUT_SVIDEO 3
|
|
#define PVR2_CVAL_INPUT_RADIO 4
|
|
+#define PVR2_CVAL_INPUT_MAX PVR2_CVAL_INPUT_RADIO
|
|
|
|
enum pvr2_config {
|
|
pvr2_config_empty, /* No configuration */
|
|
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
|
|
index ec30a004f319..e8f7a1f56be5 100644
|
|
--- a/drivers/media/usb/siano/smsusb.c
|
|
+++ b/drivers/media/usb/siano/smsusb.c
|
|
@@ -391,6 +391,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
|
|
struct smsusb_device_t *dev;
|
|
void *mdev;
|
|
int i, rc;
|
|
+ int align = 0;
|
|
|
|
/* create device object */
|
|
dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
|
|
@@ -402,6 +403,24 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
|
|
dev->udev = interface_to_usbdev(intf);
|
|
dev->state = SMSUSB_DISCONNECTED;
|
|
|
|
+ for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
|
|
+ struct usb_endpoint_descriptor *desc =
|
|
+ &intf->cur_altsetting->endpoint[i].desc;
|
|
+
|
|
+ if (desc->bEndpointAddress & USB_DIR_IN) {
|
|
+ dev->in_ep = desc->bEndpointAddress;
|
|
+ align = usb_endpoint_maxp(desc) - sizeof(struct sms_msg_hdr);
|
|
+ } else {
|
|
+ dev->out_ep = desc->bEndpointAddress;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pr_debug("in_ep = %02x, out_ep = %02x\n", dev->in_ep, dev->out_ep);
|
|
+ if (!dev->in_ep || !dev->out_ep || align < 0) { /* Missing endpoints? */
|
|
+ smsusb_term_device(intf);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
params.device_type = sms_get_board(board_id)->type;
|
|
|
|
switch (params.device_type) {
|
|
@@ -416,24 +435,12 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
|
|
/* fall-thru */
|
|
default:
|
|
dev->buffer_size = USB2_BUFFER_SIZE;
|
|
- dev->response_alignment =
|
|
- le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
|
|
- sizeof(struct sms_msg_hdr);
|
|
+ dev->response_alignment = align;
|
|
|
|
params.flags |= SMS_DEVICE_FAMILY2;
|
|
break;
|
|
}
|
|
|
|
- for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
|
|
- if (intf->cur_altsetting->endpoint[i].desc. bEndpointAddress & USB_DIR_IN)
|
|
- dev->in_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
|
|
- else
|
|
- dev->out_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
|
|
- }
|
|
-
|
|
- pr_debug("in_ep = %02x, out_ep = %02x\n",
|
|
- dev->in_ep, dev->out_ep);
|
|
-
|
|
params.device = &dev->udev->dev;
|
|
params.buffer_size = dev->buffer_size;
|
|
params.num_buffers = MAX_BUFFERS;
|
|
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
|
|
index f2e3fdf385cc..ebd1b882556d 100644
|
|
--- a/drivers/media/usb/uvc/uvc_driver.c
|
|
+++ b/drivers/media/usb/uvc/uvc_driver.c
|
|
@@ -868,7 +868,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
|
|
unsigned int size;
|
|
unsigned int i;
|
|
|
|
- extra_size = ALIGN(extra_size, sizeof(*entity->pads));
|
|
+ extra_size = roundup(extra_size, sizeof(*entity->pads));
|
|
num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
|
|
size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads
|
|
+ num_inputs;
|
|
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
|
|
index 6ab481ee8ece..8ac02b6c162f 100644
|
|
--- a/drivers/memory/tegra/mc.c
|
|
+++ b/drivers/memory/tegra/mc.c
|
|
@@ -72,7 +72,7 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
|
|
u32 value;
|
|
|
|
/* compute the number of MC clock cycles per tick */
|
|
- tick = mc->tick * clk_get_rate(mc->clk);
|
|
+ tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk);
|
|
do_div(tick, NSEC_PER_SEC);
|
|
|
|
value = readl(mc->regs + MC_EMEM_ARB_CFG);
|
|
diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c
|
|
index c0012ca4229e..74923ffb0df1 100644
|
|
--- a/drivers/misc/genwqe/card_dev.c
|
|
+++ b/drivers/misc/genwqe/card_dev.c
|
|
@@ -782,6 +782,8 @@ static int genwqe_pin_mem(struct genwqe_file *cfile, struct genwqe_mem *m)
|
|
|
|
if ((m->addr == 0x0) || (m->size == 0))
|
|
return -EINVAL;
|
|
+ if (m->size > ULONG_MAX - PAGE_SIZE - (m->addr & ~PAGE_MASK))
|
|
+ return -EINVAL;
|
|
|
|
map_addr = (m->addr & PAGE_MASK);
|
|
map_size = round_up(m->size + (m->addr & ~PAGE_MASK), PAGE_SIZE);
|
|
diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c
|
|
index 0c15ba21fa54..d4c719683a8a 100644
|
|
--- a/drivers/misc/genwqe/card_utils.c
|
|
+++ b/drivers/misc/genwqe/card_utils.c
|
|
@@ -582,6 +582,10 @@ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr,
|
|
/* determine space needed for page_list. */
|
|
data = (unsigned long)uaddr;
|
|
offs = offset_in_page(data);
|
|
+ if (size > ULONG_MAX - PAGE_SIZE - offs) {
|
|
+ m->size = 0; /* mark unused and not added */
|
|
+ return -EINVAL;
|
|
+ }
|
|
m->nr_pages = DIV_ROUND_UP(offs + size, PAGE_SIZE);
|
|
|
|
m->page_list = kcalloc(m->nr_pages,
|
|
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
|
|
index 967535d76e34..fb8741f18c1f 100644
|
|
--- a/drivers/mmc/core/sd.c
|
|
+++ b/drivers/mmc/core/sd.c
|
|
@@ -216,6 +216,14 @@ static int mmc_decode_scr(struct mmc_card *card)
|
|
|
|
if (scr->sda_spec3)
|
|
scr->cmds = UNSTUFF_BITS(resp, 32, 2);
|
|
+
|
|
+ /* SD Spec says: any SD Card shall set at least bits 0 and 2 */
|
|
+ if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) ||
|
|
+ !(scr->bus_widths & SD_SCR_BUS_WIDTH_4)) {
|
|
+ pr_err("%s: invalid bus width\n", mmc_hostname(card->host));
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
|
|
index e03ec74f3fb0..40a369c7005a 100644
|
|
--- a/drivers/mmc/host/mmc_spi.c
|
|
+++ b/drivers/mmc/host/mmc_spi.c
|
|
@@ -819,6 +819,10 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
|
|
}
|
|
|
|
status = spi_sync_locked(spi, &host->m);
|
|
+ if (status < 0) {
|
|
+ dev_dbg(&spi->dev, "read error %d\n", status);
|
|
+ return status;
|
|
+ }
|
|
|
|
if (host->dma_dev) {
|
|
dma_sync_single_for_cpu(host->dma_dev,
|
|
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
|
|
index ac66c61d9433..356b294c93c9 100644
|
|
--- a/drivers/mmc/host/sdhci-of-esdhc.c
|
|
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
|
|
@@ -624,6 +624,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
|
|
if (esdhc->vendor_ver > VENDOR_V_22)
|
|
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;
|
|
+ }
|
|
+
|
|
if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
|
|
of_device_is_compatible(np, "fsl,p5020-esdhc") ||
|
|
of_device_is_compatible(np, "fsl,p4080-esdhc") ||
|
|
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
|
|
index 403fa8d98aa3..d450d8b3708c 100644
|
|
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
|
|
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
|
|
@@ -12824,6 +12824,24 @@ static netdev_features_t bnx2x_features_check(struct sk_buff *skb,
|
|
struct net_device *dev,
|
|
netdev_features_t features)
|
|
{
|
|
+ /*
|
|
+ * A skb with gso_size + header length > 9700 will cause a
|
|
+ * firmware panic. Drop GSO support.
|
|
+ *
|
|
+ * Eventually the upper layer should not pass these packets down.
|
|
+ *
|
|
+ * For speed, if the gso_size is <= 9000, assume there will
|
|
+ * not be 700 bytes of headers and pass it through. Only do a
|
|
+ * full (slow) validation if the gso_size is > 9000.
|
|
+ *
|
|
+ * (Due to the way SKB_BY_FRAGS works this will also do a full
|
|
+ * validation in that case.)
|
|
+ */
|
|
+ if (unlikely(skb_is_gso(skb) &&
|
|
+ (skb_shinfo(skb)->gso_size > 9000) &&
|
|
+ !skb_gso_validate_mac_len(skb, 9700)))
|
|
+ features &= ~NETIF_F_GSO_MASK;
|
|
+
|
|
features = vlan_features_check(skb, features);
|
|
return vxlan_features_check(skb, features);
|
|
}
|
|
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
|
|
index d9ab970dcbe9..81282b811a6c 100644
|
|
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
|
|
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
|
|
@@ -1140,6 +1140,8 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
|
|
skb = bnxt_copy_skb(bnapi, data, len, dma_addr);
|
|
bnxt_reuse_rx_data(rxr, cons, data);
|
|
if (!skb) {
|
|
+ if (agg_bufs)
|
|
+ bnxt_reuse_rx_agg_bufs(bnapi, cp_cons, agg_bufs);
|
|
rc = -ENOMEM;
|
|
goto next_rx;
|
|
}
|
|
diff --git a/drivers/net/ethernet/chelsio/cxgb3/l2t.h b/drivers/net/ethernet/chelsio/cxgb3/l2t.h
|
|
index 8cffcdfd5678..38b5858c335a 100644
|
|
--- a/drivers/net/ethernet/chelsio/cxgb3/l2t.h
|
|
+++ b/drivers/net/ethernet/chelsio/cxgb3/l2t.h
|
|
@@ -75,8 +75,8 @@ struct l2t_data {
|
|
struct l2t_entry *rover; /* starting point for next allocation */
|
|
atomic_t nfree; /* number of free entries */
|
|
rwlock_t lock;
|
|
- struct l2t_entry l2tab[0];
|
|
struct rcu_head rcu_head; /* to handle rcu cleanup */
|
|
+ struct l2t_entry l2tab[];
|
|
};
|
|
|
|
typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
|
|
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
|
|
index a3e1498ca67c..3b96622de8ff 100644
|
|
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
|
|
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
|
|
@@ -5061,15 +5061,24 @@ static int __init cxgb4_init_module(void)
|
|
|
|
ret = pci_register_driver(&cxgb4_driver);
|
|
if (ret < 0)
|
|
- debugfs_remove(cxgb4_debugfs_root);
|
|
+ goto err_pci;
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
if (!inet6addr_registered) {
|
|
- register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
|
|
- inet6addr_registered = true;
|
|
+ ret = register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
|
|
+ if (ret)
|
|
+ pci_unregister_driver(&cxgb4_driver);
|
|
+ else
|
|
+ inet6addr_registered = true;
|
|
}
|
|
#endif
|
|
|
|
+ if (ret == 0)
|
|
+ return ret;
|
|
+
|
|
+err_pci:
|
|
+ debugfs_remove(cxgb4_debugfs_root);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
|
|
index 06b38f50980c..22c43a776c6c 100644
|
|
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
|
|
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
|
|
@@ -2263,6 +2263,10 @@ void i40e_vlan_stripping_enable(struct i40e_vsi *vsi)
|
|
struct i40e_vsi_context ctxt;
|
|
i40e_status ret;
|
|
|
|
+ /* Don't modify stripping options if a port VLAN is active */
|
|
+ if (vsi->info.pvid)
|
|
+ return;
|
|
+
|
|
if ((vsi->info.valid_sections &
|
|
cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID)) &&
|
|
((vsi->info.port_vlan_flags & I40E_AQ_VSI_PVLAN_MODE_MASK) == 0))
|
|
@@ -2293,6 +2297,10 @@ void i40e_vlan_stripping_disable(struct i40e_vsi *vsi)
|
|
struct i40e_vsi_context ctxt;
|
|
i40e_status ret;
|
|
|
|
+ /* Don't modify stripping options if a port VLAN is active */
|
|
+ if (vsi->info.pvid)
|
|
+ return;
|
|
+
|
|
if ((vsi->info.valid_sections &
|
|
cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID)) &&
|
|
((vsi->info.port_vlan_flags & I40E_AQ_VSI_PVLAN_EMOD_MASK) ==
|
|
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
|
|
index 42305f3234ff..03f0d20aa08b 100644
|
|
--- a/drivers/net/ethernet/marvell/mvpp2.c
|
|
+++ b/drivers/net/ethernet/marvell/mvpp2.c
|
|
@@ -3940,7 +3940,7 @@ static inline void mvpp2_gmac_max_rx_size_set(struct mvpp2_port *port)
|
|
/* Set defaults to the MVPP2 port */
|
|
static void mvpp2_defaults_set(struct mvpp2_port *port)
|
|
{
|
|
- int tx_port_num, val, queue, ptxq, lrxq;
|
|
+ int tx_port_num, val, queue, lrxq;
|
|
|
|
/* Configure port to loopback if needed */
|
|
if (port->flags & MVPP2_F_LOOPBACK)
|
|
@@ -3960,11 +3960,9 @@ static void mvpp2_defaults_set(struct mvpp2_port *port)
|
|
mvpp2_write(port->priv, MVPP2_TXP_SCHED_CMD_1_REG, 0);
|
|
|
|
/* Close bandwidth for all queues */
|
|
- for (queue = 0; queue < MVPP2_MAX_TXQ; queue++) {
|
|
- ptxq = mvpp2_txq_phys(port->id, queue);
|
|
+ for (queue = 0; queue < MVPP2_MAX_TXQ; queue++)
|
|
mvpp2_write(port->priv,
|
|
- MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(ptxq), 0);
|
|
- }
|
|
+ MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(queue), 0);
|
|
|
|
/* Set refill period to 1 usec, refill tokens
|
|
* and bucket size to maximum
|
|
@@ -4722,7 +4720,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port,
|
|
txq->descs_phys = 0;
|
|
|
|
/* Set minimum bandwidth for disabled TXQs */
|
|
- mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(txq->id), 0);
|
|
+ mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(txq->log_id), 0);
|
|
|
|
/* Set Tx descriptors queue starting address and size */
|
|
mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id);
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
|
|
index bcfac000199e..fcd1e6b3950d 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
|
|
@@ -1906,6 +1906,8 @@ static int mlx4_en_set_tunable(struct net_device *dev,
|
|
return ret;
|
|
}
|
|
|
|
+#define MLX4_EEPROM_PAGE_LEN 256
|
|
+
|
|
static int mlx4_en_get_module_info(struct net_device *dev,
|
|
struct ethtool_modinfo *modinfo)
|
|
{
|
|
@@ -1940,7 +1942,7 @@ static int mlx4_en_get_module_info(struct net_device *dev,
|
|
break;
|
|
case MLX4_MODULE_ID_SFP:
|
|
modinfo->type = ETH_MODULE_SFF_8472;
|
|
- modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
|
|
+ modinfo->eeprom_len = MLX4_EEPROM_PAGE_LEN;
|
|
break;
|
|
default:
|
|
return -ENOSYS;
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
|
|
index 897d061e4f03..3bf63de3a725 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
|
|
@@ -1485,7 +1485,7 @@ int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,
|
|
rule.port = port;
|
|
rule.qpn = qpn;
|
|
INIT_LIST_HEAD(&rule.list);
|
|
- mlx4_err(dev, "going promisc on %x\n", port);
|
|
+ mlx4_info(dev, "going promisc on %x\n", port);
|
|
|
|
return mlx4_flow_attach(dev, &rule, regid_p);
|
|
}
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
|
|
index c2b21313dba7..a9c4818448f9 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
|
|
@@ -1398,11 +1398,6 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
|
|
size -= offset + size - I2C_PAGE_SIZE;
|
|
|
|
i2c_addr = I2C_ADDR_LOW;
|
|
- if (offset >= I2C_PAGE_SIZE) {
|
|
- /* Reset offset to high page */
|
|
- i2c_addr = I2C_ADDR_HIGH;
|
|
- offset -= I2C_PAGE_SIZE;
|
|
- }
|
|
|
|
cable_info = (struct mlx4_cable_info *)inmad->data;
|
|
cable_info->dev_mem_address = cpu_to_be16(offset);
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
|
|
index 90d95b3654f5..6bdde92869fb 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
|
|
@@ -154,7 +154,8 @@ int stmmac_mdio_reset(struct mii_bus *bus)
|
|
of_property_read_u32_array(np,
|
|
"snps,reset-delays-us", data->delays, 3);
|
|
|
|
- if (gpio_request(data->reset_gpio, "mdio-reset"))
|
|
+ if (devm_gpio_request(priv->device, data->reset_gpio,
|
|
+ "mdio-reset"))
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c
|
|
index b5edc7f96a39..685e875f5164 100644
|
|
--- a/drivers/net/ppp/ppp_deflate.c
|
|
+++ b/drivers/net/ppp/ppp_deflate.c
|
|
@@ -610,12 +610,20 @@ static struct compressor ppp_deflate_draft = {
|
|
|
|
static int __init deflate_init(void)
|
|
{
|
|
- int answer = ppp_register_compressor(&ppp_deflate);
|
|
- if (answer == 0)
|
|
- printk(KERN_INFO
|
|
- "PPP Deflate Compression module registered\n");
|
|
- ppp_register_compressor(&ppp_deflate_draft);
|
|
- return answer;
|
|
+ int rc;
|
|
+
|
|
+ rc = ppp_register_compressor(&ppp_deflate);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ rc = ppp_register_compressor(&ppp_deflate_draft);
|
|
+ if (rc) {
|
|
+ ppp_unregister_compressor(&ppp_deflate);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ pr_info("PPP Deflate Compression module registered\n");
|
|
+ return 0;
|
|
}
|
|
|
|
static void __exit deflate_cleanup(void)
|
|
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
|
|
index 36e1377fc954..1e921e5eddc7 100644
|
|
--- a/drivers/net/usb/cdc_ncm.c
|
|
+++ b/drivers/net/usb/cdc_ncm.c
|
|
@@ -727,7 +727,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
|
|
int err;
|
|
u8 iface_no;
|
|
struct usb_cdc_parsed_header hdr;
|
|
- u16 curr_ntb_format;
|
|
+ __le16 curr_ntb_format;
|
|
|
|
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
|
if (!ctx)
|
|
@@ -841,7 +841,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
|
|
goto error2;
|
|
}
|
|
|
|
- if (curr_ntb_format == USB_CDC_NCM_NTB32_FORMAT) {
|
|
+ if (curr_ntb_format == cpu_to_le16(USB_CDC_NCM_NTB32_FORMAT)) {
|
|
dev_info(&intf->dev, "resetting NTB format to 16-bit");
|
|
err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
|
|
USB_TYPE_CLASS | USB_DIR_OUT
|
|
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
|
|
index 9710cf71054a..2502681369cd 100644
|
|
--- a/drivers/net/usb/usbnet.c
|
|
+++ b/drivers/net/usb/usbnet.c
|
|
@@ -499,6 +499,7 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
|
|
|
|
if (netif_running (dev->net) &&
|
|
netif_device_present (dev->net) &&
|
|
+ test_bit(EVENT_DEV_OPEN, &dev->flags) &&
|
|
!test_bit (EVENT_RX_HALT, &dev->flags) &&
|
|
!test_bit (EVENT_DEV_ASLEEP, &dev->flags)) {
|
|
switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
|
|
@@ -1385,6 +1386,11 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
|
|
spin_unlock_irqrestore(&dev->txq.lock, flags);
|
|
goto drop;
|
|
}
|
|
+ if (netif_queue_stopped(net)) {
|
|
+ usb_autopm_put_interface_async(dev->intf);
|
|
+ spin_unlock_irqrestore(&dev->txq.lock, flags);
|
|
+ goto drop;
|
|
+ }
|
|
|
|
#ifdef CONFIG_PM
|
|
/* if this triggers the device is still a sleep */
|
|
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
|
|
index dab25136214a..da14eca2aa2c 100644
|
|
--- a/drivers/net/wireless/at76c50x-usb.c
|
|
+++ b/drivers/net/wireless/at76c50x-usb.c
|
|
@@ -2582,8 +2582,8 @@ static int __init at76_mod_init(void)
|
|
if (result < 0)
|
|
printk(KERN_ERR DRIVER_NAME
|
|
": usb_register failed (status %d)\n", result);
|
|
-
|
|
- led_trigger_register_simple("at76_usb-tx", &ledtrig_tx);
|
|
+ else
|
|
+ led_trigger_register_simple("at76_usb-tx", &ledtrig_tx);
|
|
return result;
|
|
}
|
|
|
|
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
|
|
index 058a9f232050..55cb07693ae8 100644
|
|
--- a/drivers/net/wireless/b43/phy_lp.c
|
|
+++ b/drivers/net/wireless/b43/phy_lp.c
|
|
@@ -1834,7 +1834,7 @@ static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains,
|
|
static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
|
|
{
|
|
struct b43_phy_lp *lpphy = dev->phy.lp;
|
|
- struct lpphy_tx_gains gains, oldgains;
|
|
+ struct lpphy_tx_gains oldgains;
|
|
int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
|
|
|
|
lpphy_read_tx_pctl_mode_from_hardware(dev);
|
|
@@ -1848,9 +1848,9 @@ static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
|
|
lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
|
|
|
|
if (dev->dev->chip_id == 0x4325 && dev->dev->chip_rev == 0)
|
|
- lpphy_papd_cal(dev, gains, 0, 1, 30);
|
|
+ lpphy_papd_cal(dev, oldgains, 0, 1, 30);
|
|
else
|
|
- lpphy_papd_cal(dev, gains, 0, 1, 65);
|
|
+ lpphy_papd_cal(dev, oldgains, 0, 1, 65);
|
|
|
|
if (old_afe_ovr)
|
|
lpphy_set_tx_gains(dev, oldgains);
|
|
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
|
|
index 230cad788ace..84b8b1eaa22c 100644
|
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h
|
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
|
|
@@ -214,7 +214,9 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt,
|
|
int prec);
|
|
|
|
/* Receive frame for delivery to OS. Callee disposes of rxp. */
|
|
-void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
|
|
+void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_event);
|
|
+/* Receive async event packet from firmware. Callee disposes of rxp. */
|
|
+void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
|
|
|
|
/* Indication from bus module regarding presence/insertion of dongle. */
|
|
int brcmf_attach(struct device *dev);
|
|
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
|
index ad35e760ed3f..231c0ba6acb9 100644
|
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
|
@@ -3328,9 +3328,15 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
|
|
struct brcmf_pno_scanresults_le *pfn_result;
|
|
u32 result_count;
|
|
u32 status;
|
|
+ u32 datalen;
|
|
|
|
brcmf_dbg(SCAN, "Enter\n");
|
|
|
|
+ if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
|
|
+ brcmf_dbg(SCAN, "Event data to small. Ignore\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
if (e->event_code == BRCMF_E_PFN_NET_LOST) {
|
|
brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
|
|
return 0;
|
|
@@ -3349,6 +3355,14 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
|
|
if (result_count > 0) {
|
|
int i;
|
|
|
|
+ data += sizeof(struct brcmf_pno_scanresults_le);
|
|
+ netinfo_start = (struct brcmf_pno_net_info_le *)data;
|
|
+ datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
|
|
+ if (datalen < result_count * sizeof(*netinfo)) {
|
|
+ brcmf_err("insufficient event data\n");
|
|
+ goto out_err;
|
|
+ }
|
|
+
|
|
request = kzalloc(sizeof(*request), GFP_KERNEL);
|
|
ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
|
|
channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
|
|
@@ -3358,9 +3372,6 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
|
|
}
|
|
|
|
request->wiphy = wiphy;
|
|
- data += sizeof(struct brcmf_pno_scanresults_le);
|
|
- netinfo_start = (struct brcmf_pno_net_info_le *)data;
|
|
-
|
|
for (i = 0; i < result_count; i++) {
|
|
netinfo = &netinfo_start[i];
|
|
if (!netinfo) {
|
|
@@ -3370,6 +3381,8 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
|
|
goto out_err;
|
|
}
|
|
|
|
+ if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
|
|
+ netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
|
|
brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
|
|
netinfo->SSID, netinfo->channel);
|
|
memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
|
|
@@ -4836,6 +4849,8 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
|
|
conn_info->req_ie =
|
|
kmemdup(cfg->extra_buf, conn_info->req_ie_len,
|
|
GFP_KERNEL);
|
|
+ if (!conn_info->req_ie)
|
|
+ conn_info->req_ie_len = 0;
|
|
} else {
|
|
conn_info->req_ie_len = 0;
|
|
conn_info->req_ie = NULL;
|
|
@@ -4852,6 +4867,8 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
|
|
conn_info->resp_ie =
|
|
kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
|
|
GFP_KERNEL);
|
|
+ if (!conn_info->resp_ie)
|
|
+ conn_info->resp_ie_len = 0;
|
|
} else {
|
|
conn_info->resp_ie_len = 0;
|
|
conn_info->resp_ie = NULL;
|
|
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c
|
|
index 82753e7c7e7c..3082391c3062 100644
|
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
|
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
|
|
@@ -303,15 +303,9 @@ void brcmf_txflowblock(struct device *dev, bool state)
|
|
|
|
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
|
|
{
|
|
- skb->dev = ifp->ndev;
|
|
- skb->protocol = eth_type_trans(skb, skb->dev);
|
|
-
|
|
if (skb->pkt_type == PACKET_MULTICAST)
|
|
ifp->stats.multicast++;
|
|
|
|
- /* Process special event packets */
|
|
- brcmf_fweh_process_skb(ifp->drvr, skb);
|
|
-
|
|
if (!(ifp->ndev->flags & IFF_UP)) {
|
|
brcmu_pkt_buf_free_skb(skb);
|
|
return;
|
|
@@ -526,7 +520,7 @@ netif_rx:
|
|
}
|
|
}
|
|
|
|
-void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
|
|
+void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event)
|
|
{
|
|
struct brcmf_if *ifp;
|
|
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
|
@@ -546,11 +540,44 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
|
|
return;
|
|
}
|
|
|
|
+ skb->protocol = eth_type_trans(skb, ifp->ndev);
|
|
+
|
|
rd = (struct brcmf_skb_reorder_data *)skb->cb;
|
|
- if (rd->reorder)
|
|
+ if (rd->reorder) {
|
|
brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
|
|
- else
|
|
+ } else {
|
|
+ /* Process special event packets */
|
|
+ if (handle_event)
|
|
+ brcmf_fweh_process_skb(ifp->drvr, skb,
|
|
+ BCMILCP_SUBTYPE_VENDOR_LONG);
|
|
+
|
|
brcmf_netif_rx(ifp, skb);
|
|
+ }
|
|
+}
|
|
+
|
|
+void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
|
|
+{
|
|
+ struct brcmf_if *ifp;
|
|
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
|
+ struct brcmf_pub *drvr = bus_if->drvr;
|
|
+ int ret;
|
|
+
|
|
+ brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
|
|
+
|
|
+ /* process and remove protocol-specific header */
|
|
+ ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
|
|
+
|
|
+ if (ret || !ifp || !ifp->ndev) {
|
|
+ if (ret != -ENODATA && ifp)
|
|
+ ifp->stats.rx_errors++;
|
|
+ brcmu_pkt_buf_free_skb(skb);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ skb->protocol = eth_type_trans(skb, ifp->ndev);
|
|
+
|
|
+ brcmf_fweh_process_skb(ifp->drvr, skb, 0);
|
|
+ brcmu_pkt_buf_free_skb(skb);
|
|
}
|
|
|
|
void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
|
|
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
|
|
index 3878b6f6cfce..f9aa37032c2d 100644
|
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
|
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
|
|
@@ -25,50 +25,6 @@
|
|
#include "fweh.h"
|
|
#include "fwil.h"
|
|
|
|
-/**
|
|
- * struct brcm_ethhdr - broadcom specific ether header.
|
|
- *
|
|
- * @subtype: subtype for this packet.
|
|
- * @length: TODO: length of appended data.
|
|
- * @version: version indication.
|
|
- * @oui: OUI of this packet.
|
|
- * @usr_subtype: subtype for this OUI.
|
|
- */
|
|
-struct brcm_ethhdr {
|
|
- __be16 subtype;
|
|
- __be16 length;
|
|
- u8 version;
|
|
- u8 oui[3];
|
|
- __be16 usr_subtype;
|
|
-} __packed;
|
|
-
|
|
-struct brcmf_event_msg_be {
|
|
- __be16 version;
|
|
- __be16 flags;
|
|
- __be32 event_type;
|
|
- __be32 status;
|
|
- __be32 reason;
|
|
- __be32 auth_type;
|
|
- __be32 datalen;
|
|
- u8 addr[ETH_ALEN];
|
|
- char ifname[IFNAMSIZ];
|
|
- u8 ifidx;
|
|
- u8 bsscfgidx;
|
|
-} __packed;
|
|
-
|
|
-/**
|
|
- * struct brcmf_event - contents of broadcom event packet.
|
|
- *
|
|
- * @eth: standard ether header.
|
|
- * @hdr: broadcom specific ether header.
|
|
- * @msg: common part of the actual event message.
|
|
- */
|
|
-struct brcmf_event {
|
|
- struct ethhdr eth;
|
|
- struct brcm_ethhdr hdr;
|
|
- struct brcmf_event_msg_be msg;
|
|
-} __packed;
|
|
-
|
|
/**
|
|
* struct brcmf_fweh_queue_item - event item on event queue.
|
|
*
|
|
@@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item {
|
|
u8 ifidx;
|
|
u8 ifaddr[ETH_ALEN];
|
|
struct brcmf_event_msg_be emsg;
|
|
+ u32 datalen;
|
|
u8 data[0];
|
|
};
|
|
|
|
@@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
|
|
brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
|
|
min_t(u32, emsg.datalen, 64),
|
|
"event payload, len=%d\n", emsg.datalen);
|
|
+ if (emsg.datalen > event->datalen) {
|
|
+ brcmf_err("event invalid length header=%d, msg=%d\n",
|
|
+ event->datalen, emsg.datalen);
|
|
+ goto event_free;
|
|
+ }
|
|
|
|
/* special handling of interface event */
|
|
if (event->code == BRCMF_E_IF) {
|
|
@@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp)
|
|
* dispatch the event to a registered handler (using worker).
|
|
*/
|
|
void brcmf_fweh_process_event(struct brcmf_pub *drvr,
|
|
- struct brcmf_event *event_packet)
|
|
+ struct brcmf_event *event_packet,
|
|
+ u32 packet_len)
|
|
{
|
|
enum brcmf_fweh_event_code code;
|
|
struct brcmf_fweh_info *fweh = &drvr->fweh;
|
|
@@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
|
|
if (code != BRCMF_E_IF && !fweh->evt_handler[code])
|
|
return;
|
|
|
|
+ if (datalen > BRCMF_DCMD_MAXLEN)
|
|
+ return;
|
|
+
|
|
if (in_interrupt())
|
|
alloc_flag = GFP_ATOMIC;
|
|
|
|
@@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
|
|
/* use memcpy to get aligned event message */
|
|
memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
|
|
memcpy(event->data, data, datalen);
|
|
+ event->datalen = datalen;
|
|
memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
|
|
|
|
brcmf_fweh_queue_event(fweh, event);
|
|
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
|
|
index d9a942842382..b53db92341ce 100644
|
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
|
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
|
|
@@ -27,7 +27,6 @@
|
|
struct brcmf_pub;
|
|
struct brcmf_if;
|
|
struct brcmf_cfg80211_info;
|
|
-struct brcmf_event;
|
|
|
|
/* list of firmware events */
|
|
#define BRCMF_FWEH_EVENT_ENUM_DEFLIST \
|
|
@@ -180,11 +179,53 @@ enum brcmf_fweh_event_code {
|
|
/**
|
|
* definitions for event packet validation.
|
|
*/
|
|
-#define BRCMF_EVENT_OUI_OFFSET 19
|
|
-#define BRCM_OUI "\x00\x10\x18"
|
|
-#define DOT11_OUI_LEN 3
|
|
-#define BCMILCP_BCM_SUBTYPE_EVENT 1
|
|
+#define BRCM_OUI "\x00\x10\x18"
|
|
+#define BCMILCP_BCM_SUBTYPE_EVENT 1
|
|
+#define BCMILCP_SUBTYPE_VENDOR_LONG 32769
|
|
|
|
+/**
|
|
+ * struct brcm_ethhdr - broadcom specific ether header.
|
|
+ *
|
|
+ * @subtype: subtype for this packet.
|
|
+ * @length: TODO: length of appended data.
|
|
+ * @version: version indication.
|
|
+ * @oui: OUI of this packet.
|
|
+ * @usr_subtype: subtype for this OUI.
|
|
+ */
|
|
+struct brcm_ethhdr {
|
|
+ __be16 subtype;
|
|
+ __be16 length;
|
|
+ u8 version;
|
|
+ u8 oui[3];
|
|
+ __be16 usr_subtype;
|
|
+} __packed;
|
|
+
|
|
+struct brcmf_event_msg_be {
|
|
+ __be16 version;
|
|
+ __be16 flags;
|
|
+ __be32 event_type;
|
|
+ __be32 status;
|
|
+ __be32 reason;
|
|
+ __be32 auth_type;
|
|
+ __be32 datalen;
|
|
+ u8 addr[ETH_ALEN];
|
|
+ char ifname[IFNAMSIZ];
|
|
+ u8 ifidx;
|
|
+ u8 bsscfgidx;
|
|
+} __packed;
|
|
+
|
|
+/**
|
|
+ * struct brcmf_event - contents of broadcom event packet.
|
|
+ *
|
|
+ * @eth: standard ether header.
|
|
+ * @hdr: broadcom specific ether header.
|
|
+ * @msg: common part of the actual event message.
|
|
+ */
|
|
+struct brcmf_event {
|
|
+ struct ethhdr eth;
|
|
+ struct brcm_ethhdr hdr;
|
|
+ struct brcmf_event_msg_be msg;
|
|
+} __packed;
|
|
|
|
/**
|
|
* struct brcmf_event_msg - firmware event message.
|
|
@@ -256,34 +297,43 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr,
|
|
enum brcmf_fweh_event_code code);
|
|
int brcmf_fweh_activate_events(struct brcmf_if *ifp);
|
|
void brcmf_fweh_process_event(struct brcmf_pub *drvr,
|
|
- struct brcmf_event *event_packet);
|
|
+ struct brcmf_event *event_packet,
|
|
+ u32 packet_len);
|
|
void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
|
|
|
|
static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
|
|
- struct sk_buff *skb)
|
|
+ struct sk_buff *skb, u16 stype)
|
|
{
|
|
struct brcmf_event *event_packet;
|
|
- u8 *data;
|
|
- u16 usr_stype;
|
|
+ u16 subtype, usr_stype;
|
|
|
|
/* only process events when protocol matches */
|
|
if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
|
|
return;
|
|
|
|
- /* check for BRCM oui match */
|
|
+ if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
|
|
+ return;
|
|
+
|
|
event_packet = (struct brcmf_event *)skb_mac_header(skb);
|
|
- data = (u8 *)event_packet;
|
|
- data += BRCMF_EVENT_OUI_OFFSET;
|
|
- if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
|
|
+
|
|
+ /* check subtype if needed */
|
|
+ if (unlikely(stype)) {
|
|
+ subtype = get_unaligned_be16(&event_packet->hdr.subtype);
|
|
+ if (subtype != stype)
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* check for BRCM oui match */
|
|
+ if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
|
|
+ sizeof(event_packet->hdr.oui)))
|
|
return;
|
|
|
|
/* final match on usr_subtype */
|
|
- data += DOT11_OUI_LEN;
|
|
- usr_stype = get_unaligned_be16(data);
|
|
+ usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype);
|
|
if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
|
|
return;
|
|
|
|
- brcmf_fweh_process_event(drvr, event_packet);
|
|
+ brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN);
|
|
}
|
|
|
|
#endif /* FWEH_H_ */
|
|
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
|
index 44e618f9d890..6f7138cea555 100644
|
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
|
@@ -20,6 +20,7 @@
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/netdevice.h>
|
|
+#include <linux/etherdevice.h>
|
|
|
|
#include <brcmu_utils.h>
|
|
#include <brcmu_wifi.h>
|
|
@@ -1076,28 +1077,13 @@ static void brcmf_msgbuf_rxbuf_event_post(struct brcmf_msgbuf *msgbuf)
|
|
}
|
|
|
|
|
|
-static void
|
|
-brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
|
|
- u8 ifidx)
|
|
-{
|
|
- struct brcmf_if *ifp;
|
|
-
|
|
- ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
|
|
- if (!ifp || !ifp->ndev) {
|
|
- brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
|
|
- brcmu_pkt_buf_free_skb(skb);
|
|
- return;
|
|
- }
|
|
- brcmf_netif_rx(ifp, skb);
|
|
-}
|
|
-
|
|
-
|
|
static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
|
|
{
|
|
struct msgbuf_rx_event *event;
|
|
u32 idx;
|
|
u16 buflen;
|
|
struct sk_buff *skb;
|
|
+ struct brcmf_if *ifp;
|
|
|
|
event = (struct msgbuf_rx_event *)buf;
|
|
idx = le32_to_cpu(event->msg.request_id);
|
|
@@ -1117,7 +1103,19 @@ static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
|
|
|
|
skb_trim(skb, buflen);
|
|
|
|
- brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx);
|
|
+ ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);
|
|
+ if (!ifp || !ifp->ndev) {
|
|
+ brcmf_err("Received pkt for invalid ifidx %d\n",
|
|
+ event->msg.ifidx);
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ skb->protocol = eth_type_trans(skb, ifp->ndev);
|
|
+
|
|
+ brcmf_fweh_process_skb(ifp->drvr, skb, 0);
|
|
+
|
|
+exit:
|
|
+ brcmu_pkt_buf_free_skb(skb);
|
|
}
|
|
|
|
|
|
@@ -1129,6 +1127,7 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
|
|
u16 data_offset;
|
|
u16 buflen;
|
|
u32 idx;
|
|
+ struct brcmf_if *ifp;
|
|
|
|
brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);
|
|
|
|
@@ -1149,7 +1148,14 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
|
|
|
|
skb_trim(skb, buflen);
|
|
|
|
- brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx);
|
|
+ ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
|
|
+ if (!ifp || !ifp->ndev) {
|
|
+ brcmf_err("Received pkt for invalid ifidx %d\n",
|
|
+ rx_complete->msg.ifidx);
|
|
+ brcmu_pkt_buf_free_skb(skb);
|
|
+ return;
|
|
+ }
|
|
+ brcmf_netif_rx(ifp, skb);
|
|
}
|
|
|
|
|
|
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
|
|
index 3196245ab820..e6c8b0d5afe0 100644
|
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
|
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
|
|
@@ -1365,6 +1365,11 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
|
|
u16 mgmt_type;
|
|
u8 action;
|
|
|
|
+ if (e->datalen < sizeof(*rxframe)) {
|
|
+ brcmf_dbg(SCAN, "Event data to small. Ignore\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
ch.chspec = be16_to_cpu(rxframe->chanspec);
|
|
cfg->d11inf.decchspec(&ch);
|
|
/* Check if wpa_supplicant has registered for this frame */
|
|
@@ -1862,6 +1867,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
|
|
brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
|
|
e->reason);
|
|
|
|
+ if (e->datalen < sizeof(*rxframe)) {
|
|
+ brcmf_dbg(SCAN, "Event data to small. Ignore\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
ch.chspec = be16_to_cpu(rxframe->chanspec);
|
|
cfg->d11inf.decchspec(&ch);
|
|
|
|
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
|
index 35f62b00f1df..9954e641c943 100644
|
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
|
@@ -1394,6 +1394,17 @@ static inline u8 brcmf_sdio_getdatoffset(u8 *swheader)
|
|
return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
|
|
}
|
|
|
|
+static inline bool brcmf_sdio_fromevntchan(u8 *swheader)
|
|
+{
|
|
+ u32 hdrvalue;
|
|
+ u8 ret;
|
|
+
|
|
+ hdrvalue = *(u32 *)swheader;
|
|
+ ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT);
|
|
+
|
|
+ return (ret == SDPCM_EVENT_CHANNEL);
|
|
+}
|
|
+
|
|
static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
|
|
struct brcmf_sdio_hdrinfo *rd,
|
|
enum brcmf_sdio_frmtype type)
|
|
@@ -1754,7 +1765,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
|
|
pfirst->len, pfirst->next,
|
|
pfirst->prev);
|
|
skb_unlink(pfirst, &bus->glom);
|
|
- brcmf_rx_frame(bus->sdiodev->dev, pfirst);
|
|
+ if (brcmf_sdio_fromevntchan(&dptr[SDPCM_HWHDR_LEN]))
|
|
+ brcmf_rx_event(bus->sdiodev->dev, pfirst);
|
|
+ else
|
|
+ brcmf_rx_frame(bus->sdiodev->dev, pfirst,
|
|
+ false);
|
|
bus->sdcnt.rxglompkts++;
|
|
}
|
|
|
|
@@ -2081,18 +2096,19 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
|
|
__skb_trim(pkt, rd->len);
|
|
skb_pull(pkt, rd->dat_offset);
|
|
|
|
+ if (pkt->len == 0)
|
|
+ brcmu_pkt_buf_free_skb(pkt);
|
|
+ else if (rd->channel == SDPCM_EVENT_CHANNEL)
|
|
+ brcmf_rx_event(bus->sdiodev->dev, pkt);
|
|
+ else
|
|
+ brcmf_rx_frame(bus->sdiodev->dev, pkt,
|
|
+ false);
|
|
+
|
|
/* prepare the descriptor for the next read */
|
|
rd->len = rd->len_nxtfrm << 4;
|
|
rd->len_nxtfrm = 0;
|
|
/* treat all packet as event if we don't know */
|
|
rd->channel = SDPCM_EVENT_CHANNEL;
|
|
-
|
|
- if (pkt->len == 0) {
|
|
- brcmu_pkt_buf_free_skb(pkt);
|
|
- continue;
|
|
- }
|
|
-
|
|
- brcmf_rx_frame(bus->sdiodev->dev, pkt);
|
|
}
|
|
|
|
rxcount = maxframes - rxleft;
|
|
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
|
|
index 689e64d004bc..3002268e57f3 100644
|
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
|
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
|
|
@@ -144,7 +144,7 @@ struct brcmf_usbdev_info {
|
|
|
|
struct usb_device *usbdev;
|
|
struct device *dev;
|
|
- struct mutex dev_init_lock;
|
|
+ struct completion dev_init_done;
|
|
|
|
int ctl_in_pipe, ctl_out_pipe;
|
|
struct urb *ctl_urb; /* URB for control endpoint */
|
|
@@ -502,7 +502,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
|
|
|
|
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
|
|
skb_put(skb, urb->actual_length);
|
|
- brcmf_rx_frame(devinfo->dev, skb);
|
|
+ brcmf_rx_frame(devinfo->dev, skb, true);
|
|
brcmf_usb_rx_refill(devinfo, req);
|
|
} else {
|
|
brcmu_pkt_buf_free_skb(skb);
|
|
@@ -669,12 +669,18 @@ static int brcmf_usb_up(struct device *dev)
|
|
|
|
static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
|
|
{
|
|
+ int i;
|
|
+
|
|
if (devinfo->ctl_urb)
|
|
usb_kill_urb(devinfo->ctl_urb);
|
|
if (devinfo->bulk_urb)
|
|
usb_kill_urb(devinfo->bulk_urb);
|
|
- brcmf_usb_free_q(&devinfo->tx_postq, true);
|
|
- brcmf_usb_free_q(&devinfo->rx_postq, true);
|
|
+ if (devinfo->tx_reqs)
|
|
+ for (i = 0; i < devinfo->bus_pub.ntxq; i++)
|
|
+ usb_kill_urb(devinfo->tx_reqs[i].urb);
|
|
+ if (devinfo->rx_reqs)
|
|
+ for (i = 0; i < devinfo->bus_pub.nrxq; i++)
|
|
+ usb_kill_urb(devinfo->rx_reqs[i].urb);
|
|
}
|
|
|
|
static void brcmf_usb_down(struct device *dev)
|
|
@@ -1226,11 +1232,11 @@ static void brcmf_usb_probe_phase2(struct device *dev,
|
|
if (ret)
|
|
goto error;
|
|
|
|
- mutex_unlock(&devinfo->dev_init_lock);
|
|
+ complete(&devinfo->dev_init_done);
|
|
return;
|
|
error:
|
|
brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret);
|
|
- mutex_unlock(&devinfo->dev_init_lock);
|
|
+ complete(&devinfo->dev_init_done);
|
|
device_release_driver(dev);
|
|
}
|
|
|
|
@@ -1268,7 +1274,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
|
|
if (ret)
|
|
goto fail;
|
|
/* we are done */
|
|
- mutex_unlock(&devinfo->dev_init_lock);
|
|
+ complete(&devinfo->dev_init_done);
|
|
return 0;
|
|
}
|
|
bus->chip = bus_pub->devid;
|
|
@@ -1322,11 +1328,10 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|
|
|
devinfo->usbdev = usb;
|
|
devinfo->dev = &usb->dev;
|
|
- /* Take an init lock, to protect for disconnect while still loading.
|
|
+ /* Init completion, to protect for disconnect while still loading.
|
|
* Necessary because of the asynchronous firmware load construction
|
|
*/
|
|
- mutex_init(&devinfo->dev_init_lock);
|
|
- mutex_lock(&devinfo->dev_init_lock);
|
|
+ init_completion(&devinfo->dev_init_done);
|
|
|
|
usb_set_intfdata(intf, devinfo);
|
|
|
|
@@ -1402,7 +1407,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|
return 0;
|
|
|
|
fail:
|
|
- mutex_unlock(&devinfo->dev_init_lock);
|
|
+ complete(&devinfo->dev_init_done);
|
|
kfree(devinfo);
|
|
usb_set_intfdata(intf, NULL);
|
|
return ret;
|
|
@@ -1417,7 +1422,7 @@ brcmf_usb_disconnect(struct usb_interface *intf)
|
|
devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
|
|
|
|
if (devinfo) {
|
|
- mutex_lock(&devinfo->dev_init_lock);
|
|
+ wait_for_completion(&devinfo->dev_init_done);
|
|
/* Make sure that devinfo still exists. Firmware probe routines
|
|
* may have released the device and cleared the intfdata.
|
|
*/
|
|
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/vendor.c b/drivers/net/wireless/brcm80211/brcmfmac/vendor.c
|
|
index 8eff2753abad..d493021f6031 100644
|
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/vendor.c
|
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/vendor.c
|
|
@@ -35,9 +35,10 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
|
|
struct brcmf_if *ifp;
|
|
const struct brcmf_vndr_dcmd_hdr *cmdhdr = data;
|
|
struct sk_buff *reply;
|
|
- int ret, payload, ret_len;
|
|
+ unsigned int payload, ret_len;
|
|
void *dcmd_buf = NULL, *wr_pointer;
|
|
u16 msglen, maxmsglen = PAGE_SIZE - 0x100;
|
|
+ int ret;
|
|
|
|
if (len < sizeof(*cmdhdr)) {
|
|
brcmf_err("vendor command too short: %d\n", len);
|
|
@@ -65,7 +66,7 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
|
|
brcmf_err("oversize return buffer %d\n", ret_len);
|
|
ret_len = BRCMF_DCMD_MAXLEN;
|
|
}
|
|
- payload = max(ret_len, len) + 1;
|
|
+ payload = max_t(unsigned int, ret_len, len) + 1;
|
|
dcmd_buf = vzalloc(payload);
|
|
if (NULL == dcmd_buf)
|
|
return -ENOMEM;
|
|
diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c
|
|
index 0e51e27d2e3f..317daa968e03 100644
|
|
--- a/drivers/net/wireless/cw1200/main.c
|
|
+++ b/drivers/net/wireless/cw1200/main.c
|
|
@@ -345,6 +345,11 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
|
|
mutex_init(&priv->wsm_cmd_mux);
|
|
mutex_init(&priv->conf_mutex);
|
|
priv->workqueue = create_singlethread_workqueue("cw1200_wq");
|
|
+ if (!priv->workqueue) {
|
|
+ ieee80211_free_hw(hw);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
sema_init(&priv->scan.lock, 1);
|
|
INIT_WORK(&priv->scan.work, cw1200_scan_work);
|
|
INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work);
|
|
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
|
|
index 3ddb8ec676ed..6dd331dfb517 100644
|
|
--- a/drivers/net/wireless/mwifiex/cfp.c
|
|
+++ b/drivers/net/wireless/mwifiex/cfp.c
|
|
@@ -533,5 +533,8 @@ u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv,
|
|
rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ?
|
|
rx_rate - 1 : rx_rate;
|
|
|
|
+ if (rate_index >= MWIFIEX_MAX_AC_RX_RATES)
|
|
+ rate_index = MWIFIEX_MAX_AC_RX_RATES - 1;
|
|
+
|
|
return rate_index;
|
|
}
|
|
diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c
|
|
index aab752328c26..5013d8c1d4a6 100644
|
|
--- a/drivers/net/wireless/realtek/rtlwifi/base.c
|
|
+++ b/drivers/net/wireless/realtek/rtlwifi/base.c
|
|
@@ -466,6 +466,11 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
|
|
/* <2> work queue */
|
|
rtlpriv->works.hw = hw;
|
|
rtlpriv->works.rtl_wq = alloc_workqueue("%s", 0, 0, rtlpriv->cfg->name);
|
|
+ if (unlikely(!rtlpriv->works.rtl_wq)) {
|
|
+ pr_err("Failed to allocate work queue\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq,
|
|
(void *)rtl_watchdog_wq_callback);
|
|
INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
|
|
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
|
|
index 34f1d6b41fb9..cc3708ea8084 100644
|
|
--- a/drivers/parisc/ccio-dma.c
|
|
+++ b/drivers/parisc/ccio-dma.c
|
|
@@ -563,8 +563,6 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
|
|
/* We currently only support kernel addresses */
|
|
BUG_ON(sid != KERNEL_SPACE);
|
|
|
|
- mtsp(sid,1);
|
|
-
|
|
/*
|
|
** WORD 1 - low order word
|
|
** "hints" parm includes the VALID bit!
|
|
@@ -595,7 +593,7 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
|
|
** Grab virtual index [0:11]
|
|
** Deposit virt_idx bits into I/O PDIR word
|
|
*/
|
|
- asm volatile ("lci %%r0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
|
|
+ asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (vba));
|
|
asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci));
|
|
asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci));
|
|
|
|
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
|
|
index d6326144ce01..f3b9746157f8 100644
|
|
--- a/drivers/parisc/sba_iommu.c
|
|
+++ b/drivers/parisc/sba_iommu.c
|
|
@@ -573,8 +573,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
|
|
pa = virt_to_phys(vba);
|
|
pa &= IOVP_MASK;
|
|
|
|
- mtsp(sid,1);
|
|
- asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
|
|
+ asm("lci 0(%1), %0" : "=r" (ci) : "r" (vba));
|
|
pa |= (ci >> PAGE_SHIFT) & 0xff; /* move CI (8 bits) into lowest byte */
|
|
|
|
pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
|
|
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
|
|
index d85010ebac5a..36c6f3702167 100644
|
|
--- a/drivers/pci/quirks.c
|
|
+++ b/drivers/pci/quirks.c
|
|
@@ -3141,6 +3141,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset);
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset);
|
|
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034, quirk_no_bus_reset);
|
|
|
|
static void quirk_no_pm_reset(struct pci_dev *dev)
|
|
{
|
|
diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c
|
|
index 98a459b1c095..86e8d989092c 100644
|
|
--- a/drivers/pinctrl/pinctrl-pistachio.c
|
|
+++ b/drivers/pinctrl/pinctrl-pistachio.c
|
|
@@ -1373,6 +1373,7 @@ static int pistachio_gpio_register(struct pistachio_pinctrl *pctl)
|
|
if (!of_find_property(child, "gpio-controller", NULL)) {
|
|
dev_err(pctl->dev,
|
|
"No gpio-controller property for bank %u\n", i);
|
|
+ of_node_put(child);
|
|
ret = -ENODEV;
|
|
goto err;
|
|
}
|
|
@@ -1380,6 +1381,7 @@ static int pistachio_gpio_register(struct pistachio_pinctrl *pctl)
|
|
irq = irq_of_parse_and_map(child, 0);
|
|
if (irq < 0) {
|
|
dev_err(pctl->dev, "No IRQ for bank %u: %d\n", i, irq);
|
|
+ of_node_put(child);
|
|
ret = irq;
|
|
goto err;
|
|
}
|
|
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
|
|
index ed2d7fd0c734..488dd7eb0aeb 100644
|
|
--- a/drivers/power/power_supply_sysfs.c
|
|
+++ b/drivers/power/power_supply_sysfs.c
|
|
@@ -277,15 +277,11 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|
char *prop_buf;
|
|
char *attrname;
|
|
|
|
- dev_dbg(dev, "uevent\n");
|
|
-
|
|
if (!psy || !psy->desc) {
|
|
dev_dbg(dev, "No power supply yet\n");
|
|
return ret;
|
|
}
|
|
|
|
- dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->desc->name);
|
|
-
|
|
ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->desc->name);
|
|
if (ret)
|
|
return ret;
|
|
@@ -321,8 +317,6 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|
goto out;
|
|
}
|
|
|
|
- dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
|
|
-
|
|
ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
|
|
kfree(attrname);
|
|
if (ret)
|
|
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
|
|
index 19e53b3b8e00..166faae3a59c 100644
|
|
--- a/drivers/rtc/rtc-88pm860x.c
|
|
+++ b/drivers/rtc/rtc-88pm860x.c
|
|
@@ -414,7 +414,7 @@ static int pm860x_rtc_remove(struct platform_device *pdev)
|
|
struct pm860x_rtc_info *info = platform_get_drvdata(pdev);
|
|
|
|
#ifdef VRTC_CALIBRATION
|
|
- flush_scheduled_work();
|
|
+ cancel_delayed_work_sync(&info->calib_work);
|
|
/* disable measurement */
|
|
pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
|
|
#endif /* VRTC_CALIBRATION */
|
|
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
|
|
index a01376ae1749..fdb87520543f 100644
|
|
--- a/drivers/s390/cio/cio.h
|
|
+++ b/drivers/s390/cio/cio.h
|
|
@@ -102,7 +102,7 @@ struct subchannel {
|
|
struct schib_config config;
|
|
} __attribute__ ((aligned(8)));
|
|
|
|
-DECLARE_PER_CPU(struct irb, cio_irb);
|
|
+DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb);
|
|
|
|
#define to_subchannel(n) container_of(n, struct subchannel, dev)
|
|
|
|
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
|
|
index a39a74500e23..aeb93478482f 100644
|
|
--- a/drivers/s390/scsi/zfcp_ext.h
|
|
+++ b/drivers/s390/scsi/zfcp_ext.h
|
|
@@ -161,6 +161,7 @@ extern const struct attribute_group *zfcp_port_attr_groups[];
|
|
extern struct mutex zfcp_sysfs_port_units_mutex;
|
|
extern struct device_attribute *zfcp_sysfs_sdev_attrs[];
|
|
extern struct device_attribute *zfcp_sysfs_shost_attrs[];
|
|
+bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port);
|
|
|
|
/* zfcp_unit.c */
|
|
extern int zfcp_unit_add(struct zfcp_port *, u64);
|
|
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
|
|
index bdb257eaa2e5..68146b398603 100644
|
|
--- a/drivers/s390/scsi/zfcp_scsi.c
|
|
+++ b/drivers/s390/scsi/zfcp_scsi.c
|
|
@@ -124,6 +124,15 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)
|
|
|
|
zfcp_sdev->erp_action.port = port;
|
|
|
|
+ mutex_lock(&zfcp_sysfs_port_units_mutex);
|
|
+ if (zfcp_sysfs_port_is_removing(port)) {
|
|
+ /* port is already gone */
|
|
+ mutex_unlock(&zfcp_sysfs_port_units_mutex);
|
|
+ put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */
|
|
+ return -ENXIO;
|
|
+ }
|
|
+ mutex_unlock(&zfcp_sysfs_port_units_mutex);
|
|
+
|
|
unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev));
|
|
if (unit)
|
|
put_device(&unit->dev);
|
|
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
|
|
index 96a0be13e841..5df597d1b978 100644
|
|
--- a/drivers/s390/scsi/zfcp_sysfs.c
|
|
+++ b/drivers/s390/scsi/zfcp_sysfs.c
|
|
@@ -237,6 +237,53 @@ static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
|
|
|
|
DEFINE_MUTEX(zfcp_sysfs_port_units_mutex);
|
|
|
|
+static void zfcp_sysfs_port_set_removing(struct zfcp_port *const port)
|
|
+{
|
|
+ lockdep_assert_held(&zfcp_sysfs_port_units_mutex);
|
|
+ atomic_set(&port->units, -1);
|
|
+}
|
|
+
|
|
+bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port)
|
|
+{
|
|
+ lockdep_assert_held(&zfcp_sysfs_port_units_mutex);
|
|
+ return atomic_read(&port->units) == -1;
|
|
+}
|
|
+
|
|
+static bool zfcp_sysfs_port_in_use(struct zfcp_port *const port)
|
|
+{
|
|
+ struct zfcp_adapter *const adapter = port->adapter;
|
|
+ unsigned long flags;
|
|
+ struct scsi_device *sdev;
|
|
+ bool in_use = true;
|
|
+
|
|
+ mutex_lock(&zfcp_sysfs_port_units_mutex);
|
|
+ if (atomic_read(&port->units) > 0)
|
|
+ goto unlock_port_units_mutex; /* zfcp_unit(s) under port */
|
|
+
|
|
+ spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
|
|
+ __shost_for_each_device(sdev, adapter->scsi_host) {
|
|
+ const struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
|
|
+
|
|
+ if (sdev->sdev_state == SDEV_DEL ||
|
|
+ sdev->sdev_state == SDEV_CANCEL)
|
|
+ continue;
|
|
+ if (zsdev->port != port)
|
|
+ continue;
|
|
+ /* alive scsi_device under port of interest */
|
|
+ goto unlock_host_lock;
|
|
+ }
|
|
+
|
|
+ /* port is about to be removed, so no more unit_add or slave_alloc */
|
|
+ zfcp_sysfs_port_set_removing(port);
|
|
+ in_use = false;
|
|
+
|
|
+unlock_host_lock:
|
|
+ spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
|
|
+unlock_port_units_mutex:
|
|
+ mutex_unlock(&zfcp_sysfs_port_units_mutex);
|
|
+ return in_use;
|
|
+}
|
|
+
|
|
static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
@@ -259,15 +306,11 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
|
|
else
|
|
retval = 0;
|
|
|
|
- mutex_lock(&zfcp_sysfs_port_units_mutex);
|
|
- if (atomic_read(&port->units) > 0) {
|
|
+ if (zfcp_sysfs_port_in_use(port)) {
|
|
retval = -EBUSY;
|
|
- mutex_unlock(&zfcp_sysfs_port_units_mutex);
|
|
+ put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */
|
|
goto out;
|
|
}
|
|
- /* port is about to be removed, so no more unit_add */
|
|
- atomic_set(&port->units, -1);
|
|
- mutex_unlock(&zfcp_sysfs_port_units_mutex);
|
|
|
|
write_lock_irq(&adapter->port_list_lock);
|
|
list_del(&port->list);
|
|
diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c
|
|
index 157d3d203ba1..f00693698abc 100644
|
|
--- a/drivers/s390/scsi/zfcp_unit.c
|
|
+++ b/drivers/s390/scsi/zfcp_unit.c
|
|
@@ -122,7 +122,7 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
|
|
int retval = 0;
|
|
|
|
mutex_lock(&zfcp_sysfs_port_units_mutex);
|
|
- if (atomic_read(&port->units) == -1) {
|
|
+ if (zfcp_sysfs_port_is_removing(port)) {
|
|
/* port is already gone */
|
|
retval = -ENODEV;
|
|
goto out;
|
|
@@ -166,8 +166,14 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
|
|
write_lock_irq(&port->unit_list_lock);
|
|
list_add_tail(&unit->list, &port->unit_list);
|
|
write_unlock_irq(&port->unit_list_lock);
|
|
+ /*
|
|
+ * lock order: shost->scan_mutex before zfcp_sysfs_port_units_mutex
|
|
+ * due to zfcp_unit_scsi_scan() => zfcp_scsi_slave_alloc()
|
|
+ */
|
|
+ mutex_unlock(&zfcp_sysfs_port_units_mutex);
|
|
|
|
zfcp_unit_scsi_scan(unit);
|
|
+ return retval;
|
|
|
|
out:
|
|
mutex_unlock(&zfcp_sysfs_port_units_mutex);
|
|
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
|
|
index 1a6f65db615e..ee1f9ee995e5 100644
|
|
--- a/drivers/scsi/libsas/sas_expander.c
|
|
+++ b/drivers/scsi/libsas/sas_expander.c
|
|
@@ -2027,6 +2027,11 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
|
|
if ((SAS_ADDR(sas_addr) == 0) || (res == -ECOMM)) {
|
|
phy->phy_state = PHY_EMPTY;
|
|
sas_unregister_devs_sas_addr(dev, phy_id, last);
|
|
+ /*
|
|
+ * Even though the PHY is empty, for convenience we discover
|
|
+ * the PHY to update the PHY info, like negotiated linkrate.
|
|
+ */
|
|
+ sas_ex_phy_discover(dev, phy_id);
|
|
return res;
|
|
} else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) &&
|
|
dev_type_flutter(type, phy->attached_dev_type)) {
|
|
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
|
|
index 4131addfb872..a67950908db1 100644
|
|
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
|
|
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
|
|
@@ -902,7 +902,11 @@ lpfc_linkdown(struct lpfc_hba *phba)
|
|
lpfc_linkdown_port(vports[i]);
|
|
}
|
|
lpfc_destroy_vport_work_array(phba, vports);
|
|
- /* Clean up any firmware default rpi's */
|
|
+
|
|
+ /* Clean up any SLI3 firmware default rpi's */
|
|
+ if (phba->sli_rev > LPFC_SLI_REV3)
|
|
+ goto skip_unreg_did;
|
|
+
|
|
mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
|
if (mb) {
|
|
lpfc_unreg_did(phba, 0xffff, LPFC_UNREG_ALL_DFLT_RPIS, mb);
|
|
@@ -914,6 +918,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
|
|
}
|
|
}
|
|
|
|
+ skip_unreg_did:
|
|
/* Setup myDID for link up if we are in pt2pt mode */
|
|
if (phba->pport->fc_flag & FC_PT2PT) {
|
|
phba->pport->fc_myDID = 0;
|
|
@@ -4647,6 +4652,10 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport)
|
|
LPFC_MBOXQ_t *mbox;
|
|
int rc;
|
|
|
|
+ /* Unreg DID is an SLI3 operation. */
|
|
+ if (phba->sli_rev > LPFC_SLI_REV3)
|
|
+ return;
|
|
+
|
|
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
|
if (mbox) {
|
|
lpfc_unreg_did(phba, vport->vpi, LPFC_UNREG_ALL_DFLT_RPIS,
|
|
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
|
|
index c158967b59d7..d220b4f691c7 100644
|
|
--- a/drivers/scsi/qla4xxx/ql4_os.c
|
|
+++ b/drivers/scsi/qla4xxx/ql4_os.c
|
|
@@ -5939,7 +5939,7 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
|
|
val = rd_nvram_byte(ha, sec_addr);
|
|
if (val & BIT_7)
|
|
ddb_index[1] = (val & 0x7f);
|
|
-
|
|
+ goto exit_boot_info;
|
|
} else if (is_qla80XX(ha)) {
|
|
buf = dma_alloc_coherent(&ha->pdev->dev, size,
|
|
&buf_dma, GFP_KERNEL);
|
|
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
|
|
index 62adaca8fb97..91b9eca75b75 100644
|
|
--- a/drivers/scsi/sd.c
|
|
+++ b/drivers/scsi/sd.c
|
|
@@ -2396,7 +2396,6 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
|
|
int res;
|
|
struct scsi_device *sdp = sdkp->device;
|
|
struct scsi_mode_data data;
|
|
- int disk_ro = get_disk_ro(sdkp->disk);
|
|
int old_wp = sdkp->write_prot;
|
|
|
|
set_disk_ro(sdkp->disk, 0);
|
|
@@ -2437,7 +2436,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
|
|
"Test WP failed, assume Write Enabled\n");
|
|
} else {
|
|
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
|
|
- set_disk_ro(sdkp->disk, sdkp->write_prot || disk_ro);
|
|
+ set_disk_ro(sdkp->disk, sdkp->write_prot);
|
|
if (sdkp->first_scan || old_wp != sdkp->write_prot) {
|
|
sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
|
|
sdkp->write_prot ? "on" : "off");
|
|
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
|
|
index c94d465de941..7322a17660d1 100644
|
|
--- a/drivers/scsi/ufs/ufshcd.c
|
|
+++ b/drivers/scsi/ufs/ufshcd.c
|
|
@@ -4144,19 +4144,19 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba,
|
|
goto out;
|
|
}
|
|
|
|
- if (hba->vreg_info.vcc)
|
|
+ if (hba->vreg_info.vcc && hba->vreg_info.vcc->max_uA)
|
|
icc_level = ufshcd_get_max_icc_level(
|
|
hba->vreg_info.vcc->max_uA,
|
|
POWER_DESC_MAX_ACTV_ICC_LVLS - 1,
|
|
&desc_buf[PWR_DESC_ACTIVE_LVLS_VCC_0]);
|
|
|
|
- if (hba->vreg_info.vccq)
|
|
+ if (hba->vreg_info.vccq && hba->vreg_info.vccq->max_uA)
|
|
icc_level = ufshcd_get_max_icc_level(
|
|
hba->vreg_info.vccq->max_uA,
|
|
icc_level,
|
|
&desc_buf[PWR_DESC_ACTIVE_LVLS_VCCQ_0]);
|
|
|
|
- if (hba->vreg_info.vccq2)
|
|
+ if (hba->vreg_info.vccq2 && hba->vreg_info.vccq2->max_uA)
|
|
icc_level = ufshcd_get_max_icc_level(
|
|
hba->vreg_info.vccq2->max_uA,
|
|
icc_level,
|
|
@@ -4390,6 +4390,15 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
|
|
if (!vreg)
|
|
return 0;
|
|
|
|
+ /*
|
|
+ * "set_load" operation shall be required on those regulators
|
|
+ * which specifically configured current limitation. Otherwise
|
|
+ * zero max_uA may cause unexpected behavior when regulator is
|
|
+ * enabled or set as high power mode.
|
|
+ */
|
|
+ if (!vreg->max_uA)
|
|
+ return 0;
|
|
+
|
|
ret = regulator_set_load(vreg->reg, ua);
|
|
if (ret < 0) {
|
|
dev_err(dev, "%s: %s set load (ua=%d) failed, err=%d\n",
|
|
@@ -4425,12 +4434,15 @@ static int ufshcd_config_vreg(struct device *dev,
|
|
name = vreg->name;
|
|
|
|
if (regulator_count_voltages(reg) > 0) {
|
|
- min_uV = on ? vreg->min_uV : 0;
|
|
- ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
|
|
- if (ret) {
|
|
- dev_err(dev, "%s: %s set voltage failed, err=%d\n",
|
|
+ if (vreg->min_uV && vreg->max_uV) {
|
|
+ min_uV = on ? vreg->min_uV : 0;
|
|
+ ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
|
|
+ if (ret) {
|
|
+ dev_err(dev,
|
|
+ "%s: %s set voltage failed, err=%d\n",
|
|
__func__, name, ret);
|
|
- goto out;
|
|
+ goto out;
|
|
+ }
|
|
}
|
|
|
|
uA_load = on ? vreg->max_uA : 0;
|
|
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
|
|
index 3cac73e4c3e4..e87b6fc9f4c6 100644
|
|
--- a/drivers/spi/spi-pxa2xx.c
|
|
+++ b/drivers/spi/spi-pxa2xx.c
|
|
@@ -859,10 +859,14 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
|
|
|
|
rate = min_t(int, ssp_clk, rate);
|
|
|
|
+ /*
|
|
+ * Calculate the divisor for the SCR (Serial Clock Rate), avoiding
|
|
+ * that the SSP transmission rate can be greater than the device rate
|
|
+ */
|
|
if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
|
|
- return (ssp_clk / (2 * rate) - 1) & 0xff;
|
|
+ return (DIV_ROUND_UP(ssp_clk, 2 * rate) - 1) & 0xff;
|
|
else
|
|
- return (ssp_clk / rate - 1) & 0xfff;
|
|
+ return (DIV_ROUND_UP(ssp_clk, rate) - 1) & 0xfff;
|
|
}
|
|
|
|
static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
|
|
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
|
|
index 9882d93e7566..0556259377f7 100644
|
|
--- a/drivers/spi/spi-rspi.c
|
|
+++ b/drivers/spi/spi-rspi.c
|
|
@@ -279,7 +279,8 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
|
|
/* Sets parity, interrupt mask */
|
|
rspi_write8(rspi, 0x00, RSPI_SPCR2);
|
|
|
|
- /* Sets SPCMD */
|
|
+ /* Resets sequencer */
|
|
+ rspi_write8(rspi, 0, RSPI_SPSCR);
|
|
rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
|
|
rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
|
|
|
|
@@ -313,7 +314,8 @@ static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size)
|
|
rspi_write8(rspi, 0x00, RSPI_SSLND);
|
|
rspi_write8(rspi, 0x00, RSPI_SPND);
|
|
|
|
- /* Sets SPCMD */
|
|
+ /* Resets sequencer */
|
|
+ rspi_write8(rspi, 0, RSPI_SPSCR);
|
|
rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
|
|
rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
|
|
|
|
@@ -364,7 +366,8 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
|
|
/* Sets buffer to allow normal operation */
|
|
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
|
|
|
|
- /* Sets SPCMD */
|
|
+ /* Resets sequencer */
|
|
+ rspi_write8(rspi, 0, RSPI_SPSCR);
|
|
rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
|
|
|
|
/* Enables SPI function in master mode */
|
|
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
|
|
index 73779cecc3bb..705f515863d4 100644
|
|
--- a/drivers/spi/spi-tegra114.c
|
|
+++ b/drivers/spi/spi-tegra114.c
|
|
@@ -1067,27 +1067,19 @@ static int tegra_spi_probe(struct platform_device *pdev)
|
|
|
|
spi_irq = platform_get_irq(pdev, 0);
|
|
tspi->irq = spi_irq;
|
|
- ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
|
|
- tegra_spi_isr_thread, IRQF_ONESHOT,
|
|
- dev_name(&pdev->dev), tspi);
|
|
- if (ret < 0) {
|
|
- dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
|
|
- tspi->irq);
|
|
- goto exit_free_master;
|
|
- }
|
|
|
|
tspi->clk = devm_clk_get(&pdev->dev, "spi");
|
|
if (IS_ERR(tspi->clk)) {
|
|
dev_err(&pdev->dev, "can not get clock\n");
|
|
ret = PTR_ERR(tspi->clk);
|
|
- goto exit_free_irq;
|
|
+ goto exit_free_master;
|
|
}
|
|
|
|
tspi->rst = devm_reset_control_get(&pdev->dev, "spi");
|
|
if (IS_ERR(tspi->rst)) {
|
|
dev_err(&pdev->dev, "can not get reset\n");
|
|
ret = PTR_ERR(tspi->rst);
|
|
- goto exit_free_irq;
|
|
+ goto exit_free_master;
|
|
}
|
|
|
|
tspi->max_buf_size = SPI_FIFO_DEPTH << 2;
|
|
@@ -1095,7 +1087,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
|
|
|
|
ret = tegra_spi_init_dma_param(tspi, true);
|
|
if (ret < 0)
|
|
- goto exit_free_irq;
|
|
+ goto exit_free_master;
|
|
ret = tegra_spi_init_dma_param(tspi, false);
|
|
if (ret < 0)
|
|
goto exit_rx_dma_free;
|
|
@@ -1117,18 +1109,32 @@ static int tegra_spi_probe(struct platform_device *pdev)
|
|
dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret);
|
|
goto exit_pm_disable;
|
|
}
|
|
+
|
|
+ reset_control_assert(tspi->rst);
|
|
+ udelay(2);
|
|
+ reset_control_deassert(tspi->rst);
|
|
tspi->def_command1_reg = SPI_M_S;
|
|
tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
|
|
pm_runtime_put(&pdev->dev);
|
|
+ ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
|
|
+ tegra_spi_isr_thread, IRQF_ONESHOT,
|
|
+ dev_name(&pdev->dev), tspi);
|
|
+ if (ret < 0) {
|
|
+ dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
|
|
+ tspi->irq);
|
|
+ goto exit_pm_disable;
|
|
+ }
|
|
|
|
master->dev.of_node = pdev->dev.of_node;
|
|
ret = devm_spi_register_master(&pdev->dev, master);
|
|
if (ret < 0) {
|
|
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
|
|
- goto exit_pm_disable;
|
|
+ goto exit_free_irq;
|
|
}
|
|
return ret;
|
|
|
|
+exit_free_irq:
|
|
+ free_irq(spi_irq, tspi);
|
|
exit_pm_disable:
|
|
pm_runtime_disable(&pdev->dev);
|
|
if (!pm_runtime_status_suspended(&pdev->dev))
|
|
@@ -1136,8 +1142,6 @@ exit_pm_disable:
|
|
tegra_spi_deinit_dma_param(tspi, false);
|
|
exit_rx_dma_free:
|
|
tegra_spi_deinit_dma_param(tspi, true);
|
|
-exit_free_irq:
|
|
- free_irq(spi_irq, tspi);
|
|
exit_free_master:
|
|
spi_master_put(master);
|
|
return ret;
|
|
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
|
|
index 93dfcee0f987..9f30a4ab2004 100644
|
|
--- a/drivers/spi/spi-topcliff-pch.c
|
|
+++ b/drivers/spi/spi-topcliff-pch.c
|
|
@@ -1326,18 +1326,27 @@ static void pch_free_dma_buf(struct pch_spi_board_data *board_dat,
|
|
return;
|
|
}
|
|
|
|
-static void pch_alloc_dma_buf(struct pch_spi_board_data *board_dat,
|
|
+static int pch_alloc_dma_buf(struct pch_spi_board_data *board_dat,
|
|
struct pch_spi_data *data)
|
|
{
|
|
struct pch_spi_dma_ctrl *dma;
|
|
+ int ret;
|
|
|
|
dma = &data->dma;
|
|
+ ret = 0;
|
|
/* Get Consistent memory for Tx DMA */
|
|
dma->tx_buf_virt = dma_alloc_coherent(&board_dat->pdev->dev,
|
|
PCH_BUF_SIZE, &dma->tx_buf_dma, GFP_KERNEL);
|
|
+ if (!dma->tx_buf_virt)
|
|
+ ret = -ENOMEM;
|
|
+
|
|
/* Get Consistent memory for Rx DMA */
|
|
dma->rx_buf_virt = dma_alloc_coherent(&board_dat->pdev->dev,
|
|
PCH_BUF_SIZE, &dma->rx_buf_dma, GFP_KERNEL);
|
|
+ if (!dma->rx_buf_virt)
|
|
+ ret = -ENOMEM;
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
static int pch_spi_pd_probe(struct platform_device *plat_dev)
|
|
@@ -1414,7 +1423,9 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
|
|
|
|
if (use_dma) {
|
|
dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
|
|
- pch_alloc_dma_buf(board_dat, data);
|
|
+ ret = pch_alloc_dma_buf(board_dat, data);
|
|
+ if (ret)
|
|
+ goto err_spi_register_master;
|
|
}
|
|
|
|
ret = spi_register_master(master);
|
|
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
|
|
index 04fd651f9e3e..c132c676df3a 100644
|
|
--- a/drivers/spi/spi.c
|
|
+++ b/drivers/spi/spi.c
|
|
@@ -903,6 +903,8 @@ static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
|
|
if (max_tx || max_rx) {
|
|
list_for_each_entry(xfer, &msg->transfers,
|
|
transfer_list) {
|
|
+ if (!xfer->len)
|
|
+ continue;
|
|
if (!xfer->tx_buf)
|
|
xfer->tx_buf = master->dummy_tx;
|
|
if (!xfer->rx_buf)
|
|
diff --git a/drivers/ssb/bridge_pcmcia_80211.c b/drivers/ssb/bridge_pcmcia_80211.c
|
|
index d70568ea02d5..2ff7d90e166a 100644
|
|
--- a/drivers/ssb/bridge_pcmcia_80211.c
|
|
+++ b/drivers/ssb/bridge_pcmcia_80211.c
|
|
@@ -113,16 +113,21 @@ static struct pcmcia_driver ssb_host_pcmcia_driver = {
|
|
.resume = ssb_host_pcmcia_resume,
|
|
};
|
|
|
|
+static int pcmcia_init_failed;
|
|
+
|
|
/*
|
|
* These are not module init/exit functions!
|
|
* The module_pcmcia_driver() helper cannot be used here.
|
|
*/
|
|
int ssb_host_pcmcia_init(void)
|
|
{
|
|
- return pcmcia_register_driver(&ssb_host_pcmcia_driver);
|
|
+ pcmcia_init_failed = pcmcia_register_driver(&ssb_host_pcmcia_driver);
|
|
+
|
|
+ return pcmcia_init_failed;
|
|
}
|
|
|
|
void ssb_host_pcmcia_exit(void)
|
|
{
|
|
- pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
|
|
+ if (!pcmcia_init_failed)
|
|
+ pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
|
|
}
|
|
diff --git a/drivers/staging/iio/magnetometer/hmc5843_i2c.c b/drivers/staging/iio/magnetometer/hmc5843_i2c.c
|
|
index 3e06ceb32059..676a8e329eeb 100644
|
|
--- a/drivers/staging/iio/magnetometer/hmc5843_i2c.c
|
|
+++ b/drivers/staging/iio/magnetometer/hmc5843_i2c.c
|
|
@@ -59,8 +59,13 @@ static const struct regmap_config hmc5843_i2c_regmap_config = {
|
|
static int hmc5843_i2c_probe(struct i2c_client *cli,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
+ struct regmap *regmap = devm_regmap_init_i2c(cli,
|
|
+ &hmc5843_i2c_regmap_config);
|
|
+ if (IS_ERR(regmap))
|
|
+ return PTR_ERR(regmap);
|
|
+
|
|
return hmc5843_common_probe(&cli->dev,
|
|
- devm_regmap_init_i2c(cli, &hmc5843_i2c_regmap_config),
|
|
+ regmap,
|
|
id->driver_data, id->name);
|
|
}
|
|
|
|
diff --git a/drivers/staging/iio/magnetometer/hmc5843_spi.c b/drivers/staging/iio/magnetometer/hmc5843_spi.c
|
|
index 8be198058ea2..fded442a3c1d 100644
|
|
--- a/drivers/staging/iio/magnetometer/hmc5843_spi.c
|
|
+++ b/drivers/staging/iio/magnetometer/hmc5843_spi.c
|
|
@@ -59,6 +59,7 @@ static const struct regmap_config hmc5843_spi_regmap_config = {
|
|
static int hmc5843_spi_probe(struct spi_device *spi)
|
|
{
|
|
int ret;
|
|
+ struct regmap *regmap;
|
|
const struct spi_device_id *id = spi_get_device_id(spi);
|
|
|
|
spi->mode = SPI_MODE_3;
|
|
@@ -68,8 +69,12 @@ static int hmc5843_spi_probe(struct spi_device *spi)
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ regmap = devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config);
|
|
+ if (IS_ERR(regmap))
|
|
+ return PTR_ERR(regmap);
|
|
+
|
|
return hmc5843_common_probe(&spi->dev,
|
|
- devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config),
|
|
+ regmap,
|
|
id->driver_data, id->name);
|
|
}
|
|
|
|
diff --git a/drivers/tty/ipwireless/main.c b/drivers/tty/ipwireless/main.c
|
|
index 655c7948261c..2fa4f9123469 100644
|
|
--- a/drivers/tty/ipwireless/main.c
|
|
+++ b/drivers/tty/ipwireless/main.c
|
|
@@ -113,6 +113,10 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
|
|
|
|
ipw->common_memory = ioremap(p_dev->resource[2]->start,
|
|
resource_size(p_dev->resource[2]));
|
|
+ if (!ipw->common_memory) {
|
|
+ ret = -ENOMEM;
|
|
+ goto exit1;
|
|
+ }
|
|
if (!request_mem_region(p_dev->resource[2]->start,
|
|
resource_size(p_dev->resource[2]),
|
|
IPWIRELESS_PCCARD_NAME)) {
|
|
@@ -133,6 +137,10 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
|
|
|
|
ipw->attr_memory = ioremap(p_dev->resource[3]->start,
|
|
resource_size(p_dev->resource[3]));
|
|
+ if (!ipw->attr_memory) {
|
|
+ ret = -ENOMEM;
|
|
+ goto exit3;
|
|
+ }
|
|
if (!request_mem_region(p_dev->resource[3]->start,
|
|
resource_size(p_dev->resource[3]),
|
|
IPWIRELESS_PCCARD_NAME)) {
|
|
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
|
|
index be55fb6def89..0ac0c618954e 100644
|
|
--- a/drivers/tty/serial/max310x.c
|
|
+++ b/drivers/tty/serial/max310x.c
|
|
@@ -571,7 +571,7 @@ static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq,
|
|
}
|
|
|
|
/* Configure clock source */
|
|
- clksrc = xtal ? MAX310X_CLKSRC_CRYST_BIT : MAX310X_CLKSRC_EXTCLK_BIT;
|
|
+ clksrc = MAX310X_CLKSRC_EXTCLK_BIT | (xtal ? MAX310X_CLKSRC_CRYST_BIT : 0);
|
|
|
|
/* Configure PLL */
|
|
if (pllcfg) {
|
|
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
|
|
index 8c4707d5778e..5f0ded6fc4e9 100644
|
|
--- a/drivers/tty/serial/msm_serial.c
|
|
+++ b/drivers/tty/serial/msm_serial.c
|
|
@@ -703,6 +703,7 @@ static void msm_handle_tx(struct uart_port *port)
|
|
struct circ_buf *xmit = &msm_port->uart.state->xmit;
|
|
struct msm_dma *dma = &msm_port->tx_dma;
|
|
unsigned int pio_count, dma_count, dma_min;
|
|
+ char buf[4] = { 0 };
|
|
void __iomem *tf;
|
|
int err = 0;
|
|
|
|
@@ -712,10 +713,12 @@ static void msm_handle_tx(struct uart_port *port)
|
|
else
|
|
tf = port->membase + UART_TF;
|
|
|
|
+ buf[0] = port->x_char;
|
|
+
|
|
if (msm_port->is_uartdm)
|
|
msm_reset_dm_count(port, 1);
|
|
|
|
- iowrite8_rep(tf, &port->x_char, 1);
|
|
+ iowrite32_rep(tf, buf, 1);
|
|
port->icount.tx++;
|
|
port->x_char = 0;
|
|
return;
|
|
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
|
|
index 988c564b61a8..fd92c842504d 100644
|
|
--- a/drivers/tty/vt/keyboard.c
|
|
+++ b/drivers/tty/vt/keyboard.c
|
|
@@ -121,6 +121,7 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals);
|
|
static struct input_handler kbd_handler;
|
|
static DEFINE_SPINLOCK(kbd_event_lock);
|
|
static DEFINE_SPINLOCK(led_lock);
|
|
+static DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf' and friends */
|
|
static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
|
|
static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
|
|
static bool dead_key_next;
|
|
@@ -1969,11 +1970,12 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
|
char *p;
|
|
u_char *q;
|
|
u_char __user *up;
|
|
- int sz;
|
|
+ int sz, fnw_sz;
|
|
int delta;
|
|
char *first_free, *fj, *fnw;
|
|
int i, j, k;
|
|
int ret;
|
|
+ unsigned long flags;
|
|
|
|
if (!capable(CAP_SYS_TTY_CONFIG))
|
|
perm = 0;
|
|
@@ -2016,7 +2018,14 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
|
goto reterr;
|
|
}
|
|
|
|
+ fnw = NULL;
|
|
+ fnw_sz = 0;
|
|
+ /* race aginst other writers */
|
|
+ again:
|
|
+ spin_lock_irqsave(&func_buf_lock, flags);
|
|
q = func_table[i];
|
|
+
|
|
+ /* fj pointer to next entry after 'q' */
|
|
first_free = funcbufptr + (funcbufsize - funcbufleft);
|
|
for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
|
|
;
|
|
@@ -2024,10 +2033,12 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
|
fj = func_table[j];
|
|
else
|
|
fj = first_free;
|
|
-
|
|
+ /* buffer usage increase by new entry */
|
|
delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
|
|
+
|
|
if (delta <= funcbufleft) { /* it fits in current buf */
|
|
if (j < MAX_NR_FUNC) {
|
|
+ /* make enough space for new entry at 'fj' */
|
|
memmove(fj + delta, fj, first_free - fj);
|
|
for (k = j; k < MAX_NR_FUNC; k++)
|
|
if (func_table[k])
|
|
@@ -2040,20 +2051,28 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
|
sz = 256;
|
|
while (sz < funcbufsize - funcbufleft + delta)
|
|
sz <<= 1;
|
|
- fnw = kmalloc(sz, GFP_KERNEL);
|
|
- if(!fnw) {
|
|
- ret = -ENOMEM;
|
|
- goto reterr;
|
|
+ if (fnw_sz != sz) {
|
|
+ spin_unlock_irqrestore(&func_buf_lock, flags);
|
|
+ kfree(fnw);
|
|
+ fnw = kmalloc(sz, GFP_KERNEL);
|
|
+ fnw_sz = sz;
|
|
+ if (!fnw) {
|
|
+ ret = -ENOMEM;
|
|
+ goto reterr;
|
|
+ }
|
|
+ goto again;
|
|
}
|
|
|
|
if (!q)
|
|
func_table[i] = fj;
|
|
+ /* copy data before insertion point to new location */
|
|
if (fj > funcbufptr)
|
|
memmove(fnw, funcbufptr, fj - funcbufptr);
|
|
for (k = 0; k < j; k++)
|
|
if (func_table[k])
|
|
func_table[k] = fnw + (func_table[k] - funcbufptr);
|
|
|
|
+ /* copy data after insertion point to new location */
|
|
if (first_free > fj) {
|
|
memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
|
|
for (k = j; k < MAX_NR_FUNC; k++)
|
|
@@ -2066,7 +2085,9 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
|
funcbufleft = funcbufleft - delta + sz - funcbufsize;
|
|
funcbufsize = sz;
|
|
}
|
|
+ /* finally insert item itself */
|
|
strcpy(func_table[i], kbs->kb_string);
|
|
+ spin_unlock_irqrestore(&func_buf_lock, flags);
|
|
break;
|
|
}
|
|
ret = 0;
|
|
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
|
|
index 6a287c81a7be..aef208585544 100644
|
|
--- a/drivers/usb/core/config.c
|
|
+++ b/drivers/usb/core/config.c
|
|
@@ -902,8 +902,8 @@ int usb_get_bos_descriptor(struct usb_device *dev)
|
|
|
|
/* Get BOS descriptor */
|
|
ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE);
|
|
- if (ret < USB_DT_BOS_SIZE) {
|
|
- dev_err(ddev, "unable to get BOS descriptor\n");
|
|
+ if (ret < USB_DT_BOS_SIZE || bos->bLength < USB_DT_BOS_SIZE) {
|
|
+ dev_err(ddev, "unable to get BOS descriptor or descriptor too short\n");
|
|
if (ret >= 0)
|
|
ret = -ENOMSG;
|
|
kfree(bos);
|
|
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
|
|
index 9c4f9b6e57e2..99c146f4b6b5 100644
|
|
--- a/drivers/usb/core/hcd.c
|
|
+++ b/drivers/usb/core/hcd.c
|
|
@@ -3007,6 +3007,9 @@ usb_hcd_platform_shutdown(struct platform_device *dev)
|
|
{
|
|
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
|
|
|
+ /* No need for pm_runtime_put(), we're shutting down */
|
|
+ pm_runtime_get_sync(&dev->dev);
|
|
+
|
|
if (hcd->driver->shutdown)
|
|
hcd->driver->shutdown(hcd);
|
|
}
|
|
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
|
index 7c87c0b38bcf..6e307de25163 100644
|
|
--- a/drivers/usb/core/hub.c
|
|
+++ b/drivers/usb/core/hub.c
|
|
@@ -5637,7 +5637,10 @@ int usb_reset_device(struct usb_device *udev)
|
|
cintf->needs_binding = 1;
|
|
}
|
|
}
|
|
- usb_unbind_and_rebind_marked_interfaces(udev);
|
|
+
|
|
+ /* If the reset failed, hub_wq will unbind drivers later */
|
|
+ if (ret == 0)
|
|
+ usb_unbind_and_rebind_marked_interfaces(udev);
|
|
}
|
|
|
|
usb_autosuspend_device(udev);
|
|
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
|
|
index 733479ddf8a7..38c7676e7a82 100644
|
|
--- a/drivers/usb/core/quirks.c
|
|
+++ b/drivers/usb/core/quirks.c
|
|
@@ -64,6 +64,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|
/* Microsoft LifeCam-VX700 v2.0 */
|
|
{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
|
|
|
|
+ /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */
|
|
+ { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM },
|
|
+
|
|
/* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */
|
|
{ USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME },
|
|
|
|
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
|
|
index e3fdc799ad6e..ed152b8ea645 100644
|
|
--- a/drivers/usb/host/xhci.c
|
|
+++ b/drivers/usb/host/xhci.c
|
|
@@ -21,6 +21,7 @@
|
|
*/
|
|
|
|
#include <linux/pci.h>
|
|
+#include <linux/iopoll.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/log2.h>
|
|
#include <linux/module.h>
|
|
@@ -46,7 +47,6 @@ static unsigned int quirks;
|
|
module_param(quirks, uint, S_IRUGO);
|
|
MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default");
|
|
|
|
-/* TODO: copied from ehci-hcd.c - can this be refactored? */
|
|
/*
|
|
* xhci_handshake - spin reading hc until handshake completes or fails
|
|
* @ptr: address of hc register to be read
|
|
@@ -63,18 +63,16 @@ MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default");
|
|
int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)
|
|
{
|
|
u32 result;
|
|
+ int ret;
|
|
|
|
- do {
|
|
- result = readl(ptr);
|
|
- if (result == ~(u32)0) /* card removed */
|
|
- return -ENODEV;
|
|
- result &= mask;
|
|
- if (result == done)
|
|
- return 0;
|
|
- udelay(1);
|
|
- usec--;
|
|
- } while (usec > 0);
|
|
- return -ETIMEDOUT;
|
|
+ ret = readl_poll_timeout_atomic(ptr, result,
|
|
+ (result & mask) == done ||
|
|
+ result == U32_MAX,
|
|
+ 1, usec);
|
|
+ if (result == U32_MAX) /* card removed */
|
|
+ return -ENODEV;
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
/*
|
|
@@ -4193,7 +4191,6 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
|
pm_addr = port_array[port_num] + PORTPMSC;
|
|
pm_val = readl(pm_addr);
|
|
hlpm_addr = port_array[port_num] + PORTHLPMC;
|
|
- field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
|
|
|
|
xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
|
|
enable ? "enable" : "disable", port_num + 1);
|
|
@@ -4205,6 +4202,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
|
* default one which works with mixed HIRD and BESL
|
|
* systems. See XHCI_DEFAULT_BESL definition in xhci.h
|
|
*/
|
|
+ field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
|
|
if ((field & USB_BESL_SUPPORT) &&
|
|
(field & USB_BESL_BASELINE_VALID))
|
|
hird = USB_GET_BESL_BASELINE(field);
|
|
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
|
|
index 13731d512624..6e761fabffca 100644
|
|
--- a/drivers/usb/misc/rio500.c
|
|
+++ b/drivers/usb/misc/rio500.c
|
|
@@ -103,9 +103,22 @@ static int close_rio(struct inode *inode, struct file *file)
|
|
{
|
|
struct rio_usb_data *rio = &rio_instance;
|
|
|
|
- rio->isopen = 0;
|
|
+ /* against disconnect() */
|
|
+ mutex_lock(&rio500_mutex);
|
|
+ mutex_lock(&(rio->lock));
|
|
|
|
- dev_info(&rio->rio_dev->dev, "Rio closed.\n");
|
|
+ rio->isopen = 0;
|
|
+ if (!rio->present) {
|
|
+ /* cleanup has been delayed */
|
|
+ kfree(rio->ibuf);
|
|
+ kfree(rio->obuf);
|
|
+ rio->ibuf = NULL;
|
|
+ rio->obuf = NULL;
|
|
+ } else {
|
|
+ dev_info(&rio->rio_dev->dev, "Rio closed.\n");
|
|
+ }
|
|
+ mutex_unlock(&(rio->lock));
|
|
+ mutex_unlock(&rio500_mutex);
|
|
return 0;
|
|
}
|
|
|
|
@@ -464,15 +477,23 @@ static int probe_rio(struct usb_interface *intf,
|
|
{
|
|
struct usb_device *dev = interface_to_usbdev(intf);
|
|
struct rio_usb_data *rio = &rio_instance;
|
|
- int retval;
|
|
+ int retval = 0;
|
|
|
|
- dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum);
|
|
+ mutex_lock(&rio500_mutex);
|
|
+ if (rio->present) {
|
|
+ dev_info(&intf->dev, "Second USB Rio at address %d refused\n", dev->devnum);
|
|
+ retval = -EBUSY;
|
|
+ goto bail_out;
|
|
+ } else {
|
|
+ dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum);
|
|
+ }
|
|
|
|
retval = usb_register_dev(intf, &usb_rio_class);
|
|
if (retval) {
|
|
dev_err(&dev->dev,
|
|
"Not able to get a minor for this device.\n");
|
|
- return -ENOMEM;
|
|
+ retval = -ENOMEM;
|
|
+ goto bail_out;
|
|
}
|
|
|
|
rio->rio_dev = dev;
|
|
@@ -481,7 +502,8 @@ static int probe_rio(struct usb_interface *intf,
|
|
dev_err(&dev->dev,
|
|
"probe_rio: Not enough memory for the output buffer\n");
|
|
usb_deregister_dev(intf, &usb_rio_class);
|
|
- return -ENOMEM;
|
|
+ retval = -ENOMEM;
|
|
+ goto bail_out;
|
|
}
|
|
dev_dbg(&intf->dev, "obuf address:%p\n", rio->obuf);
|
|
|
|
@@ -490,7 +512,8 @@ static int probe_rio(struct usb_interface *intf,
|
|
"probe_rio: Not enough memory for the input buffer\n");
|
|
usb_deregister_dev(intf, &usb_rio_class);
|
|
kfree(rio->obuf);
|
|
- return -ENOMEM;
|
|
+ retval = -ENOMEM;
|
|
+ goto bail_out;
|
|
}
|
|
dev_dbg(&intf->dev, "ibuf address:%p\n", rio->ibuf);
|
|
|
|
@@ -498,8 +521,10 @@ static int probe_rio(struct usb_interface *intf,
|
|
|
|
usb_set_intfdata (intf, rio);
|
|
rio->present = 1;
|
|
+bail_out:
|
|
+ mutex_unlock(&rio500_mutex);
|
|
|
|
- return 0;
|
|
+ return retval;
|
|
}
|
|
|
|
static void disconnect_rio(struct usb_interface *intf)
|
|
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
|
|
index 306d6852ebc7..b9d50020c684 100644
|
|
--- a/drivers/usb/misc/sisusbvga/sisusb.c
|
|
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
|
|
@@ -3103,6 +3103,13 @@ static int sisusb_probe(struct usb_interface *intf,
|
|
|
|
mutex_init(&(sisusb->lock));
|
|
|
|
+ sisusb->sisusb_dev = dev;
|
|
+ sisusb->vrambase = SISUSB_PCI_MEMBASE;
|
|
+ sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
|
|
+ sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
|
|
+ sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
|
|
+ /* Everything else is zero */
|
|
+
|
|
/* Register device */
|
|
retval = usb_register_dev(intf, &usb_sisusb_class);
|
|
if (retval) {
|
|
@@ -3112,13 +3119,7 @@ static int sisusb_probe(struct usb_interface *intf,
|
|
goto error_1;
|
|
}
|
|
|
|
- sisusb->sisusb_dev = dev;
|
|
- sisusb->minor = intf->minor;
|
|
- sisusb->vrambase = SISUSB_PCI_MEMBASE;
|
|
- sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
|
|
- sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
|
|
- sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
|
|
- /* Everything else is zero */
|
|
+ sisusb->minor = intf->minor;
|
|
|
|
/* Allocate buffers */
|
|
sisusb->ibufsize = SISUSB_IBUF_SIZE;
|
|
diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c
|
|
index 68a113594808..2811c4afde01 100644
|
|
--- a/drivers/video/fbdev/core/fbcmap.c
|
|
+++ b/drivers/video/fbdev/core/fbcmap.c
|
|
@@ -94,6 +94,8 @@ int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
|
|
int size = len * sizeof(u16);
|
|
int ret = -ENOMEM;
|
|
|
|
+ flags |= __GFP_NOWARN;
|
|
+
|
|
if (cmap->len != len) {
|
|
fb_dealloc_cmap(cmap);
|
|
if (!len)
|
|
diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c
|
|
index de119f11b78f..455a15f70172 100644
|
|
--- a/drivers/video/fbdev/core/modedb.c
|
|
+++ b/drivers/video/fbdev/core/modedb.c
|
|
@@ -933,6 +933,9 @@ void fb_var_to_videomode(struct fb_videomode *mode,
|
|
if (var->vmode & FB_VMODE_DOUBLE)
|
|
vtotal *= 2;
|
|
|
|
+ if (!htotal || !vtotal)
|
|
+ return;
|
|
+
|
|
hfreq = pixclock/htotal;
|
|
mode->refresh = hfreq/vtotal;
|
|
}
|
|
diff --git a/drivers/video/fbdev/sm712.h b/drivers/video/fbdev/sm712.h
|
|
index aad1cc4be34a..c7ebf03b8d53 100644
|
|
--- a/drivers/video/fbdev/sm712.h
|
|
+++ b/drivers/video/fbdev/sm712.h
|
|
@@ -15,14 +15,10 @@
|
|
|
|
#define FB_ACCEL_SMI_LYNX 88
|
|
|
|
-#define SCREEN_X_RES 1024
|
|
-#define SCREEN_Y_RES 600
|
|
-#define SCREEN_BPP 16
|
|
-
|
|
-/*Assume SM712 graphics chip has 4MB VRAM */
|
|
-#define SM712_VIDEOMEMORYSIZE 0x00400000
|
|
-/*Assume SM722 graphics chip has 8MB VRAM */
|
|
-#define SM722_VIDEOMEMORYSIZE 0x00800000
|
|
+#define SCREEN_X_RES 1024
|
|
+#define SCREEN_Y_RES_PC 768
|
|
+#define SCREEN_Y_RES_NETBOOK 600
|
|
+#define SCREEN_BPP 16
|
|
|
|
#define dac_reg (0x3c8)
|
|
#define dac_val (0x3c9)
|
|
diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c
|
|
index 86ae1d4556fc..589ac7e75413 100644
|
|
--- a/drivers/video/fbdev/sm712fb.c
|
|
+++ b/drivers/video/fbdev/sm712fb.c
|
|
@@ -530,6 +530,65 @@ static const struct modeinit vgamode[] = {
|
|
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
|
|
},
|
|
},
|
|
+ { /* 1024 x 768 16Bpp 60Hz */
|
|
+ 1024, 768, 16, 60,
|
|
+ /* Init_MISC */
|
|
+ 0xEB,
|
|
+ { /* Init_SR0_SR4 */
|
|
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
|
|
+ },
|
|
+ { /* Init_SR10_SR24 */
|
|
+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
|
|
+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
|
|
+ },
|
|
+ { /* Init_SR30_SR75 */
|
|
+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
|
|
+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
|
|
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
|
|
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
|
|
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
|
|
+ 0x0F, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
|
|
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
|
+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
|
|
+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
|
|
+ },
|
|
+ { /* Init_SR80_SR93 */
|
|
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
|
|
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
|
|
+ 0x00, 0x00, 0x00, 0x00,
|
|
+ },
|
|
+ { /* Init_SRA0_SRAF */
|
|
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
|
|
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
|
|
+ },
|
|
+ { /* Init_GR00_GR08 */
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
|
+ 0xFF,
|
|
+ },
|
|
+ { /* Init_AR00_AR14 */
|
|
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
|
|
+ },
|
|
+ { /* Init_CR00_CR18 */
|
|
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
|
|
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
|
|
+ 0xFF,
|
|
+ },
|
|
+ { /* Init_CR30_CR4D */
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
|
|
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
|
|
+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
|
|
+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
|
|
+ },
|
|
+ { /* Init_CR90_CRA7 */
|
|
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
|
|
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
|
|
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
|
|
+ },
|
|
+ },
|
|
{ /* mode#5: 1024 x 768 24Bpp 60Hz */
|
|
1024, 768, 24, 60,
|
|
/* Init_MISC */
|
|
@@ -827,67 +886,80 @@ static inline unsigned int chan_to_field(unsigned int chan,
|
|
|
|
static int smtc_blank(int blank_mode, struct fb_info *info)
|
|
{
|
|
+ struct smtcfb_info *sfb = info->par;
|
|
+
|
|
/* clear DPMS setting */
|
|
switch (blank_mode) {
|
|
case FB_BLANK_UNBLANK:
|
|
/* Screen On: HSync: On, VSync : On */
|
|
+
|
|
+ switch (sfb->chip_id) {
|
|
+ case 0x710:
|
|
+ case 0x712:
|
|
+ smtc_seqw(0x6a, 0x16);
|
|
+ smtc_seqw(0x6b, 0x02);
|
|
+ break;
|
|
+ case 0x720:
|
|
+ smtc_seqw(0x6a, 0x0d);
|
|
+ smtc_seqw(0x6b, 0x02);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
|
|
smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
|
|
- smtc_seqw(0x6a, 0x16);
|
|
- smtc_seqw(0x6b, 0x02);
|
|
smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
|
|
smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
|
|
- smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
|
|
- smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
|
|
smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
|
|
+ smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
|
|
break;
|
|
case FB_BLANK_NORMAL:
|
|
/* Screen Off: HSync: On, VSync : On Soft blank */
|
|
+ smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
|
|
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
|
|
+ smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
|
|
smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
|
|
+ smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
|
|
smtc_seqw(0x6a, 0x16);
|
|
smtc_seqw(0x6b, 0x02);
|
|
- smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
|
|
- smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
|
|
- smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
|
|
- smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
|
|
break;
|
|
case FB_BLANK_VSYNC_SUSPEND:
|
|
/* Screen On: HSync: On, VSync : Off */
|
|
+ smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
|
|
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
|
|
+ smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
|
|
smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
|
|
- smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
|
|
- smtc_seqw(0x6a, 0x0c);
|
|
- smtc_seqw(0x6b, 0x02);
|
|
smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
|
|
+ smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
|
|
smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
|
|
- smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
|
|
- smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
|
|
- smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
|
|
smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
|
|
+ smtc_seqw(0x6a, 0x0c);
|
|
+ smtc_seqw(0x6b, 0x02);
|
|
break;
|
|
case FB_BLANK_HSYNC_SUSPEND:
|
|
/* Screen On: HSync: Off, VSync : On */
|
|
+ smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
|
|
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
|
|
+ smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
|
|
smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
|
|
- smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
|
|
- smtc_seqw(0x6a, 0x0c);
|
|
- smtc_seqw(0x6b, 0x02);
|
|
smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
|
|
+ smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
|
|
smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
|
|
- smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
|
|
- smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
|
|
- smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
|
|
smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
|
|
+ smtc_seqw(0x6a, 0x0c);
|
|
+ smtc_seqw(0x6b, 0x02);
|
|
break;
|
|
case FB_BLANK_POWERDOWN:
|
|
/* Screen On: HSync: Off, VSync : Off */
|
|
+ smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
|
|
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
|
|
+ smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
|
|
smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
|
|
- smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
|
|
- smtc_seqw(0x6a, 0x0c);
|
|
- smtc_seqw(0x6b, 0x02);
|
|
smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
|
|
+ smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
|
|
smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
|
|
- smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
|
|
- smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
|
|
- smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
|
|
smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
|
|
+ smtc_seqw(0x6a, 0x0c);
|
|
+ smtc_seqw(0x6b, 0x02);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
@@ -1144,8 +1216,10 @@ static void sm7xx_set_timing(struct smtcfb_info *sfb)
|
|
|
|
/* init SEQ register SR30 - SR75 */
|
|
for (i = 0; i < SIZE_SR30_SR75; i++)
|
|
- if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a &&
|
|
- (i + 0x30) != 0x6b)
|
|
+ if ((i + 0x30) != 0x30 && (i + 0x30) != 0x62 &&
|
|
+ (i + 0x30) != 0x6a && (i + 0x30) != 0x6b &&
|
|
+ (i + 0x30) != 0x70 && (i + 0x30) != 0x71 &&
|
|
+ (i + 0x30) != 0x74 && (i + 0x30) != 0x75)
|
|
smtc_seqw(i + 0x30,
|
|
vgamode[j].init_sr30_sr75[i]);
|
|
|
|
@@ -1170,8 +1244,12 @@ static void sm7xx_set_timing(struct smtcfb_info *sfb)
|
|
smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
|
|
|
|
/* init CRTC register CR30 - CR4D */
|
|
- for (i = 0; i < SIZE_CR30_CR4D; i++)
|
|
+ for (i = 0; i < SIZE_CR30_CR4D; i++) {
|
|
+ if ((i + 0x30) >= 0x3B && (i + 0x30) <= 0x3F)
|
|
+ /* side-effect, don't write to CR3B-CR3F */
|
|
+ continue;
|
|
smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
|
|
+ }
|
|
|
|
/* init CRTC register CR90 - CRA7 */
|
|
for (i = 0; i < SIZE_CR90_CRA7; i++)
|
|
@@ -1322,6 +1400,11 @@ static int smtc_map_smem(struct smtcfb_info *sfb,
|
|
{
|
|
sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
|
|
|
|
+ if (sfb->chip_id == 0x720)
|
|
+ /* on SM720, the framebuffer starts at the 1 MB offset */
|
|
+ sfb->fb->fix.smem_start += 0x00200000;
|
|
+
|
|
+ /* XXX: is it safe for SM720 on Big-Endian? */
|
|
if (sfb->fb->var.bits_per_pixel == 32)
|
|
sfb->fb->fix.smem_start += big_addr;
|
|
|
|
@@ -1359,12 +1442,82 @@ static inline void sm7xx_init_hw(void)
|
|
outb_p(0x11, 0x3c5);
|
|
}
|
|
|
|
+static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
|
|
+{
|
|
+ u8 vram;
|
|
+
|
|
+ switch (sfb->chip_id) {
|
|
+ case 0x710:
|
|
+ case 0x712:
|
|
+ /*
|
|
+ * Assume SM712 graphics chip has 4MB VRAM.
|
|
+ *
|
|
+ * FIXME: SM712 can have 2MB VRAM, which is used on earlier
|
|
+ * laptops, such as IBM Thinkpad 240X. This driver would
|
|
+ * probably crash on those machines. If anyone gets one of
|
|
+ * those and is willing to help, run "git blame" and send me
|
|
+ * an E-mail.
|
|
+ */
|
|
+ return 0x00400000;
|
|
+ case 0x720:
|
|
+ outb_p(0x76, 0x3c4);
|
|
+ vram = inb_p(0x3c5) >> 6;
|
|
+
|
|
+ if (vram == 0x00)
|
|
+ return 0x00800000; /* 8 MB */
|
|
+ else if (vram == 0x01)
|
|
+ return 0x01000000; /* 16 MB */
|
|
+ else if (vram == 0x02)
|
|
+ return 0x00400000; /* illegal, fallback to 4 MB */
|
|
+ else if (vram == 0x03)
|
|
+ return 0x00400000; /* 4 MB */
|
|
+ }
|
|
+ return 0; /* unknown hardware */
|
|
+}
|
|
+
|
|
+static void sm7xx_resolution_probe(struct smtcfb_info *sfb)
|
|
+{
|
|
+ /* get mode parameter from smtc_scr_info */
|
|
+ if (smtc_scr_info.lfb_width != 0) {
|
|
+ sfb->fb->var.xres = smtc_scr_info.lfb_width;
|
|
+ sfb->fb->var.yres = smtc_scr_info.lfb_height;
|
|
+ sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
|
|
+ goto final;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * No parameter, default resolution is 1024x768-16.
|
|
+ *
|
|
+ * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600
|
|
+ * panel, also see the comments about Thinkpad 240X above.
|
|
+ */
|
|
+ sfb->fb->var.xres = SCREEN_X_RES;
|
|
+ sfb->fb->var.yres = SCREEN_Y_RES_PC;
|
|
+ sfb->fb->var.bits_per_pixel = SCREEN_BPP;
|
|
+
|
|
+#ifdef CONFIG_MIPS
|
|
+ /*
|
|
+ * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original
|
|
+ * target platform of this driver, but nearly all old x86 laptops have
|
|
+ * 1024x768. Lighting 768 panels using 600's timings would partially
|
|
+ * garble the display, so we don't want that. But it's not possible to
|
|
+ * distinguish them reliably.
|
|
+ *
|
|
+ * So we change the default to 768, but keep 600 as-is on MIPS.
|
|
+ */
|
|
+ sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK;
|
|
+#endif
|
|
+
|
|
+final:
|
|
+ big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
|
|
+}
|
|
+
|
|
static int smtcfb_pci_probe(struct pci_dev *pdev,
|
|
const struct pci_device_id *ent)
|
|
{
|
|
struct smtcfb_info *sfb;
|
|
struct fb_info *info;
|
|
- u_long smem_size = 0x00800000; /* default 8MB */
|
|
+ u_long smem_size;
|
|
int err;
|
|
unsigned long mmio_base;
|
|
|
|
@@ -1404,29 +1557,19 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
|
|
|
|
sm7xx_init_hw();
|
|
|
|
- /* get mode parameter from smtc_scr_info */
|
|
- if (smtc_scr_info.lfb_width != 0) {
|
|
- sfb->fb->var.xres = smtc_scr_info.lfb_width;
|
|
- sfb->fb->var.yres = smtc_scr_info.lfb_height;
|
|
- sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
|
|
- } else {
|
|
- /* default resolution 1024x600 16bit mode */
|
|
- sfb->fb->var.xres = SCREEN_X_RES;
|
|
- sfb->fb->var.yres = SCREEN_Y_RES;
|
|
- sfb->fb->var.bits_per_pixel = SCREEN_BPP;
|
|
- }
|
|
-
|
|
- big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
|
|
/* Map address and memory detection */
|
|
mmio_base = pci_resource_start(pdev, 0);
|
|
pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
|
|
|
|
+ smem_size = sm7xx_vram_probe(sfb);
|
|
+ dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
|
|
+ smem_size / 1048576);
|
|
+
|
|
switch (sfb->chip_id) {
|
|
case 0x710:
|
|
case 0x712:
|
|
sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
|
|
sfb->fb->fix.mmio_len = 0x00400000;
|
|
- smem_size = SM712_VIDEOMEMORYSIZE;
|
|
sfb->lfb = ioremap(mmio_base, mmio_addr);
|
|
if (!sfb->lfb) {
|
|
dev_err(&pdev->dev,
|
|
@@ -1458,8 +1601,7 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
|
|
case 0x720:
|
|
sfb->fb->fix.mmio_start = mmio_base;
|
|
sfb->fb->fix.mmio_len = 0x00200000;
|
|
- smem_size = SM722_VIDEOMEMORYSIZE;
|
|
- sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
|
|
+ sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
|
|
sfb->lfb = sfb->dp_regs + 0x00200000;
|
|
sfb->mmio = (smtc_regbaseaddress =
|
|
sfb->dp_regs + 0x000c0000);
|
|
@@ -1476,6 +1618,9 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
|
|
goto failed_fb;
|
|
}
|
|
|
|
+ /* probe and decide resolution */
|
|
+ sm7xx_resolution_probe(sfb);
|
|
+
|
|
/* can support 32 bpp */
|
|
if (15 == sfb->fb->var.bits_per_pixel)
|
|
sfb->fb->var.bits_per_pixel = 16;
|
|
@@ -1486,7 +1631,11 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
|
|
if (err)
|
|
goto failed;
|
|
|
|
- smtcfb_setmode(sfb);
|
|
+ /*
|
|
+ * The screen would be temporarily garbled when sm712fb takes over
|
|
+ * vesafb or VGA text mode. Zero the framebuffer.
|
|
+ */
|
|
+ memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len);
|
|
|
|
err = register_framebuffer(info);
|
|
if (err < 0)
|
|
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
|
|
index 282092421cc9..1a9d9ec8db4d 100644
|
|
--- a/drivers/w1/w1_io.c
|
|
+++ b/drivers/w1/w1_io.c
|
|
@@ -437,8 +437,7 @@ int w1_reset_resume_command(struct w1_master *dev)
|
|
if (w1_reset_bus(dev))
|
|
return -1;
|
|
|
|
- /* This will make only the last matched slave perform a skip ROM. */
|
|
- w1_write_8(dev, W1_RESUME_CMD);
|
|
+ w1_write_8(dev, dev->slave_count > 1 ? W1_RESUME_CMD : W1_SKIP_ROM);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(w1_reset_resume_command);
|
|
diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c
|
|
index fb0221434f81..49c5f0e9600a 100644
|
|
--- a/drivers/xen/xen-pciback/pciback_ops.c
|
|
+++ b/drivers/xen/xen-pciback/pciback_ops.c
|
|
@@ -126,8 +126,6 @@ void xen_pcibk_reset_device(struct pci_dev *dev)
|
|
if (pci_is_enabled(dev))
|
|
pci_disable_device(dev);
|
|
|
|
- pci_write_config_word(dev, PCI_COMMAND, 0);
|
|
-
|
|
dev->is_busmaster = 0;
|
|
} else {
|
|
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
|
diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c
|
|
index 816a0e08ef10..d7591efa7775 100644
|
|
--- a/drivers/xen/xenbus/xenbus_dev_frontend.c
|
|
+++ b/drivers/xen/xenbus/xenbus_dev_frontend.c
|
|
@@ -536,7 +536,7 @@ static int xenbus_file_open(struct inode *inode, struct file *filp)
|
|
if (xen_store_evtchn == 0)
|
|
return -ENOENT;
|
|
|
|
- nonseekable_open(inode, filp);
|
|
+ stream_open(inode, filp);
|
|
|
|
u = kzalloc(sizeof(*u), GFP_KERNEL);
|
|
if (u == NULL)
|
|
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
|
|
index e2f659dc5745..81c5d07a2af1 100644
|
|
--- a/fs/btrfs/backref.c
|
|
+++ b/fs/btrfs/backref.c
|
|
@@ -1685,13 +1685,19 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
|
|
extent_item_objectid);
|
|
|
|
if (!search_commit_root) {
|
|
- trans = btrfs_join_transaction(fs_info->extent_root);
|
|
- if (IS_ERR(trans))
|
|
- return PTR_ERR(trans);
|
|
+ trans = btrfs_attach_transaction(fs_info->extent_root);
|
|
+ if (IS_ERR(trans)) {
|
|
+ if (PTR_ERR(trans) != -ENOENT &&
|
|
+ PTR_ERR(trans) != -EROFS)
|
|
+ return PTR_ERR(trans);
|
|
+ trans = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (trans)
|
|
btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem);
|
|
- } else {
|
|
+ else
|
|
down_read(&fs_info->commit_root_sem);
|
|
- }
|
|
|
|
ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
|
|
tree_mod_seq_elem.seq, &refs,
|
|
@@ -1721,7 +1727,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
|
|
|
|
free_leaf_list(refs);
|
|
out:
|
|
- if (!search_commit_root) {
|
|
+ if (trans) {
|
|
btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);
|
|
btrfs_end_transaction(trans, fs_info->extent_root);
|
|
} else {
|
|
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
|
|
index 978bbfed5a2c..df2bb4b61a00 100644
|
|
--- a/fs/btrfs/extent-tree.c
|
|
+++ b/fs/btrfs/extent-tree.c
|
|
@@ -10730,9 +10730,9 @@ int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
|
|
* transaction.
|
|
*/
|
|
static int btrfs_trim_free_extents(struct btrfs_device *device,
|
|
- u64 minlen, u64 *trimmed)
|
|
+ struct fstrim_range *range, u64 *trimmed)
|
|
{
|
|
- u64 start = 0, len = 0;
|
|
+ u64 start = range->start, len = 0;
|
|
int ret;
|
|
|
|
*trimmed = 0;
|
|
@@ -10768,8 +10768,8 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
|
|
atomic_inc(&trans->use_count);
|
|
spin_unlock(&fs_info->trans_lock);
|
|
|
|
- ret = find_free_dev_extent_start(trans, device, minlen, start,
|
|
- &start, &len);
|
|
+ ret = find_free_dev_extent_start(trans, device, range->minlen,
|
|
+ start, &start, &len);
|
|
if (trans)
|
|
btrfs_put_transaction(trans);
|
|
|
|
@@ -10781,6 +10781,16 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
|
|
break;
|
|
}
|
|
|
|
+ /* If we are out of the passed range break */
|
|
+ if (start > range->start + range->len - 1) {
|
|
+ mutex_unlock(&fs_info->chunk_mutex);
|
|
+ ret = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ start = max(range->start, start);
|
|
+ len = min(range->len, len);
|
|
+
|
|
ret = btrfs_issue_discard(device->bdev, start, len, &bytes);
|
|
up_read(&fs_info->commit_root_sem);
|
|
mutex_unlock(&fs_info->chunk_mutex);
|
|
@@ -10791,6 +10801,10 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
|
|
start += len;
|
|
*trimmed += bytes;
|
|
|
|
+ /* We've trimmed enough */
|
|
+ if (*trimmed >= range->len)
|
|
+ break;
|
|
+
|
|
if (fatal_signal_pending(current)) {
|
|
ret = -ERESTARTSYS;
|
|
break;
|
|
@@ -10857,8 +10871,7 @@ int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range)
|
|
mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
|
|
devices = &root->fs_info->fs_devices->devices;
|
|
list_for_each_entry(device, devices, dev_list) {
|
|
- ret = btrfs_trim_free_extents(device, range->minlen,
|
|
- &group_trimmed);
|
|
+ ret = btrfs_trim_free_extents(device, range, &group_trimmed);
|
|
if (ret)
|
|
break;
|
|
|
|
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
|
|
index 052973620595..d056060529f8 100644
|
|
--- a/fs/btrfs/file.c
|
|
+++ b/fs/btrfs/file.c
|
|
@@ -1900,6 +1900,18 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|
bool full_sync = 0;
|
|
u64 len;
|
|
|
|
+ /*
|
|
+ * If the inode needs a full sync, make sure we use a full range to
|
|
+ * avoid log tree corruption, due to hole detection racing with ordered
|
|
+ * extent completion for adjacent ranges, and assertion failures during
|
|
+ * hole detection.
|
|
+ */
|
|
+ if (test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
|
|
+ &BTRFS_I(inode)->runtime_flags)) {
|
|
+ start = 0;
|
|
+ end = LLONG_MAX;
|
|
+ }
|
|
+
|
|
/*
|
|
* The range length can be represented by u64, we have to do the typecasts
|
|
* to avoid signed overflow if it's [0, LLONG_MAX] eg. from fsync()
|
|
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
|
|
index e0ac85949067..e6aaa15505c5 100644
|
|
--- a/fs/btrfs/sysfs.c
|
|
+++ b/fs/btrfs/sysfs.c
|
|
@@ -733,7 +733,12 @@ int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs,
|
|
fs_devs->fsid_kobj.kset = btrfs_kset;
|
|
error = kobject_init_and_add(&fs_devs->fsid_kobj,
|
|
&btrfs_ktype, parent, "%pU", fs_devs->fsid);
|
|
- return error;
|
|
+ if (error) {
|
|
+ kobject_put(&fs_devs->fsid_kobj);
|
|
+ return error;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info)
|
|
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
|
|
index c7190f322576..57a46093656a 100644
|
|
--- a/fs/btrfs/tree-log.c
|
|
+++ b/fs/btrfs/tree-log.c
|
|
@@ -2808,6 +2808,12 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
|
root->log_transid++;
|
|
log->log_transid = root->log_transid;
|
|
root->log_start_pid = 0;
|
|
+ /*
|
|
+ * Update or create log root item under the root's log_mutex to prevent
|
|
+ * races with concurrent log syncs that can lead to failure to update
|
|
+ * log root item because it was not created yet.
|
|
+ */
|
|
+ ret = update_log_root(trans, log);
|
|
/*
|
|
* IO has been started, blocks of the log tree have WRITTEN flag set
|
|
* in their headers. new modifications of the log will be written to
|
|
@@ -2827,8 +2833,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
|
|
|
mutex_unlock(&log_root_tree->log_mutex);
|
|
|
|
- ret = update_log_root(trans, log);
|
|
-
|
|
mutex_lock(&log_root_tree->log_mutex);
|
|
if (atomic_dec_and_test(&log_root_tree->log_writers)) {
|
|
/*
|
|
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
|
|
index f446afada328..ab8a8c9c74f2 100644
|
|
--- a/fs/ceph/super.c
|
|
+++ b/fs/ceph/super.c
|
|
@@ -712,6 +712,12 @@ static void ceph_umount_begin(struct super_block *sb)
|
|
return;
|
|
}
|
|
|
|
+static int ceph_remount(struct super_block *sb, int *flags, char *data)
|
|
+{
|
|
+ sync_filesystem(sb);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static const struct super_operations ceph_super_ops = {
|
|
.alloc_inode = ceph_alloc_inode,
|
|
.destroy_inode = ceph_destroy_inode,
|
|
@@ -719,6 +725,7 @@ static const struct super_operations ceph_super_ops = {
|
|
.drop_inode = ceph_drop_inode,
|
|
.sync_fs = ceph_sync_fs,
|
|
.put_super = ceph_put_super,
|
|
+ .remount_fs = ceph_remount,
|
|
.show_options = ceph_show_options,
|
|
.statfs = ceph_statfs,
|
|
.umount_begin = ceph_umount_begin,
|
|
diff --git a/fs/char_dev.c b/fs/char_dev.c
|
|
index 24b142569ca9..d0655ca89481 100644
|
|
--- a/fs/char_dev.c
|
|
+++ b/fs/char_dev.c
|
|
@@ -130,6 +130,12 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
|
|
ret = -EBUSY;
|
|
goto out;
|
|
}
|
|
+
|
|
+ if (new_min < old_min && new_max > old_max) {
|
|
+ ret = -EBUSY;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
}
|
|
|
|
cd->next = *cp;
|
|
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
|
|
index 23a8374fa97f..309c134fb66f 100644
|
|
--- a/fs/cifs/file.c
|
|
+++ b/fs/cifs/file.c
|
|
@@ -2829,7 +2829,9 @@ cifs_read_allocate_pages(struct cifs_readdata *rdata, unsigned int nr_pages)
|
|
}
|
|
|
|
if (rc) {
|
|
- for (i = 0; i < nr_pages; i++) {
|
|
+ unsigned int nr_page_failed = i;
|
|
+
|
|
+ for (i = 0; i < nr_page_failed; i++) {
|
|
put_page(rdata->pages[i]);
|
|
rdata->pages[i] = NULL;
|
|
}
|
|
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
|
|
index eae3cdffaf7f..591c93de8c20 100644
|
|
--- a/fs/cifs/smb2ops.c
|
|
+++ b/fs/cifs/smb2ops.c
|
|
@@ -1329,26 +1329,28 @@ smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
|
|
unsigned int epoch, bool *purge_cache)
|
|
{
|
|
char message[5] = {0};
|
|
+ unsigned int new_oplock = 0;
|
|
|
|
oplock &= 0xFF;
|
|
if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
|
|
return;
|
|
|
|
- cinode->oplock = 0;
|
|
if (oplock & SMB2_LEASE_READ_CACHING_HE) {
|
|
- cinode->oplock |= CIFS_CACHE_READ_FLG;
|
|
+ new_oplock |= CIFS_CACHE_READ_FLG;
|
|
strcat(message, "R");
|
|
}
|
|
if (oplock & SMB2_LEASE_HANDLE_CACHING_HE) {
|
|
- cinode->oplock |= CIFS_CACHE_HANDLE_FLG;
|
|
+ new_oplock |= CIFS_CACHE_HANDLE_FLG;
|
|
strcat(message, "H");
|
|
}
|
|
if (oplock & SMB2_LEASE_WRITE_CACHING_HE) {
|
|
- cinode->oplock |= CIFS_CACHE_WRITE_FLG;
|
|
+ new_oplock |= CIFS_CACHE_WRITE_FLG;
|
|
strcat(message, "W");
|
|
}
|
|
- if (!cinode->oplock)
|
|
- strcat(message, "None");
|
|
+ if (!new_oplock)
|
|
+ strncpy(message, "None", sizeof(message));
|
|
+
|
|
+ cinode->oplock = new_oplock;
|
|
cifs_dbg(FYI, "%s Lease granted on inode %p\n", message,
|
|
&cinode->vfs_inode);
|
|
}
|
|
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
|
|
index 1708597659a1..8d98c9ac9205 100644
|
|
--- a/fs/ext4/extents.c
|
|
+++ b/fs/ext4/extents.c
|
|
@@ -1049,6 +1049,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
|
__le32 border;
|
|
ext4_fsblk_t *ablocks = NULL; /* array of allocated blocks */
|
|
int err = 0;
|
|
+ size_t ext_size = 0;
|
|
|
|
/* make decision: where to split? */
|
|
/* FIXME: now decision is simplest: at current extent */
|
|
@@ -1140,6 +1141,10 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
|
le16_add_cpu(&neh->eh_entries, m);
|
|
}
|
|
|
|
+ /* zero out unused area in the extent block */
|
|
+ ext_size = sizeof(struct ext4_extent_header) +
|
|
+ sizeof(struct ext4_extent) * le16_to_cpu(neh->eh_entries);
|
|
+ memset(bh->b_data + ext_size, 0, inode->i_sb->s_blocksize - ext_size);
|
|
ext4_extent_block_csum_set(inode, neh);
|
|
set_buffer_uptodate(bh);
|
|
unlock_buffer(bh);
|
|
@@ -1219,6 +1224,11 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
|
sizeof(struct ext4_extent_idx) * m);
|
|
le16_add_cpu(&neh->eh_entries, m);
|
|
}
|
|
+ /* zero out unused area in the extent block */
|
|
+ ext_size = sizeof(struct ext4_extent_header) +
|
|
+ (sizeof(struct ext4_extent) * le16_to_cpu(neh->eh_entries));
|
|
+ memset(bh->b_data + ext_size, 0,
|
|
+ inode->i_sb->s_blocksize - ext_size);
|
|
ext4_extent_block_csum_set(inode, neh);
|
|
set_buffer_uptodate(bh);
|
|
unlock_buffer(bh);
|
|
@@ -1284,6 +1294,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
|
|
ext4_fsblk_t newblock, goal = 0;
|
|
struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
|
|
int err = 0;
|
|
+ size_t ext_size = 0;
|
|
|
|
/* Try to prepend new index to old one */
|
|
if (ext_depth(inode))
|
|
@@ -1309,9 +1320,11 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
|
|
goto out;
|
|
}
|
|
|
|
+ ext_size = sizeof(EXT4_I(inode)->i_data);
|
|
/* move top-level index/leaf into new block */
|
|
- memmove(bh->b_data, EXT4_I(inode)->i_data,
|
|
- sizeof(EXT4_I(inode)->i_data));
|
|
+ memmove(bh->b_data, EXT4_I(inode)->i_data, ext_size);
|
|
+ /* zero out unused area in the extent block */
|
|
+ memset(bh->b_data + ext_size, 0, inode->i_sb->s_blocksize - ext_size);
|
|
|
|
/* set size of new block */
|
|
neh = ext_block_hdr(bh);
|
|
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
|
|
index 181db3c7f5d1..063c5991f095 100644
|
|
--- a/fs/ext4/inode.c
|
|
+++ b/fs/ext4/inode.c
|
|
@@ -4944,7 +4944,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
|
|
up_write(&EXT4_I(inode)->i_data_sem);
|
|
ext4_journal_stop(handle);
|
|
if (error) {
|
|
- if (orphan)
|
|
+ if (orphan && inode->i_nlink)
|
|
ext4_orphan_del(NULL, inode);
|
|
goto err_out;
|
|
}
|
|
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
|
|
index e44e3cd738b6..b02f210ea617 100644
|
|
--- a/fs/ext4/ioctl.c
|
|
+++ b/fs/ext4/ioctl.c
|
|
@@ -577,7 +577,7 @@ group_add_out:
|
|
if (err == 0)
|
|
err = err2;
|
|
mnt_drop_write_file(filp);
|
|
- if (!err && (o_group > EXT4_SB(sb)->s_groups_count) &&
|
|
+ if (!err && (o_group < EXT4_SB(sb)->s_groups_count) &&
|
|
ext4_has_group_desc_csum(sb) &&
|
|
test_opt(sb, INIT_INODE_TABLE))
|
|
err = ext4_register_li_request(sb, o_group);
|
|
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
|
|
index 6a7df72cb3da..6f00388a1471 100644
|
|
--- a/fs/ext4/super.c
|
|
+++ b/fs/ext4/super.c
|
|
@@ -3867,7 +3867,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|
"data=, fs mounted w/o journal");
|
|
goto failed_mount_wq;
|
|
}
|
|
- sbi->s_def_mount_opt &= EXT4_MOUNT_JOURNAL_CHECKSUM;
|
|
+ sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM;
|
|
clear_opt(sb, JOURNAL_CHECKSUM);
|
|
clear_opt(sb, DATA_FLAGS);
|
|
sbi->s_journal = NULL;
|
|
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
|
|
index cfb75dbb96f5..76597dd8cfe8 100644
|
|
--- a/fs/fs-writeback.c
|
|
+++ b/fs/fs-writeback.c
|
|
@@ -331,11 +331,22 @@ struct inode_switch_wbs_context {
|
|
struct work_struct work;
|
|
};
|
|
|
|
+static void bdi_down_write_wb_switch_rwsem(struct backing_dev_info *bdi)
|
|
+{
|
|
+ down_write(&bdi->wb_switch_rwsem);
|
|
+}
|
|
+
|
|
+static void bdi_up_write_wb_switch_rwsem(struct backing_dev_info *bdi)
|
|
+{
|
|
+ up_write(&bdi->wb_switch_rwsem);
|
|
+}
|
|
+
|
|
static void inode_switch_wbs_work_fn(struct work_struct *work)
|
|
{
|
|
struct inode_switch_wbs_context *isw =
|
|
container_of(work, struct inode_switch_wbs_context, work);
|
|
struct inode *inode = isw->inode;
|
|
+ struct backing_dev_info *bdi = inode_to_bdi(inode);
|
|
struct address_space *mapping = inode->i_mapping;
|
|
struct bdi_writeback *old_wb = inode->i_wb;
|
|
struct bdi_writeback *new_wb = isw->new_wb;
|
|
@@ -343,6 +354,12 @@ static void inode_switch_wbs_work_fn(struct work_struct *work)
|
|
bool switched = false;
|
|
void **slot;
|
|
|
|
+ /*
|
|
+ * If @inode switches cgwb membership while sync_inodes_sb() is
|
|
+ * being issued, sync_inodes_sb() might miss it. Synchronize.
|
|
+ */
|
|
+ down_read(&bdi->wb_switch_rwsem);
|
|
+
|
|
/*
|
|
* By the time control reaches here, RCU grace period has passed
|
|
* since I_WB_SWITCH assertion and all wb stat update transactions
|
|
@@ -435,6 +452,8 @@ skip_switch:
|
|
spin_unlock(&new_wb->list_lock);
|
|
spin_unlock(&old_wb->list_lock);
|
|
|
|
+ up_read(&bdi->wb_switch_rwsem);
|
|
+
|
|
if (switched) {
|
|
wb_wakeup(new_wb);
|
|
wb_put(old_wb);
|
|
@@ -475,9 +494,18 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
|
|
if (inode->i_state & I_WB_SWITCH)
|
|
return;
|
|
|
|
+ /*
|
|
+ * Avoid starting new switches while sync_inodes_sb() is in
|
|
+ * progress. Otherwise, if the down_write protected issue path
|
|
+ * blocks heavily, we might end up starting a large number of
|
|
+ * switches which will block on the rwsem.
|
|
+ */
|
|
+ if (!down_read_trylock(&bdi->wb_switch_rwsem))
|
|
+ return;
|
|
+
|
|
isw = kzalloc(sizeof(*isw), GFP_ATOMIC);
|
|
if (!isw)
|
|
- return;
|
|
+ goto out_unlock;
|
|
|
|
/* find and pin the new wb */
|
|
rcu_read_lock();
|
|
@@ -502,8 +530,6 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
|
|
ihold(inode);
|
|
isw->inode = inode;
|
|
|
|
- atomic_inc(&isw_nr_in_flight);
|
|
-
|
|
/*
|
|
* In addition to synchronizing among switchers, I_WB_SWITCH tells
|
|
* the RCU protected stat update paths to grab the mapping's
|
|
@@ -511,12 +537,17 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
|
|
* Let's continue after I_WB_SWITCH is guaranteed to be visible.
|
|
*/
|
|
call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn);
|
|
- return;
|
|
+
|
|
+ atomic_inc(&isw_nr_in_flight);
|
|
+
|
|
+ goto out_unlock;
|
|
|
|
out_free:
|
|
if (isw->new_wb)
|
|
wb_put(isw->new_wb);
|
|
kfree(isw);
|
|
+out_unlock:
|
|
+ up_read(&bdi->wb_switch_rwsem);
|
|
}
|
|
|
|
/**
|
|
@@ -880,7 +911,11 @@ restart:
|
|
void cgroup_writeback_umount(void)
|
|
{
|
|
if (atomic_read(&isw_nr_in_flight)) {
|
|
- synchronize_rcu();
|
|
+ /*
|
|
+ * Use rcu_barrier() to wait for all pending callbacks to
|
|
+ * ensure that all in-flight wb switches are in the workqueue.
|
|
+ */
|
|
+ rcu_barrier();
|
|
flush_workqueue(isw_wq);
|
|
}
|
|
}
|
|
@@ -896,6 +931,9 @@ fs_initcall(cgroup_writeback_init);
|
|
|
|
#else /* CONFIG_CGROUP_WRITEBACK */
|
|
|
|
+static void bdi_down_write_wb_switch_rwsem(struct backing_dev_info *bdi) { }
|
|
+static void bdi_up_write_wb_switch_rwsem(struct backing_dev_info *bdi) { }
|
|
+
|
|
static struct bdi_writeback *
|
|
locked_inode_to_wb_and_lock_list(struct inode *inode)
|
|
__releases(&inode->i_lock)
|
|
@@ -2341,8 +2379,11 @@ void sync_inodes_sb(struct super_block *sb)
|
|
return;
|
|
WARN_ON(!rwsem_is_locked(&sb->s_umount));
|
|
|
|
+ /* protect against inode wb switch, see inode_switch_wbs_work_fn() */
|
|
+ bdi_down_write_wb_switch_rwsem(bdi);
|
|
bdi_split_work_to_wbs(bdi, &work, false);
|
|
wb_wait_for_completion(bdi, &done);
|
|
+ bdi_up_write_wb_switch_rwsem(bdi);
|
|
|
|
wait_sb_inodes(sb);
|
|
}
|
|
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
|
|
index d40c2451487c..ab93c4591f8c 100644
|
|
--- a/fs/fuse/file.c
|
|
+++ b/fs/fuse/file.c
|
|
@@ -178,7 +178,9 @@ void fuse_finish_open(struct inode *inode, struct file *file)
|
|
file->f_op = &fuse_direct_io_file_operations;
|
|
if (!(ff->open_flags & FOPEN_KEEP_CACHE))
|
|
invalidate_inode_pages2(inode->i_mapping);
|
|
- if (ff->open_flags & FOPEN_NONSEEKABLE)
|
|
+ if (ff->open_flags & FOPEN_STREAM)
|
|
+ stream_open(inode, file);
|
|
+ else if (ff->open_flags & FOPEN_NONSEEKABLE)
|
|
nonseekable_open(inode, file);
|
|
if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) {
|
|
struct fuse_inode *fi = get_fuse_inode(inode);
|
|
@@ -1533,7 +1535,7 @@ __acquires(fc->lock)
|
|
{
|
|
struct fuse_conn *fc = get_fuse_conn(inode);
|
|
struct fuse_inode *fi = get_fuse_inode(inode);
|
|
- size_t crop = i_size_read(inode);
|
|
+ loff_t crop = i_size_read(inode);
|
|
struct fuse_req *req;
|
|
|
|
while (fi->writectr >= 0 && !list_empty(&fi->queued_writes)) {
|
|
@@ -2947,6 +2949,13 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
|
|
}
|
|
}
|
|
|
|
+ if (!(mode & FALLOC_FL_KEEP_SIZE) &&
|
|
+ offset + length > i_size_read(inode)) {
|
|
+ err = inode_newsize_ok(inode, offset + length);
|
|
+ if (err)
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
if (!(mode & FALLOC_FL_KEEP_SIZE))
|
|
set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
|
|
|
|
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
|
|
index 09a0cf5f3dd8..1eb737c466dd 100644
|
|
--- a/fs/gfs2/glock.c
|
|
+++ b/fs/gfs2/glock.c
|
|
@@ -136,22 +136,26 @@ static int demote_ok(const struct gfs2_glock *gl)
|
|
|
|
void gfs2_glock_add_to_lru(struct gfs2_glock *gl)
|
|
{
|
|
+ if (!(gl->gl_ops->go_flags & GLOF_LRU))
|
|
+ return;
|
|
+
|
|
spin_lock(&lru_lock);
|
|
|
|
- if (!list_empty(&gl->gl_lru))
|
|
- list_del_init(&gl->gl_lru);
|
|
- else
|
|
+ list_del(&gl->gl_lru);
|
|
+ list_add_tail(&gl->gl_lru, &lru_list);
|
|
+
|
|
+ if (!test_bit(GLF_LRU, &gl->gl_flags)) {
|
|
+ set_bit(GLF_LRU, &gl->gl_flags);
|
|
atomic_inc(&lru_count);
|
|
+ }
|
|
|
|
- list_add_tail(&gl->gl_lru, &lru_list);
|
|
- set_bit(GLF_LRU, &gl->gl_flags);
|
|
spin_unlock(&lru_lock);
|
|
}
|
|
|
|
static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl)
|
|
{
|
|
spin_lock(&lru_lock);
|
|
- if (!list_empty(&gl->gl_lru)) {
|
|
+ if (test_bit(GLF_LRU, &gl->gl_flags)) {
|
|
list_del_init(&gl->gl_lru);
|
|
atomic_dec(&lru_count);
|
|
clear_bit(GLF_LRU, &gl->gl_flags);
|
|
@@ -1040,8 +1044,7 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
|
|
!test_bit(GLF_DEMOTE, &gl->gl_flags))
|
|
fast_path = 1;
|
|
}
|
|
- if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl) &&
|
|
- (glops->go_flags & GLOF_LRU))
|
|
+ if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl))
|
|
gfs2_glock_add_to_lru(gl);
|
|
|
|
trace_gfs2_glock_queue(gh, 0);
|
|
@@ -1341,6 +1344,7 @@ __acquires(&lru_lock)
|
|
if (!spin_trylock(&gl->gl_lockref.lock)) {
|
|
add_back_to_lru:
|
|
list_add(&gl->gl_lru, &lru_list);
|
|
+ set_bit(GLF_LRU, &gl->gl_flags);
|
|
atomic_inc(&lru_count);
|
|
continue;
|
|
}
|
|
@@ -1348,7 +1352,6 @@ add_back_to_lru:
|
|
spin_unlock(&gl->gl_lockref.lock);
|
|
goto add_back_to_lru;
|
|
}
|
|
- clear_bit(GLF_LRU, &gl->gl_flags);
|
|
gl->gl_lockref.count++;
|
|
if (demote_ok(gl))
|
|
handle_callback(gl, LM_ST_UNLOCKED, 0, false);
|
|
@@ -1384,6 +1387,7 @@ static long gfs2_scan_glock_lru(int nr)
|
|
if (!test_bit(GLF_LOCK, &gl->gl_flags)) {
|
|
list_move(&gl->gl_lru, &dispose);
|
|
atomic_dec(&lru_count);
|
|
+ clear_bit(GLF_LRU, &gl->gl_flags);
|
|
freed++;
|
|
continue;
|
|
}
|
|
diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c
|
|
index 8b907c5cc913..3c3d037df824 100644
|
|
--- a/fs/gfs2/lock_dlm.c
|
|
+++ b/fs/gfs2/lock_dlm.c
|
|
@@ -32,9 +32,10 @@ extern struct workqueue_struct *gfs2_control_wq;
|
|
* @delta is the difference between the current rtt sample and the
|
|
* running average srtt. We add 1/8 of that to the srtt in order to
|
|
* update the current srtt estimate. The variance estimate is a bit
|
|
- * more complicated. We subtract the abs value of the @delta from
|
|
- * the current variance estimate and add 1/4 of that to the running
|
|
- * total.
|
|
+ * more complicated. We subtract the current variance estimate from
|
|
+ * the abs value of the @delta and add 1/4 of that to the running
|
|
+ * total. That's equivalent to 3/4 of the current variance
|
|
+ * estimate plus 1/4 of the abs of @delta.
|
|
*
|
|
* Note that the index points at the array entry containing the smoothed
|
|
* mean value, and the variance is always in the following entry
|
|
@@ -50,7 +51,7 @@ static inline void gfs2_update_stats(struct gfs2_lkstats *s, unsigned index,
|
|
s64 delta = sample - s->stats[index];
|
|
s->stats[index] += (delta >> 3);
|
|
index++;
|
|
- s->stats[index] += ((abs(delta) - s->stats[index]) >> 2);
|
|
+ s->stats[index] += (s64)(abs(delta) - s->stats[index]) >> 2;
|
|
}
|
|
|
|
/**
|
|
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
|
|
index 27c4e2ac39a9..937c6ee1786f 100644
|
|
--- a/fs/hugetlbfs/inode.c
|
|
+++ b/fs/hugetlbfs/inode.c
|
|
@@ -414,9 +414,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
|
|
if (next >= end)
|
|
break;
|
|
|
|
- hash = hugetlb_fault_mutex_hash(h, current->mm,
|
|
- &pseudo_vma,
|
|
- mapping, next, 0);
|
|
+ hash = hugetlb_fault_mutex_hash(h, mapping, next, 0);
|
|
mutex_lock(&hugetlb_fault_mutex_table[hash]);
|
|
|
|
lock_page(page);
|
|
@@ -569,7 +567,6 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
|
|
struct address_space *mapping = inode->i_mapping;
|
|
struct hstate *h = hstate_inode(inode);
|
|
struct vm_area_struct pseudo_vma;
|
|
- struct mm_struct *mm = current->mm;
|
|
loff_t hpage_size = huge_page_size(h);
|
|
unsigned long hpage_shift = huge_page_shift(h);
|
|
pgoff_t start, index, end;
|
|
@@ -633,8 +630,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
|
|
addr = index * hpage_size;
|
|
|
|
/* mutex taken here, fault path and hole punch */
|
|
- hash = hugetlb_fault_mutex_hash(h, mm, &pseudo_vma, mapping,
|
|
- index, addr);
|
|
+ hash = hugetlb_fault_mutex_hash(h, mapping, index, addr);
|
|
mutex_lock(&hugetlb_fault_mutex_table[hash]);
|
|
|
|
/* See if already present in mapping to avoid alloc/free */
|
|
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
|
|
index 44f5cea49699..5be61affeefd 100644
|
|
--- a/fs/nfs/nfs4state.c
|
|
+++ b/fs/nfs/nfs4state.c
|
|
@@ -140,6 +140,10 @@ int nfs40_discover_server_trunking(struct nfs_client *clp,
|
|
/* Sustain the lease, even if it's empty. If the clientid4
|
|
* goes stale it's of no use for trunking discovery. */
|
|
nfs4_schedule_state_renewal(*result);
|
|
+
|
|
+ /* If the client state need to recover, do it. */
|
|
+ if (clp->cl_state)
|
|
+ nfs4_schedule_state_manager(clp);
|
|
}
|
|
out:
|
|
return status;
|
|
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
|
|
index 3494e220b510..bed15dec3c16 100644
|
|
--- a/fs/ocfs2/export.c
|
|
+++ b/fs/ocfs2/export.c
|
|
@@ -148,16 +148,24 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
|
|
u64 blkno;
|
|
struct dentry *parent;
|
|
struct inode *dir = d_inode(child);
|
|
+ int set;
|
|
|
|
trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name,
|
|
(unsigned long long)OCFS2_I(dir)->ip_blkno);
|
|
|
|
+ status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), 1);
|
|
+ if (status < 0) {
|
|
+ mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
|
|
+ parent = ERR_PTR(status);
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
status = ocfs2_inode_lock(dir, NULL, 0);
|
|
if (status < 0) {
|
|
if (status != -ENOENT)
|
|
mlog_errno(status);
|
|
parent = ERR_PTR(status);
|
|
- goto bail;
|
|
+ goto unlock_nfs_sync;
|
|
}
|
|
|
|
status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
|
|
@@ -166,11 +174,31 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
|
|
goto bail_unlock;
|
|
}
|
|
|
|
+ status = ocfs2_test_inode_bit(OCFS2_SB(dir->i_sb), blkno, &set);
|
|
+ if (status < 0) {
|
|
+ if (status == -EINVAL) {
|
|
+ status = -ESTALE;
|
|
+ } else
|
|
+ mlog(ML_ERROR, "test inode bit failed %d\n", status);
|
|
+ parent = ERR_PTR(status);
|
|
+ goto bail_unlock;
|
|
+ }
|
|
+
|
|
+ trace_ocfs2_get_dentry_test_bit(status, set);
|
|
+ if (!set) {
|
|
+ status = -ESTALE;
|
|
+ parent = ERR_PTR(status);
|
|
+ goto bail_unlock;
|
|
+ }
|
|
+
|
|
parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0));
|
|
|
|
bail_unlock:
|
|
ocfs2_inode_unlock(dir, 0);
|
|
|
|
+unlock_nfs_sync:
|
|
+ ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), 1);
|
|
+
|
|
bail:
|
|
trace_ocfs2_get_parent_end(parent);
|
|
|
|
diff --git a/fs/open.c b/fs/open.c
|
|
index fbc5c7b230b3..6cf516156111 100644
|
|
--- a/fs/open.c
|
|
+++ b/fs/open.c
|
|
@@ -1152,3 +1152,21 @@ int nonseekable_open(struct inode *inode, struct file *filp)
|
|
}
|
|
|
|
EXPORT_SYMBOL(nonseekable_open);
|
|
+
|
|
+/*
|
|
+ * stream_open is used by subsystems that want stream-like file descriptors.
|
|
+ * Such file descriptors are not seekable and don't have notion of position
|
|
+ * (file.f_pos is always 0). Contrary to file descriptors of other regular
|
|
+ * files, .read() and .write() can run simultaneously.
|
|
+ *
|
|
+ * stream_open never fails and is marked to return int so that it could be
|
|
+ * directly used as file_operations.open .
|
|
+ */
|
|
+int stream_open(struct inode *inode, struct file *filp)
|
|
+{
|
|
+ filp->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE | FMODE_ATOMIC_POS);
|
|
+ filp->f_mode |= FMODE_STREAM;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+EXPORT_SYMBOL(stream_open);
|
|
diff --git a/fs/read_write.c b/fs/read_write.c
|
|
index 16e554ba885d..7b175b9134ec 100644
|
|
--- a/fs/read_write.c
|
|
+++ b/fs/read_write.c
|
|
@@ -553,12 +553,13 @@ EXPORT_SYMBOL(vfs_write);
|
|
|
|
static inline loff_t file_pos_read(struct file *file)
|
|
{
|
|
- return file->f_pos;
|
|
+ return file->f_mode & FMODE_STREAM ? 0 : file->f_pos;
|
|
}
|
|
|
|
static inline void file_pos_write(struct file *file, loff_t pos)
|
|
{
|
|
- file->f_pos = pos;
|
|
+ if ((file->f_mode & FMODE_STREAM) == 0)
|
|
+ file->f_pos = pos;
|
|
}
|
|
|
|
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
|
|
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
|
|
index 3f9463f8cf2f..f877d5cadd98 100644
|
|
--- a/fs/ufs/util.h
|
|
+++ b/fs/ufs/util.h
|
|
@@ -228,7 +228,7 @@ ufs_get_inode_gid(struct super_block *sb, struct ufs_inode *inode)
|
|
case UFS_UID_44BSD:
|
|
return fs32_to_cpu(sb, inode->ui_u3.ui_44.ui_gid);
|
|
case UFS_UID_EFT:
|
|
- if (inode->ui_u1.oldids.ui_suid == 0xFFFF)
|
|
+ if (inode->ui_u1.oldids.ui_sgid == 0xFFFF)
|
|
return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_gid);
|
|
/* Fall through */
|
|
default:
|
|
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
|
|
index 59d58bdad7d3..e93541282aa1 100644
|
|
--- a/fs/userfaultfd.c
|
|
+++ b/fs/userfaultfd.c
|
|
@@ -137,7 +137,7 @@ static void userfaultfd_ctx_put(struct userfaultfd_ctx *ctx)
|
|
VM_BUG_ON(waitqueue_active(&ctx->fault_wqh));
|
|
VM_BUG_ON(spin_is_locked(&ctx->fd_wqh.lock));
|
|
VM_BUG_ON(waitqueue_active(&ctx->fd_wqh));
|
|
- mmput(ctx->mm);
|
|
+ mmdrop(ctx->mm);
|
|
kmem_cache_free(userfaultfd_ctx_cachep, ctx);
|
|
}
|
|
}
|
|
@@ -434,6 +434,9 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
|
|
|
|
ACCESS_ONCE(ctx->released) = true;
|
|
|
|
+ if (!mmget_not_zero(mm))
|
|
+ goto wakeup;
|
|
+
|
|
/*
|
|
* Flush page faults out of all CPUs. NOTE: all page faults
|
|
* must be retried without returning VM_FAULT_SIGBUS if
|
|
@@ -466,7 +469,8 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
|
|
vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
|
|
}
|
|
up_write(&mm->mmap_sem);
|
|
-
|
|
+ mmput(mm);
|
|
+wakeup:
|
|
/*
|
|
* After no new page faults can wait on this fault_*wqh, flush
|
|
* the last page faults that may have been already waiting on
|
|
@@ -760,10 +764,12 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
|
|
start = uffdio_register.range.start;
|
|
end = start + uffdio_register.range.len;
|
|
|
|
+ ret = -ENOMEM;
|
|
+ if (!mmget_not_zero(mm))
|
|
+ goto out;
|
|
+
|
|
down_write(&mm->mmap_sem);
|
|
vma = find_vma_prev(mm, start, &prev);
|
|
-
|
|
- ret = -ENOMEM;
|
|
if (!vma)
|
|
goto out_unlock;
|
|
|
|
@@ -864,6 +870,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
|
|
} while (vma && vma->vm_start < end);
|
|
out_unlock:
|
|
up_write(&mm->mmap_sem);
|
|
+ mmput(mm);
|
|
if (!ret) {
|
|
/*
|
|
* Now that we scanned all vmas we can already tell
|
|
@@ -902,10 +909,12 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
|
|
start = uffdio_unregister.start;
|
|
end = start + uffdio_unregister.len;
|
|
|
|
+ ret = -ENOMEM;
|
|
+ if (!mmget_not_zero(mm))
|
|
+ goto out;
|
|
+
|
|
down_write(&mm->mmap_sem);
|
|
vma = find_vma_prev(mm, start, &prev);
|
|
-
|
|
- ret = -ENOMEM;
|
|
if (!vma)
|
|
goto out_unlock;
|
|
|
|
@@ -998,6 +1007,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
|
|
} while (vma && vma->vm_start < end);
|
|
out_unlock:
|
|
up_write(&mm->mmap_sem);
|
|
+ mmput(mm);
|
|
out:
|
|
return ret;
|
|
}
|
|
@@ -1067,9 +1077,11 @@ static int userfaultfd_copy(struct userfaultfd_ctx *ctx,
|
|
goto out;
|
|
if (uffdio_copy.mode & ~UFFDIO_COPY_MODE_DONTWAKE)
|
|
goto out;
|
|
-
|
|
- ret = mcopy_atomic(ctx->mm, uffdio_copy.dst, uffdio_copy.src,
|
|
- uffdio_copy.len);
|
|
+ if (mmget_not_zero(ctx->mm)) {
|
|
+ ret = mcopy_atomic(ctx->mm, uffdio_copy.dst, uffdio_copy.src,
|
|
+ uffdio_copy.len);
|
|
+ mmput(ctx->mm);
|
|
+ }
|
|
if (unlikely(put_user(ret, &user_uffdio_copy->copy)))
|
|
return -EFAULT;
|
|
if (ret < 0)
|
|
@@ -1110,8 +1122,11 @@ static int userfaultfd_zeropage(struct userfaultfd_ctx *ctx,
|
|
if (uffdio_zeropage.mode & ~UFFDIO_ZEROPAGE_MODE_DONTWAKE)
|
|
goto out;
|
|
|
|
- ret = mfill_zeropage(ctx->mm, uffdio_zeropage.range.start,
|
|
- uffdio_zeropage.range.len);
|
|
+ if (mmget_not_zero(ctx->mm)) {
|
|
+ ret = mfill_zeropage(ctx->mm, uffdio_zeropage.range.start,
|
|
+ uffdio_zeropage.range.len);
|
|
+ mmput(ctx->mm);
|
|
+ }
|
|
if (unlikely(put_user(ret, &user_uffdio_zeropage->zeropage)))
|
|
return -EFAULT;
|
|
if (ret < 0)
|
|
@@ -1289,12 +1304,12 @@ static struct file *userfaultfd_file_create(int flags)
|
|
ctx->released = false;
|
|
ctx->mm = current->mm;
|
|
/* prevent the mm struct to be freed */
|
|
- atomic_inc(&ctx->mm->mm_users);
|
|
+ atomic_inc(&ctx->mm->mm_count);
|
|
|
|
file = anon_inode_getfile("[userfaultfd]", &userfaultfd_fops, ctx,
|
|
O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS));
|
|
if (IS_ERR(file)) {
|
|
- mmput(ctx->mm);
|
|
+ mmdrop(ctx->mm);
|
|
kmem_cache_free(userfaultfd_ctx_cachep, ctx);
|
|
}
|
|
out:
|
|
diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h
|
|
index 072501a0ac86..dfa6d4f08b99 100644
|
|
--- a/include/linux/backing-dev-defs.h
|
|
+++ b/include/linux/backing-dev-defs.h
|
|
@@ -157,6 +157,7 @@ struct backing_dev_info {
|
|
struct radix_tree_root cgwb_tree; /* radix tree of active cgroup wbs */
|
|
struct rb_root cgwb_congested_tree; /* their congested states */
|
|
atomic_t usage_cnt; /* counts both cgwbs and cgwb_contested's */
|
|
+ struct rw_semaphore wb_switch_rwsem; /* no cgwb switch while syncing */
|
|
#else
|
|
struct bdi_writeback_congested *wb_congested;
|
|
#endif
|
|
diff --git a/include/linux/bio.h b/include/linux/bio.h
|
|
index 42e4e3cbb001..0ffb9a397620 100644
|
|
--- a/include/linux/bio.h
|
|
+++ b/include/linux/bio.h
|
|
@@ -290,7 +290,7 @@ static inline void bio_cnt_set(struct bio *bio, unsigned int count)
|
|
{
|
|
if (count != 1) {
|
|
bio->bi_flags |= (1 << BIO_REFFED);
|
|
- smp_mb__before_atomic();
|
|
+ smp_mb();
|
|
}
|
|
atomic_set(&bio->__bi_cnt, count);
|
|
}
|
|
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
|
|
index e76d03f44c80..83edade218fa 100644
|
|
--- a/include/linux/bitops.h
|
|
+++ b/include/linux/bitops.h
|
|
@@ -68,7 +68,7 @@ static __always_inline unsigned long hweight_long(unsigned long w)
|
|
*/
|
|
static inline __u64 rol64(__u64 word, unsigned int shift)
|
|
{
|
|
- return (word << shift) | (word >> (64 - shift));
|
|
+ return (word << (shift & 63)) | (word >> ((-shift) & 63));
|
|
}
|
|
|
|
/**
|
|
@@ -78,7 +78,7 @@ static inline __u64 rol64(__u64 word, unsigned int shift)
|
|
*/
|
|
static inline __u64 ror64(__u64 word, unsigned int shift)
|
|
{
|
|
- return (word >> shift) | (word << (64 - shift));
|
|
+ return (word >> (shift & 63)) | (word << ((-shift) & 63));
|
|
}
|
|
|
|
/**
|
|
@@ -88,7 +88,7 @@ static inline __u64 ror64(__u64 word, unsigned int shift)
|
|
*/
|
|
static inline __u32 rol32(__u32 word, unsigned int shift)
|
|
{
|
|
- return (word << shift) | (word >> ((-shift) & 31));
|
|
+ return (word << (shift & 31)) | (word >> ((-shift) & 31));
|
|
}
|
|
|
|
/**
|
|
@@ -98,7 +98,7 @@ static inline __u32 rol32(__u32 word, unsigned int shift)
|
|
*/
|
|
static inline __u32 ror32(__u32 word, unsigned int shift)
|
|
{
|
|
- return (word >> shift) | (word << (32 - shift));
|
|
+ return (word >> (shift & 31)) | (word << ((-shift) & 31));
|
|
}
|
|
|
|
/**
|
|
@@ -108,7 +108,7 @@ static inline __u32 ror32(__u32 word, unsigned int shift)
|
|
*/
|
|
static inline __u16 rol16(__u16 word, unsigned int shift)
|
|
{
|
|
- return (word << shift) | (word >> (16 - shift));
|
|
+ return (word << (shift & 15)) | (word >> ((-shift) & 15));
|
|
}
|
|
|
|
/**
|
|
@@ -118,7 +118,7 @@ static inline __u16 rol16(__u16 word, unsigned int shift)
|
|
*/
|
|
static inline __u16 ror16(__u16 word, unsigned int shift)
|
|
{
|
|
- return (word >> shift) | (word << (16 - shift));
|
|
+ return (word >> (shift & 15)) | (word << ((-shift) & 15));
|
|
}
|
|
|
|
/**
|
|
@@ -128,7 +128,7 @@ static inline __u16 ror16(__u16 word, unsigned int shift)
|
|
*/
|
|
static inline __u8 rol8(__u8 word, unsigned int shift)
|
|
{
|
|
- return (word << shift) | (word >> (8 - shift));
|
|
+ return (word << (shift & 7)) | (word >> ((-shift) & 7));
|
|
}
|
|
|
|
/**
|
|
@@ -138,7 +138,7 @@ static inline __u8 rol8(__u8 word, unsigned int shift)
|
|
*/
|
|
static inline __u8 ror8(__u8 word, unsigned int shift)
|
|
{
|
|
- return (word >> shift) | (word << (8 - shift));
|
|
+ return (word >> (shift & 7)) | (word << ((-shift) & 7));
|
|
}
|
|
|
|
/**
|
|
diff --git a/include/linux/fs.h b/include/linux/fs.h
|
|
index 13277d2715df..26c4bf47cc99 100644
|
|
--- a/include/linux/fs.h
|
|
+++ b/include/linux/fs.h
|
|
@@ -140,6 +140,9 @@ typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate);
|
|
/* Has write method(s) */
|
|
#define FMODE_CAN_WRITE ((__force fmode_t)0x40000)
|
|
|
|
+/* File is stream-like */
|
|
+#define FMODE_STREAM ((__force fmode_t)0x200000)
|
|
+
|
|
/* File was opened by fanotify and shouldn't generate fanotify events */
|
|
#define FMODE_NONOTIFY ((__force fmode_t)0x4000000)
|
|
|
|
@@ -2706,6 +2709,7 @@ extern loff_t fixed_size_llseek(struct file *file, loff_t offset,
|
|
int whence, loff_t size);
|
|
extern int generic_file_open(struct inode * inode, struct file * filp);
|
|
extern int nonseekable_open(struct inode * inode, struct file * filp);
|
|
+extern int stream_open(struct inode * inode, struct file * filp);
|
|
|
|
#ifdef CONFIG_BLOCK
|
|
typedef void (dio_submit_t)(int rw, struct bio *bio, struct inode *inode,
|
|
diff --git a/include/linux/hid.h b/include/linux/hid.h
|
|
index fd86687f8119..5f3131885136 100644
|
|
--- a/include/linux/hid.h
|
|
+++ b/include/linux/hid.h
|
|
@@ -372,6 +372,7 @@ struct hid_global {
|
|
|
|
struct hid_local {
|
|
unsigned usage[HID_MAX_USAGES]; /* usage array */
|
|
+ u8 usage_size[HID_MAX_USAGES]; /* usage size array */
|
|
unsigned collection_index[HID_MAX_USAGES]; /* collection index array */
|
|
unsigned usage_index;
|
|
unsigned usage_minimum;
|
|
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
|
|
index 3957d99e66ea..cc185525a94b 100644
|
|
--- a/include/linux/hugetlb.h
|
|
+++ b/include/linux/hugetlb.h
|
|
@@ -91,9 +91,7 @@ void putback_active_hugepage(struct page *page);
|
|
void free_huge_page(struct page *page);
|
|
void hugetlb_fix_reserve_counts(struct inode *inode, bool restore_reserve);
|
|
extern struct mutex *hugetlb_fault_mutex_table;
|
|
-u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
|
|
- struct vm_area_struct *vma,
|
|
- struct address_space *mapping,
|
|
+u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
|
|
pgoff_t idx, unsigned long address);
|
|
|
|
#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
|
|
diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h
|
|
index 6cc48ac55fd2..40b14736c73d 100644
|
|
--- a/include/linux/iio/adc/ad_sigma_delta.h
|
|
+++ b/include/linux/iio/adc/ad_sigma_delta.h
|
|
@@ -66,6 +66,7 @@ struct ad_sigma_delta {
|
|
bool irq_dis;
|
|
|
|
bool bus_locked;
|
|
+ bool keep_cs_asserted;
|
|
|
|
uint8_t comm;
|
|
|
|
diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h
|
|
index 743b34f56f2b..f9a8889e134a 100644
|
|
--- a/include/linux/list_lru.h
|
|
+++ b/include/linux/list_lru.h
|
|
@@ -51,6 +51,7 @@ struct list_lru {
|
|
struct list_lru_node *node;
|
|
#ifdef CONFIG_MEMCG_KMEM
|
|
struct list_head list;
|
|
+ bool memcg_aware;
|
|
#endif
|
|
};
|
|
|
|
diff --git a/include/linux/mfd/da9063/registers.h b/include/linux/mfd/da9063/registers.h
|
|
index 2e0ba6d5fbc3..f97173bef581 100644
|
|
--- a/include/linux/mfd/da9063/registers.h
|
|
+++ b/include/linux/mfd/da9063/registers.h
|
|
@@ -215,9 +215,9 @@
|
|
|
|
/* DA9063 Configuration registers */
|
|
/* OTP */
|
|
-#define DA9063_REG_OPT_COUNT 0x101
|
|
-#define DA9063_REG_OPT_ADDR 0x102
|
|
-#define DA9063_REG_OPT_DATA 0x103
|
|
+#define DA9063_REG_OTP_CONT 0x101
|
|
+#define DA9063_REG_OTP_ADDR 0x102
|
|
+#define DA9063_REG_OTP_DATA 0x103
|
|
|
|
/* Customer Trim and Configuration */
|
|
#define DA9063_REG_T_OFFSET 0x104
|
|
diff --git a/include/linux/of.h b/include/linux/of.h
|
|
index d9371c9cd88a..2772f027f88f 100644
|
|
--- a/include/linux/of.h
|
|
+++ b/include/linux/of.h
|
|
@@ -199,8 +199,8 @@ extern struct device_node *of_find_all_nodes(struct device_node *prev);
|
|
static inline u64 of_read_number(const __be32 *cell, int size)
|
|
{
|
|
u64 r = 0;
|
|
- while (size--)
|
|
- r = (r << 32) | be32_to_cpu(*(cell++));
|
|
+ for (; size--; cell++)
|
|
+ r = (r << 32) | be32_to_cpu(*cell);
|
|
return r;
|
|
}
|
|
|
|
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
|
|
index a0189ba67fde..addd03641e1a 100644
|
|
--- a/include/linux/rcupdate.h
|
|
+++ b/include/linux/rcupdate.h
|
|
@@ -297,14 +297,12 @@ void synchronize_rcu(void);
|
|
|
|
static inline void __rcu_read_lock(void)
|
|
{
|
|
- if (IS_ENABLED(CONFIG_PREEMPT_COUNT))
|
|
- preempt_disable();
|
|
+ preempt_disable();
|
|
}
|
|
|
|
static inline void __rcu_read_unlock(void)
|
|
{
|
|
- if (IS_ENABLED(CONFIG_PREEMPT_COUNT))
|
|
- preempt_enable();
|
|
+ preempt_enable();
|
|
}
|
|
|
|
static inline void synchronize_rcu(void)
|
|
diff --git a/include/linux/sched.h b/include/linux/sched.h
|
|
index a0b540f800d9..315df144c156 100644
|
|
--- a/include/linux/sched.h
|
|
+++ b/include/linux/sched.h
|
|
@@ -2614,12 +2614,17 @@ extern struct mm_struct * mm_alloc(void);
|
|
|
|
/* mmdrop drops the mm and the page tables */
|
|
extern void __mmdrop(struct mm_struct *);
|
|
-static inline void mmdrop(struct mm_struct * mm)
|
|
+static inline void mmdrop(struct mm_struct *mm)
|
|
{
|
|
if (unlikely(atomic_dec_and_test(&mm->mm_count)))
|
|
__mmdrop(mm);
|
|
}
|
|
|
|
+static inline bool mmget_not_zero(struct mm_struct *mm)
|
|
+{
|
|
+ return atomic_inc_not_zero(&mm->mm_users);
|
|
+}
|
|
+
|
|
/* mmput gets rid of the mappings and all user-space */
|
|
extern void mmput(struct mm_struct *);
|
|
/* Grab a reference to a task's mm, if it is not already going away */
|
|
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
|
|
index 502787c29ce9..a2f12d377d23 100644
|
|
--- a/include/linux/skbuff.h
|
|
+++ b/include/linux/skbuff.h
|
|
@@ -3664,5 +3664,35 @@ static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
|
|
return hdr_len + skb_gso_transport_seglen(skb);
|
|
}
|
|
|
|
+/**
|
|
+ * skb_gso_mac_seglen - Return length of individual segments of a gso packet
|
|
+ *
|
|
+ * @skb: GSO skb
|
|
+ *
|
|
+ * skb_gso_mac_seglen is used to determine the real size of the
|
|
+ * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4
|
|
+ * headers (TCP/UDP).
|
|
+ */
|
|
+static inline unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
|
|
+{
|
|
+ unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
|
|
+ return hdr_len + skb_gso_transport_seglen(skb);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * skb_gso_validate_mac_len - Will a split GSO skb fit in a given length?
|
|
+ *
|
|
+ * @skb: GSO skb
|
|
+ * @len: length to validate against
|
|
+ *
|
|
+ * skb_gso_validate_mac_len validates if a given skb will fit a wanted
|
|
+ * length once split, including L2, L3 and L4 headers and the payload.
|
|
+ */
|
|
+static inline bool
|
|
+skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len)
|
|
+{
|
|
+ return skb_gso_mac_seglen(skb) <= len;
|
|
+}
|
|
+
|
|
#endif /* __KERNEL__ */
|
|
#endif /* _LINUX_SKBUFF_H */
|
|
diff --git a/include/linux/smpboot.h b/include/linux/smpboot.h
|
|
index 12910cf19869..12a4b09f4d08 100644
|
|
--- a/include/linux/smpboot.h
|
|
+++ b/include/linux/smpboot.h
|
|
@@ -30,7 +30,7 @@ struct smpboot_thread_data;
|
|
* @thread_comm: The base name of the thread
|
|
*/
|
|
struct smp_hotplug_thread {
|
|
- struct task_struct __percpu **store;
|
|
+ struct task_struct * __percpu *store;
|
|
struct list_head list;
|
|
int (*thread_should_run)(unsigned int cpu);
|
|
void (*thread_fn)(unsigned int cpu);
|
|
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
|
|
index 7e84aac39ade..667e7f9fd877 100644
|
|
--- a/include/linux/usb/gadget.h
|
|
+++ b/include/linux/usb/gadget.h
|
|
@@ -671,7 +671,9 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev)
|
|
*/
|
|
static inline size_t usb_ep_align(struct usb_ep *ep, size_t len)
|
|
{
|
|
- return round_up(len, (size_t)le16_to_cpu(ep->desc->wMaxPacketSize));
|
|
+ int max_packet_size = (size_t)usb_endpoint_maxp(ep->desc) & 0x7ff;
|
|
+
|
|
+ return round_up(len, max_packet_size);
|
|
}
|
|
|
|
/**
|
|
diff --git a/include/net/arp.h b/include/net/arp.h
|
|
index 1b3f86981757..92d2f7d7d1cb 100644
|
|
--- a/include/net/arp.h
|
|
+++ b/include/net/arp.h
|
|
@@ -17,6 +17,7 @@ static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32
|
|
return val * hash_rnd[0];
|
|
}
|
|
|
|
+#ifdef CONFIG_INET
|
|
static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)
|
|
{
|
|
if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
|
|
@@ -24,6 +25,13 @@ static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev
|
|
|
|
return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev);
|
|
}
|
|
+#else
|
|
+static inline
|
|
+struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
+#endif
|
|
|
|
static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key)
|
|
{
|
|
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
|
|
index c9aca042e61d..d3a5cf3b5446 100644
|
|
--- a/include/uapi/linux/fuse.h
|
|
+++ b/include/uapi/linux/fuse.h
|
|
@@ -205,10 +205,12 @@ struct fuse_file_lock {
|
|
* FOPEN_DIRECT_IO: bypass page cache for this open file
|
|
* FOPEN_KEEP_CACHE: don't invalidate the data cache on open
|
|
* FOPEN_NONSEEKABLE: the file is not seekable
|
|
+ * FOPEN_STREAM: the file is stream-like (no file position at all)
|
|
*/
|
|
#define FOPEN_DIRECT_IO (1 << 0)
|
|
#define FOPEN_KEEP_CACHE (1 << 1)
|
|
#define FOPEN_NONSEEKABLE (1 << 2)
|
|
+#define FOPEN_STREAM (1 << 4)
|
|
|
|
/**
|
|
* INIT request/reply flags
|
|
diff --git a/include/uapi/linux/tipc_config.h b/include/uapi/linux/tipc_config.h
|
|
index 087b0ef82c07..bbebd258cf07 100644
|
|
--- a/include/uapi/linux/tipc_config.h
|
|
+++ b/include/uapi/linux/tipc_config.h
|
|
@@ -301,8 +301,10 @@ static inline int TLV_SET(void *tlv, __u16 type, void *data, __u16 len)
|
|
tlv_ptr = (struct tlv_desc *)tlv;
|
|
tlv_ptr->tlv_type = htons(type);
|
|
tlv_ptr->tlv_len = htons(tlv_len);
|
|
- if (len && data)
|
|
- memcpy(TLV_DATA(tlv_ptr), data, tlv_len);
|
|
+ if (len && data) {
|
|
+ memcpy(TLV_DATA(tlv_ptr), data, len);
|
|
+ memset(TLV_DATA(tlv_ptr) + len, 0, TLV_SPACE(len) - tlv_len);
|
|
+ }
|
|
return TLV_SPACE(len);
|
|
}
|
|
|
|
@@ -399,8 +401,10 @@ static inline int TCM_SET(void *msg, __u16 cmd, __u16 flags,
|
|
tcm_hdr->tcm_len = htonl(msg_len);
|
|
tcm_hdr->tcm_type = htons(cmd);
|
|
tcm_hdr->tcm_flags = htons(flags);
|
|
- if (data_len && data)
|
|
+ if (data_len && data) {
|
|
memcpy(TCM_DATA(msg), data, data_len);
|
|
+ memset(TCM_DATA(msg) + data_len, 0, TCM_SPACE(data_len) - msg_len);
|
|
+ }
|
|
return TCM_SPACE(data_len);
|
|
}
|
|
|
|
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
|
|
index b57f929f1b46..cf7aa656b308 100644
|
|
--- a/kernel/auditfilter.c
|
|
+++ b/kernel/auditfilter.c
|
|
@@ -1095,22 +1095,24 @@ int audit_rule_change(int type, __u32 portid, int seq, void *data,
|
|
int err = 0;
|
|
struct audit_entry *entry;
|
|
|
|
- entry = audit_data_to_entry(data, datasz);
|
|
- if (IS_ERR(entry))
|
|
- return PTR_ERR(entry);
|
|
-
|
|
switch (type) {
|
|
case AUDIT_ADD_RULE:
|
|
+ entry = audit_data_to_entry(data, datasz);
|
|
+ if (IS_ERR(entry))
|
|
+ return PTR_ERR(entry);
|
|
err = audit_add_rule(entry);
|
|
audit_log_rule_change("add_rule", &entry->rule, !err);
|
|
break;
|
|
case AUDIT_DEL_RULE:
|
|
+ entry = audit_data_to_entry(data, datasz);
|
|
+ if (IS_ERR(entry))
|
|
+ return PTR_ERR(entry);
|
|
err = audit_del_rule(entry);
|
|
audit_log_rule_change("remove_rule", &entry->rule, !err);
|
|
break;
|
|
default:
|
|
- err = -EINVAL;
|
|
WARN_ON(1);
|
|
+ return -EINVAL;
|
|
}
|
|
|
|
if (err || type == AUDIT_DEL_RULE) {
|
|
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
|
|
index d89328e260df..041a02b334d7 100644
|
|
--- a/kernel/rcu/rcutorture.c
|
|
+++ b/kernel/rcu/rcutorture.c
|
|
@@ -1603,6 +1603,10 @@ rcu_torture_cleanup(void)
|
|
cur_ops->cb_barrier();
|
|
return;
|
|
}
|
|
+ if (!cur_ops) {
|
|
+ torture_cleanup_end();
|
|
+ return;
|
|
+ }
|
|
|
|
rcu_torture_barrier_cleanup();
|
|
torture_stop_kthread(rcu_torture_stall, stall_task);
|
|
@@ -1741,6 +1745,7 @@ rcu_torture_init(void)
|
|
pr_alert(" %s", torture_ops[i]->name);
|
|
pr_alert("\n");
|
|
firsterr = -EINVAL;
|
|
+ cur_ops = NULL;
|
|
goto unwind;
|
|
}
|
|
if (cur_ops->fqs == NULL && fqs_duration != 0) {
|
|
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
|
|
index d35a7d528ea6..0e70bfeded7f 100644
|
|
--- a/kernel/sched/core.c
|
|
+++ b/kernel/sched/core.c
|
|
@@ -8361,6 +8361,8 @@ static void cpu_cgroup_attach(struct cgroup_taskset *tset)
|
|
static int cpu_shares_write_u64(struct cgroup_subsys_state *css,
|
|
struct cftype *cftype, u64 shareval)
|
|
{
|
|
+ if (shareval > scale_load_down(ULONG_MAX))
|
|
+ shareval = MAX_SHARES;
|
|
return sched_group_set_shares(css_tg(css), scale_load(shareval));
|
|
}
|
|
|
|
@@ -8460,8 +8462,10 @@ int tg_set_cfs_quota(struct task_group *tg, long cfs_quota_us)
|
|
period = ktime_to_ns(tg->cfs_bandwidth.period);
|
|
if (cfs_quota_us < 0)
|
|
quota = RUNTIME_INF;
|
|
- else
|
|
+ else if ((u64)cfs_quota_us <= U64_MAX / NSEC_PER_USEC)
|
|
quota = (u64)cfs_quota_us * NSEC_PER_USEC;
|
|
+ else
|
|
+ return -EINVAL;
|
|
|
|
return tg_set_cfs_bandwidth(tg, period, quota);
|
|
}
|
|
@@ -8483,6 +8487,9 @@ int tg_set_cfs_period(struct task_group *tg, long cfs_period_us)
|
|
{
|
|
u64 quota, period;
|
|
|
|
+ if ((u64)cfs_period_us > U64_MAX / NSEC_PER_USEC)
|
|
+ return -EINVAL;
|
|
+
|
|
period = (u64)cfs_period_us * NSEC_PER_USEC;
|
|
quota = tg->cfs_bandwidth.quota;
|
|
|
|
diff --git a/kernel/signal.c b/kernel/signal.c
|
|
index 96e8c3cbfa38..072fd152ab01 100644
|
|
--- a/kernel/signal.c
|
|
+++ b/kernel/signal.c
|
|
@@ -2244,6 +2244,8 @@ relock:
|
|
if (signal_group_exit(signal)) {
|
|
ksig->info.si_signo = signr = SIGKILL;
|
|
sigdelset(¤t->pending.signal, SIGKILL);
|
|
+ trace_signal_deliver(SIGKILL, SEND_SIG_NOINFO,
|
|
+ &sighand->action[SIGKILL - 1]);
|
|
recalc_sigpending();
|
|
goto fatal;
|
|
}
|
|
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
|
|
index ba5392807912..bd4c0bb61ad7 100644
|
|
--- a/kernel/trace/trace_events.c
|
|
+++ b/kernel/trace/trace_events.c
|
|
@@ -1288,9 +1288,6 @@ event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
|
|
char buf[32];
|
|
int len;
|
|
|
|
- if (*ppos)
|
|
- return 0;
|
|
-
|
|
if (unlikely(!id))
|
|
return -ENODEV;
|
|
|
|
diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c
|
|
index e0af6ff73d14..f8b1e3cb716b 100644
|
|
--- a/lib/strncpy_from_user.c
|
|
+++ b/lib/strncpy_from_user.c
|
|
@@ -20,10 +20,11 @@
|
|
* hit it), 'max' is the address space maximum (and we return
|
|
* -EFAULT if we hit it).
|
|
*/
|
|
-static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
|
|
+static inline long do_strncpy_from_user(char *dst, const char __user *src,
|
|
+ unsigned long count, unsigned long max)
|
|
{
|
|
const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
|
|
- long res = 0;
|
|
+ unsigned long res = 0;
|
|
|
|
/*
|
|
* Truncate 'max' to the user-specified limit, so that
|
|
diff --git a/lib/strnlen_user.c b/lib/strnlen_user.c
|
|
index 3a5f2b366d84..1c87bfa63db7 100644
|
|
--- a/lib/strnlen_user.c
|
|
+++ b/lib/strnlen_user.c
|
|
@@ -27,7 +27,7 @@
|
|
static inline long do_strnlen_user(const char __user *src, unsigned long count, unsigned long max)
|
|
{
|
|
const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
|
|
- long align, res = 0;
|
|
+ unsigned long align, res = 0;
|
|
unsigned long c;
|
|
|
|
/*
|
|
@@ -41,7 +41,7 @@ static inline long do_strnlen_user(const char __user *src, unsigned long count,
|
|
* Do everything aligned. But that means that we
|
|
* need to also expand the maximum..
|
|
*/
|
|
- align = (sizeof(long) - 1) & (unsigned long)src;
|
|
+ align = (sizeof(unsigned long) - 1) & (unsigned long)src;
|
|
src -= align;
|
|
max += align;
|
|
|
|
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
|
|
index 7f80b1a1bc34..07e3b3b8e846 100644
|
|
--- a/mm/backing-dev.c
|
|
+++ b/mm/backing-dev.c
|
|
@@ -669,6 +669,7 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi)
|
|
INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC);
|
|
bdi->cgwb_congested_tree = RB_ROOT;
|
|
atomic_set(&bdi->usage_cnt, 1);
|
|
+ init_rwsem(&bdi->wb_switch_rwsem);
|
|
|
|
ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
|
|
if (!ret) {
|
|
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
|
|
index 324b2953e57e..d7f65a8c629b 100644
|
|
--- a/mm/hugetlb.c
|
|
+++ b/mm/hugetlb.c
|
|
@@ -3703,21 +3703,14 @@ backout_unlocked:
|
|
}
|
|
|
|
#ifdef CONFIG_SMP
|
|
-u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
|
|
- struct vm_area_struct *vma,
|
|
- struct address_space *mapping,
|
|
+u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
|
|
pgoff_t idx, unsigned long address)
|
|
{
|
|
unsigned long key[2];
|
|
u32 hash;
|
|
|
|
- if (vma->vm_flags & VM_SHARED) {
|
|
- key[0] = (unsigned long) mapping;
|
|
- key[1] = idx;
|
|
- } else {
|
|
- key[0] = (unsigned long) mm;
|
|
- key[1] = address >> huge_page_shift(h);
|
|
- }
|
|
+ key[0] = (unsigned long) mapping;
|
|
+ key[1] = idx;
|
|
|
|
hash = jhash2((u32 *)&key, sizeof(key)/sizeof(u32), 0);
|
|
|
|
@@ -3728,9 +3721,7 @@ u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
|
|
* For uniprocesor systems we always use a single mutex, so just
|
|
* return 0 and avoid the hashing overhead.
|
|
*/
|
|
-u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
|
|
- struct vm_area_struct *vma,
|
|
- struct address_space *mapping,
|
|
+u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
|
|
pgoff_t idx, unsigned long address)
|
|
{
|
|
return 0;
|
|
@@ -3776,7 +3767,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
* get spurious allocation failures if two CPUs race to instantiate
|
|
* the same page in the page cache.
|
|
*/
|
|
- hash = hugetlb_fault_mutex_hash(h, mm, vma, mapping, idx, address);
|
|
+ hash = hugetlb_fault_mutex_hash(h, mapping, idx, address);
|
|
mutex_lock(&hugetlb_fault_mutex_table[hash]);
|
|
|
|
entry = huge_ptep_get(ptep);
|
|
diff --git a/mm/list_lru.c b/mm/list_lru.c
|
|
index 786176b1a0ee..732a066e3d3a 100644
|
|
--- a/mm/list_lru.c
|
|
+++ b/mm/list_lru.c
|
|
@@ -42,11 +42,7 @@ static void list_lru_unregister(struct list_lru *lru)
|
|
#ifdef CONFIG_MEMCG_KMEM
|
|
static inline bool list_lru_memcg_aware(struct list_lru *lru)
|
|
{
|
|
- /*
|
|
- * This needs node 0 to be always present, even
|
|
- * in the systems supporting sparse numa ids.
|
|
- */
|
|
- return !!lru->node[0].memcg_lrus;
|
|
+ return lru->memcg_aware;
|
|
}
|
|
|
|
static inline struct list_lru_one *
|
|
@@ -389,6 +385,8 @@ static int memcg_init_list_lru(struct list_lru *lru, bool memcg_aware)
|
|
{
|
|
int i;
|
|
|
|
+ lru->memcg_aware = memcg_aware;
|
|
+
|
|
if (!memcg_aware)
|
|
return 0;
|
|
|
|
diff --git a/mm/mincore.c b/mm/mincore.c
|
|
index 14bb9fb37f0c..9700c2303941 100644
|
|
--- a/mm/mincore.c
|
|
+++ b/mm/mincore.c
|
|
@@ -165,6 +165,22 @@ out:
|
|
return 0;
|
|
}
|
|
|
|
+static inline bool can_do_mincore(struct vm_area_struct *vma)
|
|
+{
|
|
+ if (vma_is_anonymous(vma))
|
|
+ return true;
|
|
+ if (!vma->vm_file)
|
|
+ return false;
|
|
+ /*
|
|
+ * Reveal pagecache information only for non-anonymous mappings that
|
|
+ * correspond to the files the calling process could (if tried) open
|
|
+ * for writing; otherwise we'd be including shared non-exclusive
|
|
+ * mappings, which opens a side channel.
|
|
+ */
|
|
+ return inode_owner_or_capable(file_inode(vma->vm_file)) ||
|
|
+ inode_permission(file_inode(vma->vm_file), MAY_WRITE) == 0;
|
|
+}
|
|
+
|
|
/*
|
|
* Do a chunk of "sys_mincore()". We've already checked
|
|
* all the arguments, we hold the mmap semaphore: we should
|
|
@@ -185,8 +201,13 @@ static long do_mincore(unsigned long addr, unsigned long pages, unsigned char *v
|
|
vma = find_vma(current->mm, addr);
|
|
if (!vma || addr < vma->vm_start)
|
|
return -ENOMEM;
|
|
- mincore_walk.mm = vma->vm_mm;
|
|
end = min(vma->vm_end, addr + (pages << PAGE_SHIFT));
|
|
+ if (!can_do_mincore(vma)) {
|
|
+ unsigned long pages = DIV_ROUND_UP(end - addr, PAGE_SIZE);
|
|
+ memset(vec, 1, pages);
|
|
+ return pages;
|
|
+ }
|
|
+ mincore_walk.mm = vma->vm_mm;
|
|
err = walk_page_range(addr, end, &mincore_walk);
|
|
if (err < 0)
|
|
return err;
|
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
|
index 49f78bce5795..db5345f5f7b0 100644
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -4550,7 +4550,6 @@ static struct sk_buff *napi_frags_skb(struct napi_struct *napi)
|
|
skb_reset_mac_header(skb);
|
|
skb_gro_reset_offset(skb);
|
|
|
|
- eth = skb_gro_header_fast(skb, 0);
|
|
if (unlikely(skb_gro_header_hard(skb, hlen))) {
|
|
eth = skb_gro_header_slow(skb, hlen, 0);
|
|
if (unlikely(!eth)) {
|
|
@@ -4558,6 +4557,7 @@ static struct sk_buff *napi_frags_skb(struct napi_struct *napi)
|
|
return NULL;
|
|
}
|
|
} else {
|
|
+ eth = (const struct ethhdr *)skb->data;
|
|
gro_pull_from_frag0(skb, hlen);
|
|
NAPI_GRO_CB(skb)->frag0 += hlen;
|
|
NAPI_GRO_CB(skb)->frag0_len -= hlen;
|
|
@@ -6986,7 +6986,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
|
|
|
|
refcnt = netdev_refcnt_read(dev);
|
|
|
|
- if (time_after(jiffies, warning_time + 10 * HZ)) {
|
|
+ if (refcnt && time_after(jiffies, warning_time + 10 * HZ)) {
|
|
pr_emerg("unregister_netdevice: waiting for %s to become free. Usage count = %d\n",
|
|
dev->name, refcnt);
|
|
warning_time = jiffies;
|
|
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
|
|
index 9a53c66deb64..66428c0eb663 100644
|
|
--- a/net/core/ethtool.c
|
|
+++ b/net/core/ethtool.c
|
|
@@ -428,8 +428,13 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
|
|
if (rc >= 0)
|
|
info.n_priv_flags = rc;
|
|
}
|
|
- if (ops->get_regs_len)
|
|
- info.regdump_len = ops->get_regs_len(dev);
|
|
+ if (ops->get_regs_len) {
|
|
+ int ret = ops->get_regs_len(dev);
|
|
+
|
|
+ if (ret > 0)
|
|
+ info.regdump_len = ret;
|
|
+ }
|
|
+
|
|
if (ops->get_eeprom_len)
|
|
info.eedump_len = ops->get_eeprom_len(dev);
|
|
|
|
@@ -883,6 +888,9 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
|
|
return -EFAULT;
|
|
|
|
reglen = ops->get_regs_len(dev);
|
|
+ if (reglen <= 0)
|
|
+ return reglen;
|
|
+
|
|
if (regs.len > reglen)
|
|
regs.len = reglen;
|
|
|
|
@@ -893,13 +901,16 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
+ if (regs.len < reglen)
|
|
+ reglen = regs.len;
|
|
+
|
|
ops->get_regs(dev, ®s, regbuf);
|
|
|
|
ret = -EFAULT;
|
|
if (copy_to_user(useraddr, ®s, sizeof(regs)))
|
|
goto out;
|
|
useraddr += offsetof(struct ethtool_regs, data);
|
|
- if (regbuf && copy_to_user(useraddr, regbuf, regs.len))
|
|
+ if (copy_to_user(useraddr, regbuf, reglen))
|
|
goto out;
|
|
ret = 0;
|
|
|
|
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
|
|
index 78dc184072e8..9d812ba38ff2 100644
|
|
--- a/net/core/neighbour.c
|
|
+++ b/net/core/neighbour.c
|
|
@@ -30,6 +30,7 @@
|
|
#include <linux/times.h>
|
|
#include <net/net_namespace.h>
|
|
#include <net/neighbour.h>
|
|
+#include <net/arp.h>
|
|
#include <net/dst.h>
|
|
#include <net/sock.h>
|
|
#include <net/netevent.h>
|
|
@@ -2490,7 +2491,13 @@ int neigh_xmit(int index, struct net_device *dev,
|
|
if (!tbl)
|
|
goto out;
|
|
rcu_read_lock_bh();
|
|
- neigh = __neigh_lookup_noref(tbl, addr, dev);
|
|
+ if (index == NEIGH_ARP_TABLE) {
|
|
+ u32 key = *((u32 *)addr);
|
|
+
|
|
+ neigh = __ipv4_neigh_lookup_noref(dev, key);
|
|
+ } else {
|
|
+ neigh = __neigh_lookup_noref(tbl, addr, dev);
|
|
+ }
|
|
if (!neigh)
|
|
neigh = __neigh_create(tbl, addr, dev, false);
|
|
err = PTR_ERR(neigh);
|
|
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
|
|
index b6327601f979..4ea957c1e7ee 100644
|
|
--- a/net/core/pktgen.c
|
|
+++ b/net/core/pktgen.c
|
|
@@ -3139,7 +3139,13 @@ static int pktgen_wait_thread_run(struct pktgen_thread *t)
|
|
{
|
|
while (thread_is_running(t)) {
|
|
|
|
+ /* note: 't' will still be around even after the unlock/lock
|
|
+ * cycle because pktgen_thread threads are only cleared at
|
|
+ * net exit
|
|
+ */
|
|
+ mutex_unlock(&pktgen_thread_lock);
|
|
msleep_interruptible(100);
|
|
+ mutex_lock(&pktgen_thread_lock);
|
|
|
|
if (signal_pending(current))
|
|
goto signal;
|
|
@@ -3154,6 +3160,10 @@ static int pktgen_wait_all_threads_run(struct pktgen_net *pn)
|
|
struct pktgen_thread *t;
|
|
int sig = 1;
|
|
|
|
+ /* prevent from racing with rmmod */
|
|
+ if (!try_module_get(THIS_MODULE))
|
|
+ return sig;
|
|
+
|
|
mutex_lock(&pktgen_thread_lock);
|
|
|
|
list_for_each_entry(t, &pn->pktgen_threads, th_list) {
|
|
@@ -3167,6 +3177,7 @@ static int pktgen_wait_all_threads_run(struct pktgen_net *pn)
|
|
t->control |= (T_STOP);
|
|
|
|
mutex_unlock(&pktgen_thread_lock);
|
|
+ module_put(THIS_MODULE);
|
|
return sig;
|
|
}
|
|
|
|
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
|
|
index fcf327ebd134..bbcbbc1cc2cc 100644
|
|
--- a/net/ipv4/ip_vti.c
|
|
+++ b/net/ipv4/ip_vti.c
|
|
@@ -648,9 +648,9 @@ static int __init vti_init(void)
|
|
return err;
|
|
|
|
rtnl_link_failed:
|
|
- xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP);
|
|
-xfrm_tunnel_failed:
|
|
xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
|
|
+xfrm_tunnel_failed:
|
|
+ xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP);
|
|
xfrm_proto_comp_failed:
|
|
xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH);
|
|
xfrm_proto_ah_failed:
|
|
@@ -666,6 +666,7 @@ pernet_dev_failed:
|
|
static void __exit vti_fini(void)
|
|
{
|
|
rtnl_link_unregister(&vti_link_ops);
|
|
+ xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
|
|
xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP);
|
|
xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH);
|
|
xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP);
|
|
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
|
|
index fddae0164b91..d9758ecdcba6 100644
|
|
--- a/net/ipv4/xfrm4_policy.c
|
|
+++ b/net/ipv4/xfrm4_policy.c
|
|
@@ -108,7 +108,8 @@ static void
|
|
_decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
|
|
{
|
|
const struct iphdr *iph = ip_hdr(skb);
|
|
- u8 *xprth = skb_network_header(skb) + iph->ihl * 4;
|
|
+ int ihl = iph->ihl;
|
|
+ u8 *xprth = skb_network_header(skb) + ihl * 4;
|
|
struct flowi4 *fl4 = &fl->u.ip4;
|
|
int oif = 0;
|
|
|
|
@@ -119,6 +120,11 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
|
|
fl4->flowi4_mark = skb->mark;
|
|
fl4->flowi4_oif = reverse ? skb->skb_iif : oif;
|
|
|
|
+ fl4->flowi4_proto = iph->protocol;
|
|
+ fl4->daddr = reverse ? iph->saddr : iph->daddr;
|
|
+ fl4->saddr = reverse ? iph->daddr : iph->saddr;
|
|
+ fl4->flowi4_tos = iph->tos;
|
|
+
|
|
if (!ip_is_fragment(iph)) {
|
|
switch (iph->protocol) {
|
|
case IPPROTO_UDP:
|
|
@@ -130,7 +136,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
|
|
pskb_may_pull(skb, xprth + 4 - skb->data)) {
|
|
__be16 *ports;
|
|
|
|
- xprth = skb_network_header(skb) + iph->ihl * 4;
|
|
+ xprth = skb_network_header(skb) + ihl * 4;
|
|
ports = (__be16 *)xprth;
|
|
|
|
fl4->fl4_sport = ports[!!reverse];
|
|
@@ -143,7 +149,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
|
|
pskb_may_pull(skb, xprth + 2 - skb->data)) {
|
|
u8 *icmp;
|
|
|
|
- xprth = skb_network_header(skb) + iph->ihl * 4;
|
|
+ xprth = skb_network_header(skb) + ihl * 4;
|
|
icmp = xprth;
|
|
|
|
fl4->fl4_icmp_type = icmp[0];
|
|
@@ -156,7 +162,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
|
|
pskb_may_pull(skb, xprth + 4 - skb->data)) {
|
|
__be32 *ehdr;
|
|
|
|
- xprth = skb_network_header(skb) + iph->ihl * 4;
|
|
+ xprth = skb_network_header(skb) + ihl * 4;
|
|
ehdr = (__be32 *)xprth;
|
|
|
|
fl4->fl4_ipsec_spi = ehdr[0];
|
|
@@ -168,7 +174,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
|
|
pskb_may_pull(skb, xprth + 8 - skb->data)) {
|
|
__be32 *ah_hdr;
|
|
|
|
- xprth = skb_network_header(skb) + iph->ihl * 4;
|
|
+ xprth = skb_network_header(skb) + ihl * 4;
|
|
ah_hdr = (__be32 *)xprth;
|
|
|
|
fl4->fl4_ipsec_spi = ah_hdr[1];
|
|
@@ -180,7 +186,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
|
|
pskb_may_pull(skb, xprth + 4 - skb->data)) {
|
|
__be16 *ipcomp_hdr;
|
|
|
|
- xprth = skb_network_header(skb) + iph->ihl * 4;
|
|
+ xprth = skb_network_header(skb) + ihl * 4;
|
|
ipcomp_hdr = (__be16 *)xprth;
|
|
|
|
fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1]));
|
|
@@ -193,7 +199,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
|
|
__be16 *greflags;
|
|
__be32 *gre_hdr;
|
|
|
|
- xprth = skb_network_header(skb) + iph->ihl * 4;
|
|
+ xprth = skb_network_header(skb) + ihl * 4;
|
|
greflags = (__be16 *)xprth;
|
|
gre_hdr = (__be32 *)xprth;
|
|
|
|
@@ -210,10 +216,6 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
|
|
break;
|
|
}
|
|
}
|
|
- fl4->flowi4_proto = iph->protocol;
|
|
- fl4->daddr = reverse ? iph->saddr : iph->daddr;
|
|
- fl4->saddr = reverse ? iph->daddr : iph->saddr;
|
|
- fl4->flowi4_tos = iph->tos;
|
|
}
|
|
|
|
static inline int xfrm4_garbage_collect(struct dst_ops *ops)
|
|
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
|
|
index 4d52a0e2f60d..55953c5804c3 100644
|
|
--- a/net/ipv6/raw.c
|
|
+++ b/net/ipv6/raw.c
|
|
@@ -283,7 +283,9 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|
/* Binding to link-local address requires an interface */
|
|
if (!sk->sk_bound_dev_if)
|
|
goto out_unlock;
|
|
+ }
|
|
|
|
+ if (sk->sk_bound_dev_if) {
|
|
err = -ENODEV;
|
|
dev = dev_get_by_index_rcu(sock_net(sk),
|
|
sk->sk_bound_dev_if);
|
|
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
|
|
index 56b72cada346..f9d493c59d6c 100644
|
|
--- a/net/ipv6/xfrm6_tunnel.c
|
|
+++ b/net/ipv6/xfrm6_tunnel.c
|
|
@@ -391,6 +391,10 @@ static void __exit xfrm6_tunnel_fini(void)
|
|
xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
|
|
xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
|
|
unregister_pernet_subsys(&xfrm6_tunnel_net_ops);
|
|
+ /* Someone maybe has gotten the xfrm6_tunnel_spi.
|
|
+ * So need to wait it.
|
|
+ */
|
|
+ rcu_barrier();
|
|
kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
|
|
}
|
|
|
|
diff --git a/net/llc/llc_output.c b/net/llc/llc_output.c
|
|
index 94425e421213..9e4b6bcf6920 100644
|
|
--- a/net/llc/llc_output.c
|
|
+++ b/net/llc/llc_output.c
|
|
@@ -72,6 +72,8 @@ int llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
|
|
rc = llc_mac_hdr_init(skb, skb->dev->dev_addr, dmac);
|
|
if (likely(!rc))
|
|
rc = dev_queue_xmit(skb);
|
|
+ else
|
|
+ kfree_skb(skb);
|
|
return rc;
|
|
}
|
|
|
|
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
|
|
index ed4fef32b394..08384dbf426c 100644
|
|
--- a/net/mac80211/mlme.c
|
|
+++ b/net/mac80211/mlme.c
|
|
@@ -1104,9 +1104,6 @@ static void ieee80211_chswitch_work(struct work_struct *work)
|
|
goto out;
|
|
}
|
|
|
|
- /* XXX: shouldn't really modify cfg80211-owned data! */
|
|
- ifmgd->associated->channel = sdata->csa_chandef.chan;
|
|
-
|
|
ifmgd->csa_waiting_bcn = true;
|
|
|
|
ieee80211_sta_reset_beacon_monitor(sdata);
|
|
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
|
|
index a2340748ec86..d7888924166e 100644
|
|
--- a/net/rds/ib_rdma.c
|
|
+++ b/net/rds/ib_rdma.c
|
|
@@ -725,12 +725,14 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
|
|
wait_clean_list_grace();
|
|
|
|
list_to_llist_nodes(pool, &unmap_list, &clean_nodes, &clean_tail);
|
|
- if (ibmr_ret)
|
|
+ if (ibmr_ret) {
|
|
*ibmr_ret = llist_entry(clean_nodes, struct rds_ib_mr, llnode);
|
|
-
|
|
+ clean_nodes = clean_nodes->next;
|
|
+ }
|
|
/* more than one entry in llist nodes */
|
|
- if (clean_nodes->next)
|
|
- llist_add_batch(clean_nodes->next, clean_tail, &pool->clean_list);
|
|
+ if (clean_nodes)
|
|
+ llist_add_batch(clean_nodes, clean_tail,
|
|
+ &pool->clean_list);
|
|
|
|
}
|
|
|
|
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
|
|
index a06c9d6bfc9c..05c7a66f64da 100644
|
|
--- a/net/sched/sch_tbf.c
|
|
+++ b/net/sched/sch_tbf.c
|
|
@@ -142,16 +142,6 @@ static u64 psched_ns_t2l(const struct psched_ratecfg *r,
|
|
return len;
|
|
}
|
|
|
|
-/*
|
|
- * Return length of individual segments of a gso packet,
|
|
- * including all headers (MAC, IP, TCP/UDP)
|
|
- */
|
|
-static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
|
|
-{
|
|
- unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
|
|
- return hdr_len + skb_gso_transport_seglen(skb);
|
|
-}
|
|
-
|
|
/* GSO packet is too big, segment it so that tbf can transmit
|
|
* each segment in time
|
|
*/
|
|
diff --git a/net/tipc/core.c b/net/tipc/core.c
|
|
index e2bdb07a49a2..c306e9bc1621 100644
|
|
--- a/net/tipc/core.c
|
|
+++ b/net/tipc/core.c
|
|
@@ -70,9 +70,6 @@ static int __net_init tipc_init_net(struct net *net)
|
|
goto out_nametbl;
|
|
|
|
INIT_LIST_HEAD(&tn->dist_queue);
|
|
- err = tipc_topsrv_start(net);
|
|
- if (err)
|
|
- goto out_subscr;
|
|
|
|
err = tipc_bcast_init(net);
|
|
if (err)
|
|
@@ -81,8 +78,6 @@ static int __net_init tipc_init_net(struct net *net)
|
|
return 0;
|
|
|
|
out_bclink:
|
|
- tipc_bcast_stop(net);
|
|
-out_subscr:
|
|
tipc_nametbl_stop(net);
|
|
out_nametbl:
|
|
tipc_sk_rht_destroy(net);
|
|
@@ -92,7 +87,6 @@ out_sk_rht:
|
|
|
|
static void __net_exit tipc_exit_net(struct net *net)
|
|
{
|
|
- tipc_topsrv_stop(net);
|
|
tipc_net_stop(net);
|
|
tipc_bcast_stop(net);
|
|
tipc_nametbl_stop(net);
|
|
@@ -106,6 +100,11 @@ static struct pernet_operations tipc_net_ops = {
|
|
.size = sizeof(struct tipc_net),
|
|
};
|
|
|
|
+static struct pernet_operations tipc_topsrv_net_ops = {
|
|
+ .init = tipc_topsrv_init_net,
|
|
+ .exit = tipc_topsrv_exit_net,
|
|
+};
|
|
+
|
|
static int __init tipc_init(void)
|
|
{
|
|
int err;
|
|
@@ -126,10 +125,6 @@ static int __init tipc_init(void)
|
|
if (err)
|
|
goto out_netlink_compat;
|
|
|
|
- err = tipc_socket_init();
|
|
- if (err)
|
|
- goto out_socket;
|
|
-
|
|
err = tipc_register_sysctl();
|
|
if (err)
|
|
goto out_sysctl;
|
|
@@ -138,6 +133,14 @@ static int __init tipc_init(void)
|
|
if (err)
|
|
goto out_pernet;
|
|
|
|
+ err = tipc_socket_init();
|
|
+ if (err)
|
|
+ goto out_socket;
|
|
+
|
|
+ err = register_pernet_subsys(&tipc_topsrv_net_ops);
|
|
+ if (err)
|
|
+ goto out_pernet_topsrv;
|
|
+
|
|
err = tipc_bearer_setup();
|
|
if (err)
|
|
goto out_bearer;
|
|
@@ -145,12 +148,14 @@ static int __init tipc_init(void)
|
|
pr_info("Started in single node mode\n");
|
|
return 0;
|
|
out_bearer:
|
|
+ unregister_pernet_subsys(&tipc_topsrv_net_ops);
|
|
+out_pernet_topsrv:
|
|
+ tipc_socket_stop();
|
|
+out_socket:
|
|
unregister_pernet_subsys(&tipc_net_ops);
|
|
out_pernet:
|
|
tipc_unregister_sysctl();
|
|
out_sysctl:
|
|
- tipc_socket_stop();
|
|
-out_socket:
|
|
tipc_netlink_compat_stop();
|
|
out_netlink_compat:
|
|
tipc_netlink_stop();
|
|
@@ -162,10 +167,11 @@ out_netlink:
|
|
static void __exit tipc_exit(void)
|
|
{
|
|
tipc_bearer_cleanup();
|
|
+ unregister_pernet_subsys(&tipc_topsrv_net_ops);
|
|
+ tipc_socket_stop();
|
|
unregister_pernet_subsys(&tipc_net_ops);
|
|
tipc_netlink_stop();
|
|
tipc_netlink_compat_stop();
|
|
- tipc_socket_stop();
|
|
tipc_unregister_sysctl();
|
|
|
|
pr_info("Deactivated\n");
|
|
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
|
|
index 500c9e614a06..4f80f00cd8f9 100644
|
|
--- a/net/tipc/subscr.c
|
|
+++ b/net/tipc/subscr.c
|
|
@@ -306,7 +306,7 @@ static void *tipc_subscrb_connect_cb(int conid)
|
|
return (void *)tipc_subscrb_create(conid);
|
|
}
|
|
|
|
-int tipc_topsrv_start(struct net *net)
|
|
+static int tipc_topsrv_start(struct net *net)
|
|
{
|
|
struct tipc_net *tn = net_generic(net, tipc_net_id);
|
|
const char name[] = "topology_server";
|
|
@@ -344,7 +344,7 @@ int tipc_topsrv_start(struct net *net)
|
|
return tipc_server_start(topsrv);
|
|
}
|
|
|
|
-void tipc_topsrv_stop(struct net *net)
|
|
+static void tipc_topsrv_stop(struct net *net)
|
|
{
|
|
struct tipc_net *tn = net_generic(net, tipc_net_id);
|
|
struct tipc_server *topsrv = tn->topsrv;
|
|
@@ -353,3 +353,13 @@ void tipc_topsrv_stop(struct net *net)
|
|
kfree(topsrv->saddr);
|
|
kfree(topsrv);
|
|
}
|
|
+
|
|
+int __net_init tipc_topsrv_init_net(struct net *net)
|
|
+{
|
|
+ return tipc_topsrv_start(net);
|
|
+}
|
|
+
|
|
+void __net_exit tipc_topsrv_exit_net(struct net *net)
|
|
+{
|
|
+ tipc_topsrv_stop(net);
|
|
+}
|
|
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
|
|
index 92ee18cc5fe6..e9aa8c7a6fec 100644
|
|
--- a/net/tipc/subscr.h
|
|
+++ b/net/tipc/subscr.h
|
|
@@ -77,7 +77,8 @@ int tipc_subscrp_check_overlap(struct tipc_subscription *sub, u32 found_lower,
|
|
void tipc_subscrp_report_overlap(struct tipc_subscription *sub,
|
|
u32 found_lower, u32 found_upper, u32 event,
|
|
u32 port_ref, u32 node, int must);
|
|
-int tipc_topsrv_start(struct net *net);
|
|
-void tipc_topsrv_stop(struct net *net);
|
|
+
|
|
+int __net_init tipc_topsrv_init_net(struct net *net);
|
|
+void __net_exit tipc_topsrv_exit_net(struct net *net);
|
|
|
|
#endif
|
|
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
|
|
index 81013490a99f..1968998e6c6c 100644
|
|
--- a/net/wireless/nl80211.c
|
|
+++ b/net/wireless/nl80211.c
|
|
@@ -12788,6 +12788,11 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
|
|
|
|
wdev->chandef = *chandef;
|
|
wdev->preset_chandef = *chandef;
|
|
+
|
|
+ if (wdev->iftype == NL80211_IFTYPE_STATION &&
|
|
+ !WARN_ON(!wdev->current_bss))
|
|
+ wdev->current_bss->pub.channel = chandef->chan;
|
|
+
|
|
nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
|
|
NL80211_CMD_CH_SWITCH_NOTIFY, 0);
|
|
}
|
|
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
|
|
index 177a6c75f136..b04c03043976 100644
|
|
--- a/net/xfrm/xfrm_user.c
|
|
+++ b/net/xfrm/xfrm_user.c
|
|
@@ -1340,7 +1340,7 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
|
|
ret = verify_policy_dir(p->dir);
|
|
if (ret)
|
|
return ret;
|
|
- if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir))
|
|
+ if (p->index && (xfrm_policy_id2dir(p->index) != p->dir))
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
diff --git a/scripts/coccinelle/api/stream_open.cocci b/scripts/coccinelle/api/stream_open.cocci
|
|
new file mode 100644
|
|
index 000000000000..350145da7669
|
|
--- /dev/null
|
|
+++ b/scripts/coccinelle/api/stream_open.cocci
|
|
@@ -0,0 +1,363 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+// Author: Kirill Smelkov (kirr@nexedi.com)
|
|
+//
|
|
+// Search for stream-like files that are using nonseekable_open and convert
|
|
+// them to stream_open. A stream-like file is a file that does not use ppos in
|
|
+// its read and write. Rationale for the conversion is to avoid deadlock in
|
|
+// between read and write.
|
|
+
|
|
+virtual report
|
|
+virtual patch
|
|
+virtual explain // explain decisions in the patch (SPFLAGS="-D explain")
|
|
+
|
|
+// stream-like reader & writer - ones that do not depend on f_pos.
|
|
+@ stream_reader @
|
|
+identifier readstream, ppos;
|
|
+identifier f, buf, len;
|
|
+type loff_t;
|
|
+@@
|
|
+ ssize_t readstream(struct file *f, char *buf, size_t len, loff_t *ppos)
|
|
+ {
|
|
+ ... when != ppos
|
|
+ }
|
|
+
|
|
+@ stream_writer @
|
|
+identifier writestream, ppos;
|
|
+identifier f, buf, len;
|
|
+type loff_t;
|
|
+@@
|
|
+ ssize_t writestream(struct file *f, const char *buf, size_t len, loff_t *ppos)
|
|
+ {
|
|
+ ... when != ppos
|
|
+ }
|
|
+
|
|
+
|
|
+// a function that blocks
|
|
+@ blocks @
|
|
+identifier block_f;
|
|
+identifier wait_event =~ "^wait_event_.*";
|
|
+@@
|
|
+ block_f(...) {
|
|
+ ... when exists
|
|
+ wait_event(...)
|
|
+ ... when exists
|
|
+ }
|
|
+
|
|
+// stream_reader that can block inside.
|
|
+//
|
|
+// XXX wait_* can be called not directly from current function (e.g. func -> f -> g -> wait())
|
|
+// XXX currently reader_blocks supports only direct and 1-level indirect cases.
|
|
+@ reader_blocks_direct @
|
|
+identifier stream_reader.readstream;
|
|
+identifier wait_event =~ "^wait_event_.*";
|
|
+@@
|
|
+ readstream(...)
|
|
+ {
|
|
+ ... when exists
|
|
+ wait_event(...)
|
|
+ ... when exists
|
|
+ }
|
|
+
|
|
+@ reader_blocks_1 @
|
|
+identifier stream_reader.readstream;
|
|
+identifier blocks.block_f;
|
|
+@@
|
|
+ readstream(...)
|
|
+ {
|
|
+ ... when exists
|
|
+ block_f(...)
|
|
+ ... when exists
|
|
+ }
|
|
+
|
|
+@ reader_blocks depends on reader_blocks_direct || reader_blocks_1 @
|
|
+identifier stream_reader.readstream;
|
|
+@@
|
|
+ readstream(...) {
|
|
+ ...
|
|
+ }
|
|
+
|
|
+
|
|
+// file_operations + whether they have _any_ .read, .write, .llseek ... at all.
|
|
+//
|
|
+// XXX add support for file_operations xxx[N] = ... (sound/core/pcm_native.c)
|
|
+@ fops0 @
|
|
+identifier fops;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ ...
|
|
+ };
|
|
+
|
|
+@ has_read @
|
|
+identifier fops0.fops;
|
|
+identifier read_f;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .read = read_f,
|
|
+ };
|
|
+
|
|
+@ has_read_iter @
|
|
+identifier fops0.fops;
|
|
+identifier read_iter_f;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .read_iter = read_iter_f,
|
|
+ };
|
|
+
|
|
+@ has_write @
|
|
+identifier fops0.fops;
|
|
+identifier write_f;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .write = write_f,
|
|
+ };
|
|
+
|
|
+@ has_write_iter @
|
|
+identifier fops0.fops;
|
|
+identifier write_iter_f;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .write_iter = write_iter_f,
|
|
+ };
|
|
+
|
|
+@ has_llseek @
|
|
+identifier fops0.fops;
|
|
+identifier llseek_f;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .llseek = llseek_f,
|
|
+ };
|
|
+
|
|
+@ has_no_llseek @
|
|
+identifier fops0.fops;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .llseek = no_llseek,
|
|
+ };
|
|
+
|
|
+@ has_mmap @
|
|
+identifier fops0.fops;
|
|
+identifier mmap_f;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .mmap = mmap_f,
|
|
+ };
|
|
+
|
|
+@ has_copy_file_range @
|
|
+identifier fops0.fops;
|
|
+identifier copy_file_range_f;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .copy_file_range = copy_file_range_f,
|
|
+ };
|
|
+
|
|
+@ has_remap_file_range @
|
|
+identifier fops0.fops;
|
|
+identifier remap_file_range_f;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .remap_file_range = remap_file_range_f,
|
|
+ };
|
|
+
|
|
+@ has_splice_read @
|
|
+identifier fops0.fops;
|
|
+identifier splice_read_f;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .splice_read = splice_read_f,
|
|
+ };
|
|
+
|
|
+@ has_splice_write @
|
|
+identifier fops0.fops;
|
|
+identifier splice_write_f;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .splice_write = splice_write_f,
|
|
+ };
|
|
+
|
|
+
|
|
+// file_operations that is candidate for stream_open conversion - it does not
|
|
+// use mmap and other methods that assume @offset access to file.
|
|
+//
|
|
+// XXX for simplicity require no .{read/write}_iter and no .splice_{read/write} for now.
|
|
+// XXX maybe_steam.fops cannot be used in other rules - it gives "bad rule maybe_stream or bad variable fops".
|
|
+@ maybe_stream depends on (!has_llseek || has_no_llseek) && !has_mmap && !has_copy_file_range && !has_remap_file_range && !has_read_iter && !has_write_iter && !has_splice_read && !has_splice_write @
|
|
+identifier fops0.fops;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ };
|
|
+
|
|
+
|
|
+// ---- conversions ----
|
|
+
|
|
+// XXX .open = nonseekable_open -> .open = stream_open
|
|
+// XXX .open = func -> openfunc -> nonseekable_open
|
|
+
|
|
+// read & write
|
|
+//
|
|
+// if both are used in the same file_operations together with an opener -
|
|
+// under that conditions we can use stream_open instead of nonseekable_open.
|
|
+@ fops_rw depends on maybe_stream @
|
|
+identifier fops0.fops, openfunc;
|
|
+identifier stream_reader.readstream;
|
|
+identifier stream_writer.writestream;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .open = openfunc,
|
|
+ .read = readstream,
|
|
+ .write = writestream,
|
|
+ };
|
|
+
|
|
+@ report_rw depends on report @
|
|
+identifier fops_rw.openfunc;
|
|
+position p1;
|
|
+@@
|
|
+ openfunc(...) {
|
|
+ <...
|
|
+ nonseekable_open@p1
|
|
+ ...>
|
|
+ }
|
|
+
|
|
+@ script:python depends on report && reader_blocks @
|
|
+fops << fops0.fops;
|
|
+p << report_rw.p1;
|
|
+@@
|
|
+coccilib.report.print_report(p[0],
|
|
+ "ERROR: %s: .read() can deadlock .write(); change nonseekable_open -> stream_open to fix." % (fops,))
|
|
+
|
|
+@ script:python depends on report && !reader_blocks @
|
|
+fops << fops0.fops;
|
|
+p << report_rw.p1;
|
|
+@@
|
|
+coccilib.report.print_report(p[0],
|
|
+ "WARNING: %s: .read() and .write() have stream semantic; safe to change nonseekable_open -> stream_open." % (fops,))
|
|
+
|
|
+
|
|
+@ explain_rw_deadlocked depends on explain && reader_blocks @
|
|
+identifier fops_rw.openfunc;
|
|
+@@
|
|
+ openfunc(...) {
|
|
+ <...
|
|
+- nonseekable_open
|
|
++ nonseekable_open /* read & write (was deadlock) */
|
|
+ ...>
|
|
+ }
|
|
+
|
|
+
|
|
+@ explain_rw_nodeadlock depends on explain && !reader_blocks @
|
|
+identifier fops_rw.openfunc;
|
|
+@@
|
|
+ openfunc(...) {
|
|
+ <...
|
|
+- nonseekable_open
|
|
++ nonseekable_open /* read & write (no direct deadlock) */
|
|
+ ...>
|
|
+ }
|
|
+
|
|
+@ patch_rw depends on patch @
|
|
+identifier fops_rw.openfunc;
|
|
+@@
|
|
+ openfunc(...) {
|
|
+ <...
|
|
+- nonseekable_open
|
|
++ stream_open
|
|
+ ...>
|
|
+ }
|
|
+
|
|
+
|
|
+// read, but not write
|
|
+@ fops_r depends on maybe_stream && !has_write @
|
|
+identifier fops0.fops, openfunc;
|
|
+identifier stream_reader.readstream;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .open = openfunc,
|
|
+ .read = readstream,
|
|
+ };
|
|
+
|
|
+@ report_r depends on report @
|
|
+identifier fops_r.openfunc;
|
|
+position p1;
|
|
+@@
|
|
+ openfunc(...) {
|
|
+ <...
|
|
+ nonseekable_open@p1
|
|
+ ...>
|
|
+ }
|
|
+
|
|
+@ script:python depends on report @
|
|
+fops << fops0.fops;
|
|
+p << report_r.p1;
|
|
+@@
|
|
+coccilib.report.print_report(p[0],
|
|
+ "WARNING: %s: .read() has stream semantic; safe to change nonseekable_open -> stream_open." % (fops,))
|
|
+
|
|
+@ explain_r depends on explain @
|
|
+identifier fops_r.openfunc;
|
|
+@@
|
|
+ openfunc(...) {
|
|
+ <...
|
|
+- nonseekable_open
|
|
++ nonseekable_open /* read only */
|
|
+ ...>
|
|
+ }
|
|
+
|
|
+@ patch_r depends on patch @
|
|
+identifier fops_r.openfunc;
|
|
+@@
|
|
+ openfunc(...) {
|
|
+ <...
|
|
+- nonseekable_open
|
|
++ stream_open
|
|
+ ...>
|
|
+ }
|
|
+
|
|
+
|
|
+// write, but not read
|
|
+@ fops_w depends on maybe_stream && !has_read @
|
|
+identifier fops0.fops, openfunc;
|
|
+identifier stream_writer.writestream;
|
|
+@@
|
|
+ struct file_operations fops = {
|
|
+ .open = openfunc,
|
|
+ .write = writestream,
|
|
+ };
|
|
+
|
|
+@ report_w depends on report @
|
|
+identifier fops_w.openfunc;
|
|
+position p1;
|
|
+@@
|
|
+ openfunc(...) {
|
|
+ <...
|
|
+ nonseekable_open@p1
|
|
+ ...>
|
|
+ }
|
|
+
|
|
+@ script:python depends on report @
|
|
+fops << fops0.fops;
|
|
+p << report_w.p1;
|
|
+@@
|
|
+coccilib.report.print_report(p[0],
|
|
+ "WARNING: %s: .write() has stream semantic; safe to change nonseekable_open -> stream_open." % (fops,))
|
|
+
|
|
+@ explain_w depends on explain @
|
|
+identifier fops_w.openfunc;
|
|
+@@
|
|
+ openfunc(...) {
|
|
+ <...
|
|
+- nonseekable_open
|
|
++ nonseekable_open /* write only */
|
|
+ ...>
|
|
+ }
|
|
+
|
|
+@ patch_w depends on patch @
|
|
+identifier fops_w.openfunc;
|
|
+@@
|
|
+ openfunc(...) {
|
|
+ <...
|
|
+- nonseekable_open
|
|
++ stream_open
|
|
+ ...>
|
|
+ }
|
|
+
|
|
+
|
|
+// no read, no write - don't change anything
|
|
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
|
|
index a8045b8a2a18..b249b1b85746 100644
|
|
--- a/sound/pci/hda/patch_hdmi.c
|
|
+++ b/sound/pci/hda/patch_hdmi.c
|
|
@@ -1636,9 +1636,11 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
|
|
ret = !repoll || !pin_eld->monitor_present || pin_eld->eld_valid;
|
|
|
|
jack = snd_hda_jack_tbl_get(codec, pin_nid);
|
|
- if (jack)
|
|
+ if (jack) {
|
|
jack->block_report = !ret;
|
|
-
|
|
+ jack->pin_sense = (eld->monitor_present && eld->eld_valid) ?
|
|
+ AC_PINSENSE_PRESENCE : 0;
|
|
+ }
|
|
mutex_unlock(&per_pin->lock);
|
|
snd_hda_power_down_pm(codec);
|
|
return ret;
|
|
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
|
|
index 5d8ac2d798df..68d96c2e8cde 100644
|
|
--- a/sound/pci/hda/patch_realtek.c
|
|
+++ b/sound/pci/hda/patch_realtek.c
|
|
@@ -772,11 +772,10 @@ static int alc_init(struct hda_codec *codec)
|
|
if (spec->init_hook)
|
|
spec->init_hook(codec);
|
|
|
|
+ snd_hda_gen_init(codec);
|
|
alc_fix_pll(codec);
|
|
alc_auto_init_amp(codec, spec->init_amp);
|
|
|
|
- snd_hda_gen_init(codec);
|
|
-
|
|
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
|
|
|
|
return 0;
|
|
@@ -5779,7 +5778,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|
SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
|
|
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
|
|
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
|
|
- SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
|
|
+ SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
|
|
SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
|
SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
|
|
SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
|
|
@@ -6237,7 +6236,7 @@ static int patch_alc269(struct hda_codec *codec)
|
|
|
|
spec = codec->spec;
|
|
spec->gen.shared_mic_vref_pin = 0x18;
|
|
- codec->power_save_node = 1;
|
|
+ codec->power_save_node = 0;
|
|
|
|
#ifdef CONFIG_PM
|
|
codec->patch_ops.suspend = alc269_suspend;
|
|
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
|
|
index 584aab83e478..3e65dc74eb33 100644
|
|
--- a/sound/soc/codecs/max98090.c
|
|
+++ b/sound/soc/codecs/max98090.c
|
|
@@ -1209,14 +1209,14 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
|
|
&max98090_right_rcv_mixer_controls[0],
|
|
ARRAY_SIZE(max98090_right_rcv_mixer_controls)),
|
|
|
|
- SND_SOC_DAPM_MUX("LINMOD Mux", M98090_REG_LOUTR_MIXER,
|
|
- M98090_LINMOD_SHIFT, 0, &max98090_linmod_mux),
|
|
+ SND_SOC_DAPM_MUX("LINMOD Mux", SND_SOC_NOPM, 0, 0,
|
|
+ &max98090_linmod_mux),
|
|
|
|
- SND_SOC_DAPM_MUX("MIXHPLSEL Mux", M98090_REG_HP_CONTROL,
|
|
- M98090_MIXHPLSEL_SHIFT, 0, &max98090_mixhplsel_mux),
|
|
+ SND_SOC_DAPM_MUX("MIXHPLSEL Mux", SND_SOC_NOPM, 0, 0,
|
|
+ &max98090_mixhplsel_mux),
|
|
|
|
- SND_SOC_DAPM_MUX("MIXHPRSEL Mux", M98090_REG_HP_CONTROL,
|
|
- M98090_MIXHPRSEL_SHIFT, 0, &max98090_mixhprsel_mux),
|
|
+ SND_SOC_DAPM_MUX("MIXHPRSEL Mux", SND_SOC_NOPM, 0, 0,
|
|
+ &max98090_mixhprsel_mux),
|
|
|
|
SND_SOC_DAPM_PGA("HP Left Out", M98090_REG_OUTPUT_ENABLE,
|
|
M98090_HPLEN_SHIFT, 0, NULL, 0),
|
|
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
|
|
index 91879ea95415..01aa75cde571 100644
|
|
--- a/sound/soc/codecs/rt5677-spi.c
|
|
+++ b/sound/soc/codecs/rt5677-spi.c
|
|
@@ -60,13 +60,15 @@ static DEFINE_MUTEX(spi_mutex);
|
|
* RT5677_SPI_READ/WRITE_32: Transfer 4 bytes
|
|
* RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes
|
|
*
|
|
- * For example, reading 260 bytes at 0x60030002 uses the following commands:
|
|
- * 0x60030002 RT5677_SPI_READ_16 2 bytes
|
|
+ * Note:
|
|
+ * 16 Bit writes and reads are restricted to the address range
|
|
+ * 0x18020000 ~ 0x18021000
|
|
+ *
|
|
+ * For example, reading 256 bytes at 0x60030004 uses the following commands:
|
|
* 0x60030004 RT5677_SPI_READ_32 4 bytes
|
|
* 0x60030008 RT5677_SPI_READ_BURST 240 bytes
|
|
* 0x600300F8 RT5677_SPI_READ_BURST 8 bytes
|
|
* 0x60030100 RT5677_SPI_READ_32 4 bytes
|
|
- * 0x60030104 RT5677_SPI_READ_16 2 bytes
|
|
*
|
|
* Input:
|
|
* @read: true for read commands; false for write commands
|
|
@@ -81,15 +83,13 @@ static u8 rt5677_spi_select_cmd(bool read, u32 align, u32 remain, u32 *len)
|
|
{
|
|
u8 cmd;
|
|
|
|
- if (align == 2 || align == 6 || remain == 2) {
|
|
- cmd = RT5677_SPI_READ_16;
|
|
- *len = 2;
|
|
- } else if (align == 4 || remain <= 6) {
|
|
+ if (align == 4 || remain <= 4) {
|
|
cmd = RT5677_SPI_READ_32;
|
|
*len = 4;
|
|
} else {
|
|
cmd = RT5677_SPI_READ_BURST;
|
|
- *len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN);
|
|
+ *len = (((remain - 1) >> 3) + 1) << 3;
|
|
+ *len = min_t(u32, *len, RT5677_SPI_BURST_LEN);
|
|
}
|
|
return read ? cmd : cmd + 1;
|
|
}
|
|
@@ -110,7 +110,7 @@ static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen)
|
|
}
|
|
}
|
|
|
|
-/* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */
|
|
+/* Read DSP address space using SPI. addr and len have to be 4-byte aligned. */
|
|
int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
|
|
{
|
|
u32 offset;
|
|
@@ -126,7 +126,7 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
|
|
if (!g_spi)
|
|
return -ENODEV;
|
|
|
|
- if ((addr & 1) || (len & 1)) {
|
|
+ if ((addr & 3) || (len & 3)) {
|
|
dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len);
|
|
return -EACCES;
|
|
}
|
|
@@ -161,13 +161,13 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
|
|
}
|
|
EXPORT_SYMBOL_GPL(rt5677_spi_read);
|
|
|
|
-/* Write DSP address space using SPI. addr has to be 2-byte aligned.
|
|
- * If len is not 2-byte aligned, an extra byte of zero is written at the end
|
|
+/* Write DSP address space using SPI. addr has to be 4-byte aligned.
|
|
+ * If len is not 4-byte aligned, then extra zeros are written at the end
|
|
* as padding.
|
|
*/
|
|
int rt5677_spi_write(u32 addr, const void *txbuf, size_t len)
|
|
{
|
|
- u32 offset, len_with_pad = len;
|
|
+ u32 offset;
|
|
int status = 0;
|
|
struct spi_transfer t;
|
|
struct spi_message m;
|
|
@@ -180,22 +180,19 @@ int rt5677_spi_write(u32 addr, const void *txbuf, size_t len)
|
|
if (!g_spi)
|
|
return -ENODEV;
|
|
|
|
- if (addr & 1) {
|
|
+ if (addr & 3) {
|
|
dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len);
|
|
return -EACCES;
|
|
}
|
|
|
|
- if (len & 1)
|
|
- len_with_pad = len + 1;
|
|
-
|
|
memset(&t, 0, sizeof(t));
|
|
t.tx_buf = buf;
|
|
t.speed_hz = RT5677_SPI_FREQ;
|
|
spi_message_init_with_transfers(&m, &t, 1);
|
|
|
|
- for (offset = 0; offset < len_with_pad;) {
|
|
+ for (offset = 0; offset < len;) {
|
|
spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7,
|
|
- len_with_pad - offset, &t.len);
|
|
+ len - offset, &t.len);
|
|
|
|
/* Construct SPI message header */
|
|
buf[0] = spi_cmd;
|
|
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
|
|
index 2ccb8bccc9d4..512ec25c9ead 100644
|
|
--- a/sound/soc/davinci/davinci-mcasp.c
|
|
+++ b/sound/soc/davinci/davinci-mcasp.c
|
|
@@ -43,6 +43,7 @@
|
|
|
|
#define MCASP_MAX_AFIFO_DEPTH 64
|
|
|
|
+#ifdef CONFIG_PM
|
|
static u32 context_regs[] = {
|
|
DAVINCI_MCASP_TXFMCTL_REG,
|
|
DAVINCI_MCASP_RXFMCTL_REG,
|
|
@@ -65,6 +66,7 @@ struct davinci_mcasp_context {
|
|
u32 *xrsr_regs; /* for serializer configuration */
|
|
bool pm_state;
|
|
};
|
|
+#endif
|
|
|
|
struct davinci_mcasp_ruledata {
|
|
struct davinci_mcasp *mcasp;
|
|
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
|
|
index 3066e068aae5..d420995ed45b 100644
|
|
--- a/sound/soc/fsl/Kconfig
|
|
+++ b/sound/soc/fsl/Kconfig
|
|
@@ -171,16 +171,17 @@ config SND_MPC52xx_SOC_EFIKA
|
|
|
|
endif # SND_POWERPC_SOC
|
|
|
|
+config SND_SOC_IMX_PCM_FIQ
|
|
+ tristate
|
|
+ default y if SND_SOC_IMX_SSI=y && (SND_SOC_FSL_SSI=m || SND_SOC_FSL_SPDIF=m) && (MXC_TZIC || MXC_AVIC)
|
|
+ select FIQ
|
|
+
|
|
if SND_IMX_SOC
|
|
|
|
config SND_SOC_IMX_SSI
|
|
tristate
|
|
select SND_SOC_FSL_UTILS
|
|
|
|
-config SND_SOC_IMX_PCM_FIQ
|
|
- tristate
|
|
- select FIQ
|
|
-
|
|
comment "SoC Audio support for Freescale i.MX boards:"
|
|
|
|
config SND_MXC_SOC_WM1133_EV1
|
|
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
|
|
index 883087f2b092..38132143b7d5 100644
|
|
--- a/sound/soc/fsl/eukrea-tlv320.c
|
|
+++ b/sound/soc/fsl/eukrea-tlv320.c
|
|
@@ -119,13 +119,13 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
|
|
if (ret) {
|
|
dev_err(&pdev->dev,
|
|
"fsl,mux-int-port node missing or invalid.\n");
|
|
- return ret;
|
|
+ goto err;
|
|
}
|
|
ret = of_property_read_u32(np, "fsl,mux-ext-port", &ext_port);
|
|
if (ret) {
|
|
dev_err(&pdev->dev,
|
|
"fsl,mux-ext-port node missing or invalid.\n");
|
|
- return ret;
|
|
+ goto err;
|
|
}
|
|
|
|
/*
|
|
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
|
|
index 08b460ba06ef..61d2d955f26a 100644
|
|
--- a/sound/soc/fsl/fsl_sai.c
|
|
+++ b/sound/soc/fsl/fsl_sai.c
|
|
@@ -260,12 +260,14 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
|
|
case SND_SOC_DAIFMT_CBS_CFS:
|
|
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
|
|
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
|
|
+ sai->is_slave_mode = false;
|
|
break;
|
|
case SND_SOC_DAIFMT_CBM_CFM:
|
|
sai->is_slave_mode = true;
|
|
break;
|
|
case SND_SOC_DAIFMT_CBS_CFM:
|
|
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
|
|
+ sai->is_slave_mode = false;
|
|
break;
|
|
case SND_SOC_DAIFMT_CBM_CFS:
|
|
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
|
|
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
|
|
index b9e42b503a37..4f8bdb7650e8 100644
|
|
--- a/sound/soc/fsl/fsl_utils.c
|
|
+++ b/sound/soc/fsl/fsl_utils.c
|
|
@@ -75,6 +75,7 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
|
|
iprop = of_get_property(dma_np, "cell-index", NULL);
|
|
if (!iprop) {
|
|
of_node_put(dma_np);
|
|
+ of_node_put(dma_channel_np);
|
|
return -EINVAL;
|
|
}
|
|
*dma_id = be32_to_cpup(iprop);
|
|
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
|
|
index f7eb0d2f797b..1f7eb3816cd7 100644
|
|
--- a/sound/usb/mixer.c
|
|
+++ b/sound/usb/mixer.c
|
|
@@ -2112,6 +2112,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
|
|
kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
|
|
if (! kctl) {
|
|
usb_audio_err(state->chip, "cannot malloc kcontrol\n");
|
|
+ for (i = 0; i < desc->bNrInPins; i++)
|
|
+ kfree(namelist[i]);
|
|
kfree(namelist);
|
|
kfree(cval);
|
|
return -ENOMEM;
|
|
diff --git a/tools/include/linux/bitops.h b/tools/include/linux/bitops.h
|
|
index 5ad9ee1dd7f6..57187d6790c1 100644
|
|
--- a/tools/include/linux/bitops.h
|
|
+++ b/tools/include/linux/bitops.h
|
|
@@ -3,17 +3,14 @@
|
|
|
|
#include <asm/types.h>
|
|
#include <linux/kernel.h>
|
|
-#include <linux/compiler.h>
|
|
-
|
|
#ifndef __WORDSIZE
|
|
#define __WORDSIZE (__SIZEOF_LONG__ * 8)
|
|
#endif
|
|
|
|
#define BITS_PER_LONG __WORDSIZE
|
|
+#include <linux/bits.h>
|
|
+#include <linux/compiler.h>
|
|
|
|
-#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
|
-#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
|
-#define BITS_PER_BYTE 8
|
|
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
|
|
#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
|
|
#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
|
|
diff --git a/tools/include/linux/bits.h b/tools/include/linux/bits.h
|
|
new file mode 100644
|
|
index 000000000000..2b7b532c1d51
|
|
--- /dev/null
|
|
+++ b/tools/include/linux/bits.h
|
|
@@ -0,0 +1,26 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+#ifndef __LINUX_BITS_H
|
|
+#define __LINUX_BITS_H
|
|
+#include <asm/bitsperlong.h>
|
|
+
|
|
+#define BIT(nr) (1UL << (nr))
|
|
+#define BIT_ULL(nr) (1ULL << (nr))
|
|
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
|
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
|
+#define BIT_ULL_MASK(nr) (1ULL << ((nr) % BITS_PER_LONG_LONG))
|
|
+#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG)
|
|
+#define BITS_PER_BYTE 8
|
|
+
|
|
+/*
|
|
+ * Create a contiguous bitmask starting at bit position @l and ending at
|
|
+ * position @h. For example
|
|
+ * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
|
|
+ */
|
|
+#define GENMASK(h, l) \
|
|
+ (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
|
|
+
|
|
+#define GENMASK_ULL(h, l) \
|
|
+ (((~0ULL) - (1ULL << (l)) + 1) & \
|
|
+ (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
|
|
+
|
|
+#endif /* __LINUX_BITS_H */
|
|
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
|
|
index 73d192f57dc3..df41deed0320 100644
|
|
--- a/tools/perf/bench/numa.c
|
|
+++ b/tools/perf/bench/numa.c
|
|
@@ -32,6 +32,10 @@
|
|
#include <numa.h>
|
|
#include <numaif.h>
|
|
|
|
+#ifndef RUSAGE_THREAD
|
|
+# define RUSAGE_THREAD 1
|
|
+#endif
|
|
+
|
|
/*
|
|
* Regular printout to the terminal, supressed if -q is specified:
|
|
*/
|
|
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
|
|
index 62b38f2ff60d..c1944765533c 100644
|
|
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
|
|
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
|
|
@@ -58,6 +58,7 @@ enum intel_pt_pkt_state {
|
|
INTEL_PT_STATE_NO_IP,
|
|
INTEL_PT_STATE_ERR_RESYNC,
|
|
INTEL_PT_STATE_IN_SYNC,
|
|
+ INTEL_PT_STATE_TNT_CONT,
|
|
INTEL_PT_STATE_TNT,
|
|
INTEL_PT_STATE_TIP,
|
|
INTEL_PT_STATE_TIP_PGD,
|
|
@@ -72,8 +73,9 @@ static inline bool intel_pt_sample_time(enum intel_pt_pkt_state pkt_state)
|
|
case INTEL_PT_STATE_NO_IP:
|
|
case INTEL_PT_STATE_ERR_RESYNC:
|
|
case INTEL_PT_STATE_IN_SYNC:
|
|
- case INTEL_PT_STATE_TNT:
|
|
+ case INTEL_PT_STATE_TNT_CONT:
|
|
return true;
|
|
+ case INTEL_PT_STATE_TNT:
|
|
case INTEL_PT_STATE_TIP:
|
|
case INTEL_PT_STATE_TIP_PGD:
|
|
case INTEL_PT_STATE_FUP:
|
|
@@ -854,16 +856,20 @@ static uint64_t intel_pt_next_period(struct intel_pt_decoder *decoder)
|
|
timestamp = decoder->timestamp + decoder->timestamp_insn_cnt;
|
|
masked_timestamp = timestamp & decoder->period_mask;
|
|
if (decoder->continuous_period) {
|
|
- if (masked_timestamp != decoder->last_masked_timestamp)
|
|
+ if (masked_timestamp > decoder->last_masked_timestamp)
|
|
return 1;
|
|
} else {
|
|
timestamp += 1;
|
|
masked_timestamp = timestamp & decoder->period_mask;
|
|
- if (masked_timestamp != decoder->last_masked_timestamp) {
|
|
+ if (masked_timestamp > decoder->last_masked_timestamp) {
|
|
decoder->last_masked_timestamp = masked_timestamp;
|
|
decoder->continuous_period = true;
|
|
}
|
|
}
|
|
+
|
|
+ if (masked_timestamp < decoder->last_masked_timestamp)
|
|
+ return decoder->period_ticks;
|
|
+
|
|
return decoder->period_ticks - (timestamp - masked_timestamp);
|
|
}
|
|
|
|
@@ -892,7 +898,10 @@ static void intel_pt_sample_insn(struct intel_pt_decoder *decoder)
|
|
case INTEL_PT_PERIOD_TICKS:
|
|
timestamp = decoder->timestamp + decoder->timestamp_insn_cnt;
|
|
masked_timestamp = timestamp & decoder->period_mask;
|
|
- decoder->last_masked_timestamp = masked_timestamp;
|
|
+ if (masked_timestamp > decoder->last_masked_timestamp)
|
|
+ decoder->last_masked_timestamp = masked_timestamp;
|
|
+ else
|
|
+ decoder->last_masked_timestamp += decoder->period_ticks;
|
|
break;
|
|
case INTEL_PT_PERIOD_NONE:
|
|
case INTEL_PT_PERIOD_MTC:
|
|
@@ -1141,7 +1150,9 @@ static int intel_pt_walk_tnt(struct intel_pt_decoder *decoder)
|
|
return -ENOENT;
|
|
}
|
|
decoder->tnt.count -= 1;
|
|
- if (!decoder->tnt.count)
|
|
+ if (decoder->tnt.count)
|
|
+ decoder->pkt_state = INTEL_PT_STATE_TNT_CONT;
|
|
+ else
|
|
decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
|
|
decoder->tnt.payload <<= 1;
|
|
decoder->state.from_ip = decoder->ip;
|
|
@@ -1172,7 +1183,9 @@ static int intel_pt_walk_tnt(struct intel_pt_decoder *decoder)
|
|
|
|
if (intel_pt_insn.branch == INTEL_PT_BR_CONDITIONAL) {
|
|
decoder->tnt.count -= 1;
|
|
- if (!decoder->tnt.count)
|
|
+ if (decoder->tnt.count)
|
|
+ decoder->pkt_state = INTEL_PT_STATE_TNT_CONT;
|
|
+ else
|
|
decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
|
|
if (decoder->tnt.payload & BIT63) {
|
|
decoder->tnt.payload <<= 1;
|
|
@@ -1192,8 +1205,11 @@ static int intel_pt_walk_tnt(struct intel_pt_decoder *decoder)
|
|
return 0;
|
|
}
|
|
decoder->ip += intel_pt_insn.length;
|
|
- if (!decoder->tnt.count)
|
|
+ if (!decoder->tnt.count) {
|
|
+ decoder->sample_timestamp = decoder->timestamp;
|
|
+ decoder->sample_insn_cnt = decoder->timestamp_insn_cnt;
|
|
return -EAGAIN;
|
|
+ }
|
|
decoder->tnt.payload <<= 1;
|
|
continue;
|
|
}
|
|
@@ -2116,6 +2132,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder)
|
|
err = intel_pt_walk_trace(decoder);
|
|
break;
|
|
case INTEL_PT_STATE_TNT:
|
|
+ case INTEL_PT_STATE_TNT_CONT:
|
|
err = intel_pt_walk_tnt(decoder);
|
|
if (err == -EAGAIN)
|
|
err = intel_pt_walk_trace(decoder);
|
|
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
|
|
index accb7ece1d3c..3d7af024c73f 100644
|
|
--- a/tools/perf/util/string.c
|
|
+++ b/tools/perf/util/string.c
|
|
@@ -1,4 +1,5 @@
|
|
#include "util.h"
|
|
+#include <linux/compiler.h>
|
|
#include "linux/string.h"
|
|
|
|
#define K 1024LL
|
|
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
|
|
index dcc659017976..ee5d1dfe13da 100644
|
|
--- a/tools/perf/util/util.h
|
|
+++ b/tools/perf/util/util.h
|
|
@@ -76,7 +76,6 @@
|
|
#include <sys/ttydefaults.h>
|
|
#include <api/fs/tracing_path.h>
|
|
#include <termios.h>
|
|
-#include <linux/bitops.h>
|
|
#include <termios.h>
|
|
|
|
extern const char *graph_line;
|