From 98b00488459e9d27d8e42b6d241f309f26ffde07 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 29 Jun 2016 10:17:52 +0100 Subject: [PATCH 0001/1167] dt-bindings: i2c: Add support for 'i2c-bus' subnode The I2C driver core for boards using device-tree assumes any subnode of an I2C adapter in the device-tree blob is an I2C slave device. Although this makes complete sense, some I2C adapters may have subnodes which are not I2C slaves but subnodes presenting other features. For example some Tegra devices have an I2C interface which may share its pins with other devices. In order to share these pins using the pinctrl framework, it is necessary to add subnodes to the I2C device node that represent these pins. To allow I2C adapters to have non-I2C specific subnodes in device-tree that are not parsed by the I2C driver core, add support for an optional 'i2c-bus' subnode where I2C slaves can be placed. If the 'i2c-bus' subnode is present then all I2C slaves must be placed under this subnode. Signed-off-by: Jon Hunter Acked-by: Thierry Reding Acked-by: Rob Herring Acked-by: Wolfram Sang Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/i2c/i2c.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index c8d977ed847f3..a07452854118e 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -32,6 +32,14 @@ wants to support one of the below features, it should adapt the bindings below. - clock-frequency frequency of bus clock in Hz. +- i2c-bus + For I2C adapters that have child nodes that are a mixture of both I2C + devices and non-I2C devices, the 'i2c-bus' subnode can be used for + populating I2C devices. If the 'i2c-bus' subnode is present, only + subnodes of this will be considered as I2C slaves. The properties, + '#address-cells' and '#size-cells' must be defined under this subnode + if present. + - i2c-scl-falling-time-ns Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C specification. -- GitLab From 7e4c224abfe8e2a00f56a2ef0198e6de3ca1852c Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 29 Jun 2016 10:17:53 +0100 Subject: [PATCH 0002/1167] i2c: core: Add support for 'i2c-bus' subnode If the 'i2c-bus' device-tree node is present for an I2C adapter then parse this subnode for I2C slaves. Signed-off-by: Jon Hunter Acked-by: Wolfram Sang Signed-off-by: Thierry Reding --- drivers/i2c/i2c-core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index af11b658984d7..ed7002dd9401f 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1411,7 +1411,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, static void of_i2c_register_devices(struct i2c_adapter *adap) { - struct device_node *node; + struct device_node *bus, *node; /* Only register child devices if the adapter has a node pointer set */ if (!adap->dev.of_node) @@ -1419,11 +1419,17 @@ static void of_i2c_register_devices(struct i2c_adapter *adap) dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); - for_each_available_child_of_node(adap->dev.of_node, node) { + bus = of_get_child_by_name(adap->dev.of_node, "i2c-bus"); + if (!bus) + bus = of_node_get(adap->dev.of_node); + + for_each_available_child_of_node(bus, node) { if (of_node_test_and_set_flag(node, OF_POPULATED)) continue; of_i2c_register_device(adap, node); } + + of_node_put(bus); } static int of_dev_node_match(struct device *dev, void *data) -- GitLab From 7f2084fa55e6cb61f61b4224d4a8bafaeee55f9f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 15 Jan 2016 14:01:22 -0500 Subject: [PATCH 0003/1167] [kbuild] handle exports in lib-y objects reliably Collect the symbols exported by anything that goes into lib.a and add an empty object (lib-exports.o) with explicit undefs for each of those to obj-y. That allows to relax the rules regarding the use of exports in lib-* objects - right now an object with export can be in lib-* only if we are guaranteed that there always will be users in built-in parts of the tree, otherwise it needs to be in obj-*. As the result, we have an unholy mix of lib- and obj- in lib/Makefile and (especially) in arch/*/lib/Makefile. Moreover, a change in generic part of the kernel can lead to mysteriously missing exports on some configs. With this change we don't have to worry about that anymore. One side effect is that built-in.o now pulls everything with exports from the corresponding lib.a (if such exists). That's exactly what we want for linking vmlinux and fortunately it's almost the only thing built-in.o is used in. arch/ia64/hp/sim/boot/bootloader is the only exception and it's easy to get rid of now - just turn everything in arch/ia64/lib into lib-* and don't bother with arch/ia64/lib/built-in.o anymore. [AV: stylistic fix from Michal folded in] Acked-by: Michal Marek Signed-off-by: Al Viro --- arch/ia64/hp/sim/boot/Makefile | 2 +- arch/ia64/lib/Makefile | 8 +++----- scripts/Makefile.build | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/arch/ia64/hp/sim/boot/Makefile b/arch/ia64/hp/sim/boot/Makefile index 2e805e0cc5605..df6e9968c8454 100644 --- a/arch/ia64/hp/sim/boot/Makefile +++ b/arch/ia64/hp/sim/boot/Makefile @@ -33,5 +33,5 @@ $(obj)/vmlinux.bin: vmlinux FORCE LDFLAGS_bootloader = -static -T $(obj)/bootloader: $(src)/bootloader.lds $(obj)/bootloader.o $(obj)/boot_head.o $(obj)/fw-emu.o \ - lib/lib.a arch/ia64/lib/built-in.o arch/ia64/lib/lib.a FORCE + lib/lib.a arch/ia64/lib/lib.a FORCE $(call if_changed,ld) diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile index 98771e2a78afd..1f3d3877618fd 100644 --- a/arch/ia64/lib/Makefile +++ b/arch/ia64/lib/Makefile @@ -2,17 +2,15 @@ # Makefile for ia64-specific library routines.. # -obj-y := io.o - -lib-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ +lib-y := io.o __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o \ checksum.o clear_page.o csum_partial_copy.o \ clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o \ flush.o ip_fast_csum.o do_csum.o \ memset.o strlen.o xor.o -obj-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o -obj-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o +lib-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o +lib-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o lib-$(CONFIG_PERFMON) += carta_random.o AFLAGS___divdi3.o = diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 11602e5efb3bc..cd9bf22bb0279 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -81,6 +81,7 @@ endif ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),) lib-target := $(obj)/lib.a +obj-y += $(obj)/lib-ksyms.o endif ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),) @@ -395,6 +396,25 @@ $(lib-target): $(lib-y) FORCE $(call if_changed,link_l_target) targets += $(lib-target) + +dummy-object = $(obj)/.lib_exports.o +ksyms-lds = $(dot-target).lds +ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX +ref_prefix = EXTERN(_ +else +ref_prefix = EXTERN( +endif + +quiet_cmd_export_list = EXPORTS $@ +cmd_export_list = $(OBJDUMP) -h $< | \ + sed -ne '/___ksymtab/{s/.*+/$(ref_prefix)/;s/ .*/)/;p}' >$(ksyms-lds);\ + rm -f $(dummy-object);\ + $(AR) rcs$(KBUILD_ARFLAGS) $(dummy-object);\ + $(LD) $(ld_flags) -r -o $@ -T $(ksyms-lds) $(dummy-object);\ + rm $(dummy-object) $(ksyms-lds) + +$(obj)/lib-ksyms.o: $(lib-target) FORCE + $(call if_changed,export_list) endif # -- GitLab From 22823ab419d8ed884195cfa75483fd3a99bb1462 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 11 Jan 2016 10:54:54 -0500 Subject: [PATCH 0004/1167] EXPORT_SYMBOL() for asm Add asm-usable variants of EXPORT_SYMBOL/EXPORT_SYMBOL_GPL. This commit just adds the default implementation; most of the architectures can simply add export.h to asm/Kbuild and start using from assembler. The rest needs to have their define everal macros and then explicitly include One area where the things might diverge from default is the alignment; normally it's 8 bytes on 64bit targets and 4 on 32bit ones, both for unsigned long and for struct kernel_symbol. Unfortunately, amd64 and m68k are unusual - m68k aligns to 2 bytes (for both) and amd64 aligns struct kernel_symbol to 16 bytes. For those we'll need asm/export.h to override the constants used by generic version - KSYM_ALIGN and KCRC_ALIGN for kernel_symbol and unsigned long resp. And no, __alignof__ would not do the trick - on amd64 __alignof__ of struct kernel_symbol is 8, not 16. More serious source of unpleasantness is treatment of function descriptors on architectures that have those. Things like ppc64, parisc, ia64, etc. need more than the address of the first insn to call an arbitrary function. As the result, their representation of pointers to functions is not the typical "address of the entry point" - it's an address of a small static structure containing all the required information (including the entry point, of course). Sadly, the asm-side conventions differ in what the function name refers to - entry point or the function descriptor. On ppc64 we do the latter; bar: .quad foo is what void (*bar)(void) = foo; turns into and the rare places where we need to explicitly work with the label of entry point are dealt with as DOTSYM(foo). For our purposes it's ideal - generic macros are usable. However, parisc would have foo and P%foo used for label of entry point and address of the function descriptor and bar: .long P%foo woudl be used instead. ia64 goes similar to parisc in that respect, except that there it's @fptr(foo) rather than P%foo. Such architectures need to define KSYM_FUNC that would turn a function name into whatever is needed to refer to function descriptor. What's more, on such architectures we need to know whether we are exporting a function or an object - in assembler we have to tell that explicitly, to decide whether we want EXPORT_SYMBOL(foo) produce e.g. __ksymtab_foo: .quad foo or __ksymtab_foo: .quad @fptr(foo) For that reason we introduce EXPORT_DATA_SYMBOL{,_GPL}(), to be used for exports of data objects. On normal architectures it's the same thing as EXPORT_SYMBOL{,_GPL}(), but on parisc-like ones they differ and the right one needs to be used. Most of the exports are functions, so we keep EXPORT_SYMBOL for those... Signed-off-by: Al Viro --- include/asm-generic/export.h | 94 ++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 include/asm-generic/export.h diff --git a/include/asm-generic/export.h b/include/asm-generic/export.h new file mode 100644 index 0000000000000..43199a049da5f --- /dev/null +++ b/include/asm-generic/export.h @@ -0,0 +1,94 @@ +#ifndef __ASM_GENERIC_EXPORT_H +#define __ASM_GENERIC_EXPORT_H + +#ifndef KSYM_FUNC +#define KSYM_FUNC(x) x +#endif +#ifdef CONFIG_64BIT +#define __put .quad +#ifndef KSYM_ALIGN +#define KSYM_ALIGN 8 +#endif +#ifndef KCRC_ALIGN +#define KCRC_ALIGN 8 +#endif +#else +#define __put .long +#ifndef KSYM_ALIGN +#define KSYM_ALIGN 4 +#endif +#ifndef KCRC_ALIGN +#define KCRC_ALIGN 4 +#endif +#endif + +#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX +#define KSYM(name) _##name +#else +#define KSYM(name) name +#endif + +/* + * note on .section use: @progbits vs %progbits nastiness doesn't matter, + * since we immediately emit into those sections anyway. + */ +.macro ___EXPORT_SYMBOL name,val,sec +#ifdef CONFIG_MODULES + .globl KSYM(__ksymtab_\name) + .section ___ksymtab\sec+\name,"a" + .balign KSYM_ALIGN +KSYM(__ksymtab_\name): + __put \val, KSYM(__kstrtab_\name) + .previous + .section __ksymtab_strings,"a" +KSYM(__kstrtab_\name): +#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX + .asciz "_\name" +#else + .asciz "\name" +#endif + .previous +#ifdef CONFIG_MODVERSIONS + .section ___kcrctab\sec+\name,"a" + .balign KCRC_ALIGN +KSYM(__kcrctab_\name): + __put KSYM(__crc_\name) + .weak KSYM(__crc_\name) + .previous +#endif +#endif +.endm +#undef __put + +#if defined(__KSYM_DEPS__) + +#define __EXPORT_SYMBOL(sym, val, sec) === __KSYM_##sym === + +#elif defined(CONFIG_TRIM_UNUSED_KSYMS) + +#include +#include + +#define __EXPORT_SYMBOL(sym, val, sec) \ + __cond_export_sym(sym, val, sec, config_enabled(__KSYM_##sym)) +#define __cond_export_sym(sym, val, sec, conf) \ + ___cond_export_sym(sym, val, sec, conf) +#define ___cond_export_sym(sym, val, sec, enabled) \ + __cond_export_sym_##enabled(sym, val, sec) +#define __cond_export_sym_1(sym, val, sec) ___EXPORT_SYMBOL sym, val, sec +#define __cond_export_sym_0(sym, val, sec) /* nothing */ + +#else +#define __EXPORT_SYMBOL(sym, val, sec) ___EXPORT_SYMBOL sym, val, sec +#endif + +#define EXPORT_SYMBOL(name) \ + __EXPORT_SYMBOL(name, KSYM_FUNC(KSYM(name)),) +#define EXPORT_SYMBOL_GPL(name) \ + __EXPORT_SYMBOL(name, KSYM_FUNC(KSYM(name)), _gpl) +#define EXPORT_DATA_SYMBOL(name) \ + __EXPORT_SYMBOL(name, KSYM(name),) +#define EXPORT_DATA_SYMBOL_GPL(name) \ + __EXPORT_SYMBOL(name, KSYM(name),_gpl) + +#endif -- GitLab From 784d5699eddc55878627da20d3fe0c8542e2f1a2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 11 Jan 2016 11:04:34 -0500 Subject: [PATCH 0005/1167] x86: move exports to actual definitions Signed-off-by: Al Viro --- arch/x86/entry/entry_32.S | 2 + arch/x86/entry/entry_64.S | 2 + arch/x86/entry/thunk_32.S | 3 ++ arch/x86/entry/thunk_64.S | 3 ++ arch/x86/include/asm/export.h | 4 ++ arch/x86/kernel/Makefile | 4 +- arch/x86/kernel/head_32.S | 2 + arch/x86/kernel/head_64.S | 3 ++ arch/x86/kernel/i386_ksyms_32.c | 47 ------------------ arch/x86/kernel/mcount_64.S | 2 + arch/x86/kernel/x8664_ksyms_64.c | 85 -------------------------------- arch/x86/lib/checksum_32.S | 3 ++ arch/x86/lib/clear_page_64.S | 2 + arch/x86/lib/cmpxchg8b_emu.S | 2 + arch/x86/lib/copy_page_64.S | 2 + arch/x86/lib/copy_user_64.S | 8 +++ arch/x86/lib/csum-partial_64.c | 1 + arch/x86/lib/getuser.S | 5 ++ arch/x86/lib/hweight.S | 3 ++ arch/x86/lib/memcpy_64.S | 4 ++ arch/x86/lib/memmove_64.S | 3 ++ arch/x86/lib/memset_64.S | 3 ++ arch/x86/lib/putuser.S | 5 ++ arch/x86/lib/strstr_32.c | 3 +- arch/x86/um/Makefile | 2 +- arch/x86/um/checksum_32.S | 2 + arch/x86/um/ksyms.c | 13 ----- 27 files changed, 68 insertions(+), 150 deletions(-) create mode 100644 arch/x86/include/asm/export.h delete mode 100644 arch/x86/kernel/i386_ksyms_32.c delete mode 100644 arch/x86/kernel/x8664_ksyms_64.c delete mode 100644 arch/x86/um/ksyms.c diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index 0b56666e6039b..64d29a3ad3767 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -44,6 +44,7 @@ #include #include #include +#include .section .entry.text, "ax" @@ -955,6 +956,7 @@ trace: jmp ftrace_stub END(mcount) #endif /* CONFIG_DYNAMIC_FTRACE */ +EXPORT_SYMBOL(mcount) #endif /* CONFIG_FUNCTION_TRACER */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index b846875aeea67..766d48db95453 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -35,6 +35,7 @@ #include #include #include +#include #include /* Avoid __ASSEMBLER__'ifying just for this. */ @@ -785,6 +786,7 @@ ENTRY(native_load_gs_index) popfq ret END(native_load_gs_index) +EXPORT_SYMBOL(native_load_gs_index) _ASM_EXTABLE(.Lgs_change, bad_gs) .section .fixup, "ax" diff --git a/arch/x86/entry/thunk_32.S b/arch/x86/entry/thunk_32.S index e5a17114a8c4f..fee6bc79b987f 100644 --- a/arch/x86/entry/thunk_32.S +++ b/arch/x86/entry/thunk_32.S @@ -6,6 +6,7 @@ */ #include #include + #include /* put return address in eax (arg1) */ .macro THUNK name, func, put_ret_addr_in_eax=0 @@ -36,5 +37,7 @@ #ifdef CONFIG_PREEMPT THUNK ___preempt_schedule, preempt_schedule THUNK ___preempt_schedule_notrace, preempt_schedule_notrace + EXPORT_SYMBOL(___preempt_schedule) + EXPORT_SYMBOL(___preempt_schedule_notrace) #endif diff --git a/arch/x86/entry/thunk_64.S b/arch/x86/entry/thunk_64.S index 627ecbcb2e626..be36bf4e0957e 100644 --- a/arch/x86/entry/thunk_64.S +++ b/arch/x86/entry/thunk_64.S @@ -8,6 +8,7 @@ #include #include "calling.h" #include +#include /* rdi: arg1 ... normal C conventions. rax is saved/restored. */ .macro THUNK name, func, put_ret_addr_in_rdi=0 @@ -49,6 +50,8 @@ #ifdef CONFIG_PREEMPT THUNK ___preempt_schedule, preempt_schedule THUNK ___preempt_schedule_notrace, preempt_schedule_notrace + EXPORT_SYMBOL(___preempt_schedule) + EXPORT_SYMBOL(___preempt_schedule_notrace) #endif #if defined(CONFIG_TRACE_IRQFLAGS) \ diff --git a/arch/x86/include/asm/export.h b/arch/x86/include/asm/export.h new file mode 100644 index 0000000000000..138de56b13eb7 --- /dev/null +++ b/arch/x86/include/asm/export.h @@ -0,0 +1,4 @@ +#ifdef CONFIG_64BIT +#define KSYM_ALIGN 16 +#endif +#include diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 0503f5bfb18d2..d3f49c3d5aca3 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -46,9 +46,7 @@ obj-$(CONFIG_MODIFY_LDT_SYSCALL) += ldt.o obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o obj-$(CONFIG_IRQ_WORK) += irq_work.o obj-y += probe_roms.o -obj-$(CONFIG_X86_32) += i386_ksyms_32.o -obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o -obj-$(CONFIG_X86_64) += mcount_64.o +obj-$(CONFIG_X86_64) += sys_x86_64.o mcount_64.o obj-$(CONFIG_X86_ESPFIX64) += espfix_64.o obj-$(CONFIG_SYSFS) += ksysfs.o obj-y += bootflag.o e820.o diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index 6f8902b0d1514..4707baf942034 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -23,6 +23,7 @@ #include #include #include +#include /* Physical address */ #define pa(X) ((X) - __PAGE_OFFSET) @@ -673,6 +674,7 @@ ENTRY(empty_zero_page) .fill 4096,1,0 ENTRY(swapper_pg_dir) .fill 1024,4,0 +EXPORT_SYMBOL(empty_zero_page) /* * This starts the data section. diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 9f8efc9f00756..537d913f45ecb 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -21,6 +21,7 @@ #include #include #include "../entry/calling.h" +#include #ifdef CONFIG_PARAVIRT #include @@ -488,10 +489,12 @@ early_gdt_descr_base: ENTRY(phys_base) /* This must match the first entry in level2_kernel_pgt */ .quad 0x0000000000000000 +EXPORT_SYMBOL(phys_base) #include "../../x86/xen/xen-head.S" __PAGE_ALIGNED_BSS NEXT_PAGE(empty_zero_page) .skip PAGE_SIZE +EXPORT_SYMBOL(empty_zero_page) diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c deleted file mode 100644 index 1f9b878ef5efa..0000000000000 --- a/arch/x86/kernel/i386_ksyms_32.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include - -#include -#include -#include -#include - -#ifdef CONFIG_FUNCTION_TRACER -/* mcount is defined in assembly */ -EXPORT_SYMBOL(mcount); -#endif - -/* - * Note, this is a prototype to get at the symbol for - * the export, but dont use it from C code, it is used - * by assembly code and is not using C calling convention! - */ -#ifndef CONFIG_X86_CMPXCHG64 -extern void cmpxchg8b_emu(void); -EXPORT_SYMBOL(cmpxchg8b_emu); -#endif - -/* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy_generic); - -EXPORT_SYMBOL(__get_user_1); -EXPORT_SYMBOL(__get_user_2); -EXPORT_SYMBOL(__get_user_4); -EXPORT_SYMBOL(__get_user_8); - -EXPORT_SYMBOL(__put_user_1); -EXPORT_SYMBOL(__put_user_2); -EXPORT_SYMBOL(__put_user_4); -EXPORT_SYMBOL(__put_user_8); - -EXPORT_SYMBOL(strstr); - -EXPORT_SYMBOL(csum_partial); -EXPORT_SYMBOL(empty_zero_page); - -#ifdef CONFIG_PREEMPT -EXPORT_SYMBOL(___preempt_schedule); -EXPORT_SYMBOL(___preempt_schedule_notrace); -#endif - -EXPORT_SYMBOL(__sw_hweight32); diff --git a/arch/x86/kernel/mcount_64.S b/arch/x86/kernel/mcount_64.S index 61924222a9e1c..efe73aacf966e 100644 --- a/arch/x86/kernel/mcount_64.S +++ b/arch/x86/kernel/mcount_64.S @@ -7,6 +7,7 @@ #include #include #include +#include .code64 @@ -294,6 +295,7 @@ trace: jmp fgraph_trace END(function_hook) #endif /* CONFIG_DYNAMIC_FTRACE */ +EXPORT_SYMBOL(function_hook) #endif /* CONFIG_FUNCTION_TRACER */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c deleted file mode 100644 index 95e49f6e4fc30..0000000000000 --- a/arch/x86/kernel/x8664_ksyms_64.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Exports for assembly files. - All C exports should go in the respective C files. */ - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#ifdef CONFIG_FUNCTION_TRACER -/* mcount and __fentry__ are defined in assembly */ -#ifdef CC_USING_FENTRY -EXPORT_SYMBOL(__fentry__); -#else -EXPORT_SYMBOL(mcount); -#endif -#endif - -EXPORT_SYMBOL(__get_user_1); -EXPORT_SYMBOL(__get_user_2); -EXPORT_SYMBOL(__get_user_4); -EXPORT_SYMBOL(__get_user_8); -EXPORT_SYMBOL(__put_user_1); -EXPORT_SYMBOL(__put_user_2); -EXPORT_SYMBOL(__put_user_4); -EXPORT_SYMBOL(__put_user_8); - -EXPORT_SYMBOL(copy_user_generic_string); -EXPORT_SYMBOL(copy_user_generic_unrolled); -EXPORT_SYMBOL(copy_user_enhanced_fast_string); -EXPORT_SYMBOL(__copy_user_nocache); -EXPORT_SYMBOL(_copy_from_user); -EXPORT_SYMBOL(_copy_to_user); - -EXPORT_SYMBOL_GPL(memcpy_mcsafe); - -EXPORT_SYMBOL(copy_page); -EXPORT_SYMBOL(clear_page); - -EXPORT_SYMBOL(csum_partial); - -EXPORT_SYMBOL(__sw_hweight32); -EXPORT_SYMBOL(__sw_hweight64); - -/* - * Export string functions. We normally rely on gcc builtin for most of these, - * but gcc sometimes decides not to inline them. - */ -#undef memcpy -#undef memset -#undef memmove - -extern void *__memset(void *, int, __kernel_size_t); -extern void *__memcpy(void *, const void *, __kernel_size_t); -extern void *__memmove(void *, const void *, __kernel_size_t); -extern void *memset(void *, int, __kernel_size_t); -extern void *memcpy(void *, const void *, __kernel_size_t); -extern void *memmove(void *, const void *, __kernel_size_t); - -EXPORT_SYMBOL(__memset); -EXPORT_SYMBOL(__memcpy); -EXPORT_SYMBOL(__memmove); - -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memmove); - -#ifndef CONFIG_DEBUG_VIRTUAL -EXPORT_SYMBOL(phys_base); -#endif -EXPORT_SYMBOL(empty_zero_page); -#ifndef CONFIG_PARAVIRT -EXPORT_SYMBOL(native_load_gs_index); -#endif - -#ifdef CONFIG_PREEMPT -EXPORT_SYMBOL(___preempt_schedule); -EXPORT_SYMBOL(___preempt_schedule_notrace); -#endif diff --git a/arch/x86/lib/checksum_32.S b/arch/x86/lib/checksum_32.S index c1e6232098531..4d34bb548b41e 100644 --- a/arch/x86/lib/checksum_32.S +++ b/arch/x86/lib/checksum_32.S @@ -28,6 +28,7 @@ #include #include #include +#include /* * computes a partial checksum, e.g. for TCP/UDP fragments @@ -251,6 +252,7 @@ ENTRY(csum_partial) ENDPROC(csum_partial) #endif +EXPORT_SYMBOL(csum_partial) /* unsigned int csum_partial_copy_generic (const char *src, char *dst, @@ -490,3 +492,4 @@ ENDPROC(csum_partial_copy_generic) #undef ROUND1 #endif +EXPORT_SYMBOL(csum_partial_copy_generic) diff --git a/arch/x86/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S index 65be7cfaf9472..5e2af3a88cf5e 100644 --- a/arch/x86/lib/clear_page_64.S +++ b/arch/x86/lib/clear_page_64.S @@ -1,6 +1,7 @@ #include #include #include +#include /* * Most CPUs support enhanced REP MOVSB/STOSB instructions. It is @@ -23,6 +24,7 @@ ENTRY(clear_page) rep stosq ret ENDPROC(clear_page) +EXPORT_SYMBOL(clear_page) ENTRY(clear_page_orig) diff --git a/arch/x86/lib/cmpxchg8b_emu.S b/arch/x86/lib/cmpxchg8b_emu.S index ad53497784904..03a186fc06eab 100644 --- a/arch/x86/lib/cmpxchg8b_emu.S +++ b/arch/x86/lib/cmpxchg8b_emu.S @@ -7,6 +7,7 @@ */ #include +#include .text @@ -48,3 +49,4 @@ ENTRY(cmpxchg8b_emu) ret ENDPROC(cmpxchg8b_emu) +EXPORT_SYMBOL(cmpxchg8b_emu) diff --git a/arch/x86/lib/copy_page_64.S b/arch/x86/lib/copy_page_64.S index 24ef1c2104d42..e8508156c99d5 100644 --- a/arch/x86/lib/copy_page_64.S +++ b/arch/x86/lib/copy_page_64.S @@ -3,6 +3,7 @@ #include #include #include +#include /* * Some CPUs run faster using the string copy instructions (sane microcode). @@ -17,6 +18,7 @@ ENTRY(copy_page) rep movsq ret ENDPROC(copy_page) +EXPORT_SYMBOL(copy_page) ENTRY(copy_page_regs) subq $2*8, %rsp diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index bf603ebbfd8e2..d376e4b48f881 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -14,6 +14,7 @@ #include #include #include +#include /* Standard copy_to_user with segment limit checking */ ENTRY(_copy_to_user) @@ -29,6 +30,7 @@ ENTRY(_copy_to_user) "jmp copy_user_enhanced_fast_string", \ X86_FEATURE_ERMS ENDPROC(_copy_to_user) +EXPORT_SYMBOL(_copy_to_user) /* Standard copy_from_user with segment limit checking */ ENTRY(_copy_from_user) @@ -44,6 +46,8 @@ ENTRY(_copy_from_user) "jmp copy_user_enhanced_fast_string", \ X86_FEATURE_ERMS ENDPROC(_copy_from_user) +EXPORT_SYMBOL(_copy_from_user) + .section .fixup,"ax" /* must zero dest */ @@ -155,6 +159,7 @@ ENTRY(copy_user_generic_unrolled) _ASM_EXTABLE(21b,50b) _ASM_EXTABLE(22b,50b) ENDPROC(copy_user_generic_unrolled) +EXPORT_SYMBOL(copy_user_generic_unrolled) /* Some CPUs run faster using the string copy instructions. * This is also a lot simpler. Use them when possible. @@ -200,6 +205,7 @@ ENTRY(copy_user_generic_string) _ASM_EXTABLE(1b,11b) _ASM_EXTABLE(3b,12b) ENDPROC(copy_user_generic_string) +EXPORT_SYMBOL(copy_user_generic_string) /* * Some CPUs are adding enhanced REP MOVSB/STOSB instructions. @@ -229,6 +235,7 @@ ENTRY(copy_user_enhanced_fast_string) _ASM_EXTABLE(1b,12b) ENDPROC(copy_user_enhanced_fast_string) +EXPORT_SYMBOL(copy_user_enhanced_fast_string) /* * copy_user_nocache - Uncached memory copy with exception handling @@ -379,3 +386,4 @@ ENTRY(__copy_user_nocache) _ASM_EXTABLE(40b,.L_fixup_1b_copy) _ASM_EXTABLE(41b,.L_fixup_1b_copy) ENDPROC(__copy_user_nocache) +EXPORT_SYMBOL(__copy_user_nocache) diff --git a/arch/x86/lib/csum-partial_64.c b/arch/x86/lib/csum-partial_64.c index 9a7fe6a70491e..378e5d5bf9b13 100644 --- a/arch/x86/lib/csum-partial_64.c +++ b/arch/x86/lib/csum-partial_64.c @@ -135,6 +135,7 @@ __wsum csum_partial(const void *buff, int len, __wsum sum) return (__force __wsum)add32_with_carry(do_csum(buff, len), (__force u32)sum); } +EXPORT_SYMBOL(csum_partial); /* * this routine is used for miscellaneous IP-like checksums, mainly diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S index 0ef5128c2de8b..37b62d4121481 100644 --- a/arch/x86/lib/getuser.S +++ b/arch/x86/lib/getuser.S @@ -32,6 +32,7 @@ #include #include #include +#include .text ENTRY(__get_user_1) @@ -44,6 +45,7 @@ ENTRY(__get_user_1) ASM_CLAC ret ENDPROC(__get_user_1) +EXPORT_SYMBOL(__get_user_1) ENTRY(__get_user_2) add $1,%_ASM_AX @@ -57,6 +59,7 @@ ENTRY(__get_user_2) ASM_CLAC ret ENDPROC(__get_user_2) +EXPORT_SYMBOL(__get_user_2) ENTRY(__get_user_4) add $3,%_ASM_AX @@ -70,6 +73,7 @@ ENTRY(__get_user_4) ASM_CLAC ret ENDPROC(__get_user_4) +EXPORT_SYMBOL(__get_user_4) ENTRY(__get_user_8) #ifdef CONFIG_X86_64 @@ -97,6 +101,7 @@ ENTRY(__get_user_8) ret #endif ENDPROC(__get_user_8) +EXPORT_SYMBOL(__get_user_8) bad_get_user: diff --git a/arch/x86/lib/hweight.S b/arch/x86/lib/hweight.S index 02de3d74d2c5b..9d4ca92074270 100644 --- a/arch/x86/lib/hweight.S +++ b/arch/x86/lib/hweight.S @@ -1,4 +1,5 @@ #include +#include #include @@ -32,6 +33,7 @@ ENTRY(__sw_hweight32) __ASM_SIZE(pop,) %__ASM_REG(dx) ret ENDPROC(__sw_hweight32) +EXPORT_SYMBOL(__sw_hweight32) ENTRY(__sw_hweight64) #ifdef CONFIG_X86_64 @@ -75,3 +77,4 @@ ENTRY(__sw_hweight64) ret #endif ENDPROC(__sw_hweight64) +EXPORT_SYMBOL(__sw_hweight64) diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index 2ec0b0abbfaa8..94c917af96880 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S @@ -4,6 +4,7 @@ #include #include #include +#include /* * We build a jump to memcpy_orig by default which gets NOPped out on @@ -40,6 +41,8 @@ ENTRY(memcpy) ret ENDPROC(memcpy) ENDPROC(__memcpy) +EXPORT_SYMBOL(memcpy) +EXPORT_SYMBOL(__memcpy) /* * memcpy_erms() - enhanced fast string memcpy. This is faster and @@ -274,6 +277,7 @@ ENTRY(memcpy_mcsafe) xorq %rax, %rax ret ENDPROC(memcpy_mcsafe) +EXPORT_SYMBOL_GPL(memcpy_mcsafe) .section .fixup, "ax" /* Return -EFAULT for any failure */ diff --git a/arch/x86/lib/memmove_64.S b/arch/x86/lib/memmove_64.S index 90ce01bee00c1..15de86cd15b05 100644 --- a/arch/x86/lib/memmove_64.S +++ b/arch/x86/lib/memmove_64.S @@ -8,6 +8,7 @@ #include #include #include +#include #undef memmove @@ -207,3 +208,5 @@ ENTRY(__memmove) retq ENDPROC(__memmove) ENDPROC(memmove) +EXPORT_SYMBOL(__memmove) +EXPORT_SYMBOL(memmove) diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S index e1229ecd2a820..55b95db30a61c 100644 --- a/arch/x86/lib/memset_64.S +++ b/arch/x86/lib/memset_64.S @@ -3,6 +3,7 @@ #include #include #include +#include .weak memset @@ -43,6 +44,8 @@ ENTRY(__memset) ret ENDPROC(memset) ENDPROC(__memset) +EXPORT_SYMBOL(memset) +EXPORT_SYMBOL(__memset) /* * ISO C memset - set a memory block to a byte value. This function uses diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S index c891ece81e5b1..cd5d716d28978 100644 --- a/arch/x86/lib/putuser.S +++ b/arch/x86/lib/putuser.S @@ -15,6 +15,7 @@ #include #include #include +#include /* @@ -43,6 +44,7 @@ ENTRY(__put_user_1) xor %eax,%eax EXIT ENDPROC(__put_user_1) +EXPORT_SYMBOL(__put_user_1) ENTRY(__put_user_2) ENTER @@ -55,6 +57,7 @@ ENTRY(__put_user_2) xor %eax,%eax EXIT ENDPROC(__put_user_2) +EXPORT_SYMBOL(__put_user_2) ENTRY(__put_user_4) ENTER @@ -67,6 +70,7 @@ ENTRY(__put_user_4) xor %eax,%eax EXIT ENDPROC(__put_user_4) +EXPORT_SYMBOL(__put_user_4) ENTRY(__put_user_8) ENTER @@ -82,6 +86,7 @@ ENTRY(__put_user_8) xor %eax,%eax EXIT ENDPROC(__put_user_8) +EXPORT_SYMBOL(__put_user_8) bad_put_user: movl $-EFAULT,%eax diff --git a/arch/x86/lib/strstr_32.c b/arch/x86/lib/strstr_32.c index 8e2d55f754bff..a03b1c750bfed 100644 --- a/arch/x86/lib/strstr_32.c +++ b/arch/x86/lib/strstr_32.c @@ -1,4 +1,5 @@ #include +#include char *strstr(const char *cs, const char *ct) { @@ -28,4 +29,4 @@ __asm__ __volatile__( : "dx", "di"); return __res; } - +EXPORT_SYMBOL(strstr); diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile index 3ee2bb6b440bd..e7e7055a86589 100644 --- a/arch/x86/um/Makefile +++ b/arch/x86/um/Makefile @@ -8,7 +8,7 @@ else BITS := 64 endif -obj-y = bug.o bugs_$(BITS).o delay.o fault.o ksyms.o ldt.o \ +obj-y = bug.o bugs_$(BITS).o delay.o fault.o ldt.o \ ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ stub_$(BITS).o stub_segv.o \ sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \ diff --git a/arch/x86/um/checksum_32.S b/arch/x86/um/checksum_32.S index fa4b8b9841ff7..b9933eb9274ae 100644 --- a/arch/x86/um/checksum_32.S +++ b/arch/x86/um/checksum_32.S @@ -27,6 +27,7 @@ #include #include +#include /* * computes a partial checksum, e.g. for TCP/UDP fragments @@ -214,3 +215,4 @@ csum_partial: ret #endif + EXPORT_SYMBOL(csum_partial) diff --git a/arch/x86/um/ksyms.c b/arch/x86/um/ksyms.c deleted file mode 100644 index 2e8f43ec62147..0000000000000 --- a/arch/x86/um/ksyms.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include - -#ifndef CONFIG_X86_32 -/*XXX: we need them because they would be exported by x86_64 */ -#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4 -EXPORT_SYMBOL(memcpy); -#else -EXPORT_SYMBOL(__memcpy); -#endif -#endif -EXPORT_SYMBOL(csum_partial); -- GitLab From 00fc0e0dda6286407f3854cd71a125f519a5689c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 11 Jan 2016 09:51:29 -0500 Subject: [PATCH 0006/1167] alpha: move exports to actual definitions Signed-off-by: Al Viro --- arch/alpha/include/asm/Kbuild | 1 + arch/alpha/kernel/Makefile | 2 +- arch/alpha/kernel/alpha_ksyms.c | 102 --------------------------- arch/alpha/kernel/machvec_impl.h | 6 +- arch/alpha/kernel/setup.c | 1 + arch/alpha/lib/callback_srm.S | 5 ++ arch/alpha/lib/checksum.c | 3 + arch/alpha/lib/clear_page.S | 3 +- arch/alpha/lib/clear_user.S | 2 + arch/alpha/lib/copy_page.S | 3 +- arch/alpha/lib/copy_user.S | 3 + arch/alpha/lib/csum_ipv6_magic.S | 2 + arch/alpha/lib/csum_partial_copy.c | 2 + arch/alpha/lib/dec_and_lock.c | 2 + arch/alpha/lib/divide.S | 3 + arch/alpha/lib/ev6-clear_page.S | 3 +- arch/alpha/lib/ev6-clear_user.S | 3 +- arch/alpha/lib/ev6-copy_page.S | 3 +- arch/alpha/lib/ev6-copy_user.S | 3 +- arch/alpha/lib/ev6-csum_ipv6_magic.S | 2 + arch/alpha/lib/ev6-divide.S | 3 + arch/alpha/lib/ev6-memchr.S | 3 +- arch/alpha/lib/ev6-memcpy.S | 3 +- arch/alpha/lib/ev6-memset.S | 7 +- arch/alpha/lib/ev67-strcat.S | 3 +- arch/alpha/lib/ev67-strchr.S | 3 +- arch/alpha/lib/ev67-strlen.S | 3 +- arch/alpha/lib/ev67-strncat.S | 3 +- arch/alpha/lib/ev67-strrchr.S | 3 +- arch/alpha/lib/fpreg.c | 7 ++ arch/alpha/lib/memchr.S | 3 +- arch/alpha/lib/memcpy.c | 5 +- arch/alpha/lib/memmove.S | 3 +- arch/alpha/lib/memset.S | 7 +- arch/alpha/lib/strcat.S | 2 + arch/alpha/lib/strchr.S | 3 +- arch/alpha/lib/strcpy.S | 3 +- arch/alpha/lib/strlen.S | 3 +- arch/alpha/lib/strncat.S | 3 +- arch/alpha/lib/strncpy.S | 3 +- arch/alpha/lib/strrchr.S | 3 +- 41 files changed, 99 insertions(+), 131 deletions(-) delete mode 100644 arch/alpha/kernel/alpha_ksyms.c diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild index ffd9cf5ec8c40..bf8475ce85ee2 100644 --- a/arch/alpha/include/asm/Kbuild +++ b/arch/alpha/include/asm/Kbuild @@ -3,6 +3,7 @@ generic-y += clkdev.h generic-y += cputime.h generic-y += exec.h +generic-y += export.h generic-y += irq_work.h generic-y += mcs_spinlock.h generic-y += mm-arch-hooks.h diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 3ecac0106c8a1..8ce13d7a2ad38 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -8,7 +8,7 @@ ccflags-y := -Wno-sign-compare obj-y := entry.o traps.o process.o osf_sys.o irq.o \ irq_alpha.o signal.o setup.o ptrace.o time.o \ - alpha_ksyms.o systbls.o err_common.o io.o + systbls.o err_common.o io.o obj-$(CONFIG_VGA_HOSE) += console.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c deleted file mode 100644 index f4c7ab6f43b0d..0000000000000 --- a/arch/alpha/kernel/alpha_ksyms.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * linux/arch/alpha/kernel/alpha_ksyms.c - * - * Export the alpha-specific functions that are needed for loadable - * modules. - */ - -#include -#include -#include -#include -#include -#include - -#include - -/* these are C runtime functions with special calling conventions: */ -extern void __divl (void); -extern void __reml (void); -extern void __divq (void); -extern void __remq (void); -extern void __divlu (void); -extern void __remlu (void); -extern void __divqu (void); -extern void __remqu (void); - -EXPORT_SYMBOL(alpha_mv); -EXPORT_SYMBOL(callback_getenv); -EXPORT_SYMBOL(callback_setenv); -EXPORT_SYMBOL(callback_save_env); - -/* platform dependent support */ -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strcpy); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strncpy); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(__memcpy); -EXPORT_SYMBOL(__memset); -EXPORT_SYMBOL(___memset); -EXPORT_SYMBOL(__memsetw); -EXPORT_SYMBOL(__constant_c_memset); -EXPORT_SYMBOL(copy_page); -EXPORT_SYMBOL(clear_page); - -EXPORT_SYMBOL(alpha_read_fp_reg); -EXPORT_SYMBOL(alpha_read_fp_reg_s); -EXPORT_SYMBOL(alpha_write_fp_reg); -EXPORT_SYMBOL(alpha_write_fp_reg_s); - -/* Networking helper routines. */ -EXPORT_SYMBOL(csum_tcpudp_magic); -EXPORT_SYMBOL(ip_compute_csum); -EXPORT_SYMBOL(ip_fast_csum); -EXPORT_SYMBOL(csum_partial_copy_nocheck); -EXPORT_SYMBOL(csum_partial_copy_from_user); -EXPORT_SYMBOL(csum_ipv6_magic); - -#ifdef CONFIG_MATHEMU_MODULE -extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); -extern long (*alpha_fp_emul) (unsigned long pc); -EXPORT_SYMBOL(alpha_fp_emul_imprecise); -EXPORT_SYMBOL(alpha_fp_emul); -#endif - -/* - * The following are specially called from the uaccess assembly stubs. - */ -EXPORT_SYMBOL(__copy_user); -EXPORT_SYMBOL(__do_clear_user); - -/* - * SMP-specific symbols. - */ - -#ifdef CONFIG_SMP -EXPORT_SYMBOL(_atomic_dec_and_lock); -#endif /* CONFIG_SMP */ - -/* - * The following are special because they're not called - * explicitly (the C compiler or assembler generates them in - * response to division operations). Fortunately, their - * interface isn't gonna change any time soon now, so it's OK - * to leave it out of version control. - */ -# undef memcpy -# undef memset -EXPORT_SYMBOL(__divl); -EXPORT_SYMBOL(__divlu); -EXPORT_SYMBOL(__divq); -EXPORT_SYMBOL(__divqu); -EXPORT_SYMBOL(__reml); -EXPORT_SYMBOL(__remlu); -EXPORT_SYMBOL(__remq); -EXPORT_SYMBOL(__remqu); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memchr); diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h index d3398f6ab74c2..b7d69604b6d2e 100644 --- a/arch/alpha/kernel/machvec_impl.h +++ b/arch/alpha/kernel/machvec_impl.h @@ -144,9 +144,11 @@ else beforehand. Fine. We'll do it ourselves. */ #if 0 #define ALIAS_MV(system) \ - struct alpha_machine_vector alpha_mv __attribute__((alias(#system "_mv"))); + struct alpha_machine_vector alpha_mv __attribute__((alias(#system "_mv"))); \ + EXPORT_SYMBOL(alpha_mv); #else #define ALIAS_MV(system) \ - asm(".global alpha_mv\nalpha_mv = " #system "_mv"); + asm(".global alpha_mv\nalpha_mv = " #system "_mv"); \ + EXPORT_SYMBOL(alpha_mv); #endif #endif /* GENERIC */ diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index b20af76f12c1d..4811e54069fcf 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -115,6 +115,7 @@ unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE; #ifdef CONFIG_ALPHA_GENERIC struct alpha_machine_vector alpha_mv; +EXPORT_SYMBOL(alpha_mv); #endif #ifndef alpha_using_srm diff --git a/arch/alpha/lib/callback_srm.S b/arch/alpha/lib/callback_srm.S index 8804bec2c6448..6093addc931a5 100644 --- a/arch/alpha/lib/callback_srm.S +++ b/arch/alpha/lib/callback_srm.S @@ -3,6 +3,7 @@ */ #include +#include .text #define HWRPB_CRB_OFFSET 0xc0 @@ -92,6 +93,10 @@ CALLBACK(reset_env, CCB_RESET_ENV, 4) CALLBACK(save_env, CCB_SAVE_ENV, 1) CALLBACK(pswitch, CCB_PSWITCH, 3) CALLBACK(bios_emul, CCB_BIOS_EMUL, 5) + +EXPORT_SYMBOL(callback_getenv) +EXPORT_SYMBOL(callback_setenv) +EXPORT_SYMBOL(callback_save_env) .data __alpha_using_srm: # For use by bootpheader diff --git a/arch/alpha/lib/checksum.c b/arch/alpha/lib/checksum.c index 377f9e34eb970..b57f8007db14f 100644 --- a/arch/alpha/lib/checksum.c +++ b/arch/alpha/lib/checksum.c @@ -48,6 +48,7 @@ __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, (__force u64)saddr + (__force u64)daddr + (__force u64)sum + ((len + proto) << 8)); } +EXPORT_SYMBOL(csum_tcpudp_magic); __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __wsum sum) @@ -144,6 +145,7 @@ __sum16 ip_fast_csum(const void *iph, unsigned int ihl) { return (__force __sum16)~do_csum(iph,ihl*4); } +EXPORT_SYMBOL(ip_fast_csum); /* * computes the checksum of a memory block at buff, length len, @@ -178,3 +180,4 @@ __sum16 ip_compute_csum(const void *buff, int len) { return (__force __sum16)~from64to16(do_csum(buff,len)); } +EXPORT_SYMBOL(ip_compute_csum); diff --git a/arch/alpha/lib/clear_page.S b/arch/alpha/lib/clear_page.S index a221ae266e290..263d7393c0e7a 100644 --- a/arch/alpha/lib/clear_page.S +++ b/arch/alpha/lib/clear_page.S @@ -3,7 +3,7 @@ * * Zero an entire page. */ - +#include .text .align 4 .global clear_page @@ -37,3 +37,4 @@ clear_page: nop .end clear_page + EXPORT_SYMBOL(clear_page) diff --git a/arch/alpha/lib/clear_user.S b/arch/alpha/lib/clear_user.S index 8860316c19576..bf5b931866ba1 100644 --- a/arch/alpha/lib/clear_user.S +++ b/arch/alpha/lib/clear_user.S @@ -24,6 +24,7 @@ * Clobbers: * $1,$2,$3,$4,$5,$6 */ +#include /* Allow an exception for an insn; exit if we get one. */ #define EX(x,y...) \ @@ -111,3 +112,4 @@ $exception: ret $31, ($28), 1 # .. e1 : .end __do_clear_user + EXPORT_SYMBOL(__do_clear_user) diff --git a/arch/alpha/lib/copy_page.S b/arch/alpha/lib/copy_page.S index 9f3b97459cc64..2ee0bd0508c59 100644 --- a/arch/alpha/lib/copy_page.S +++ b/arch/alpha/lib/copy_page.S @@ -3,7 +3,7 @@ * * Copy an entire page. */ - +#include .text .align 4 .global copy_page @@ -47,3 +47,4 @@ copy_page: nop .end copy_page + EXPORT_SYMBOL(copy_page) diff --git a/arch/alpha/lib/copy_user.S b/arch/alpha/lib/copy_user.S index 6f3fab9eb4344..2238068b1b409 100644 --- a/arch/alpha/lib/copy_user.S +++ b/arch/alpha/lib/copy_user.S @@ -26,6 +26,8 @@ * $1,$2,$3,$4,$5,$6,$7 */ +#include + /* Allow an exception for an insn; exit if we get one. */ #define EXI(x,y...) \ 99: x,##y; \ @@ -143,3 +145,4 @@ $101: ret $31,($28),1 .end __copy_user +EXPORT_SYMBOL(__copy_user) diff --git a/arch/alpha/lib/csum_ipv6_magic.S b/arch/alpha/lib/csum_ipv6_magic.S index 2c2acb96deb68..e74b4544b0cce 100644 --- a/arch/alpha/lib/csum_ipv6_magic.S +++ b/arch/alpha/lib/csum_ipv6_magic.S @@ -12,6 +12,7 @@ * added by Ivan Kokshaysky */ +#include .globl csum_ipv6_magic .align 4 .ent csum_ipv6_magic @@ -113,3 +114,4 @@ csum_ipv6_magic: ret # .. e1 : .end csum_ipv6_magic + EXPORT_SYMBOL(csum_ipv6_magic) diff --git a/arch/alpha/lib/csum_partial_copy.c b/arch/alpha/lib/csum_partial_copy.c index 5675dca8dbb14..b4ff3b683bcd5 100644 --- a/arch/alpha/lib/csum_partial_copy.c +++ b/arch/alpha/lib/csum_partial_copy.c @@ -374,6 +374,7 @@ csum_partial_copy_from_user(const void __user *src, void *dst, int len, } return (__force __wsum)checksum; } +EXPORT_SYMBOL(csum_partial_copy_from_user); __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) @@ -386,3 +387,4 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) set_fs(oldfs); return checksum; } +EXPORT_SYMBOL(csum_partial_copy_nocheck); diff --git a/arch/alpha/lib/dec_and_lock.c b/arch/alpha/lib/dec_and_lock.c index f9f5fe830e9f9..4221b40167eed 100644 --- a/arch/alpha/lib/dec_and_lock.c +++ b/arch/alpha/lib/dec_and_lock.c @@ -7,6 +7,7 @@ #include #include +#include asm (".text \n\ .global _atomic_dec_and_lock \n\ @@ -39,3 +40,4 @@ static int __used atomic_dec_and_lock_1(atomic_t *atomic, spinlock_t *lock) spin_unlock(lock); return 0; } +EXPORT_SYMBOL(_atomic_dec_and_lock); diff --git a/arch/alpha/lib/divide.S b/arch/alpha/lib/divide.S index 2d1a0484a99e0..1e33bd1276213 100644 --- a/arch/alpha/lib/divide.S +++ b/arch/alpha/lib/divide.S @@ -45,6 +45,7 @@ * $28 - compare status */ +#include #define halt .long 0 /* @@ -151,6 +152,7 @@ ufunction: addq $30,STACK,$30 ret $31,($23),1 .end ufunction +EXPORT_SYMBOL(ufunction) /* * Uhh.. Ugly signed division. I'd rather not have it at all, but @@ -193,3 +195,4 @@ sfunction: addq $30,STACK,$30 ret $31,($23),1 .end sfunction +EXPORT_SYMBOL(sfunction) diff --git a/arch/alpha/lib/ev6-clear_page.S b/arch/alpha/lib/ev6-clear_page.S index adf4f7be0e2b6..abe99e69a1945 100644 --- a/arch/alpha/lib/ev6-clear_page.S +++ b/arch/alpha/lib/ev6-clear_page.S @@ -3,7 +3,7 @@ * * Zero an entire page. */ - +#include .text .align 4 .global clear_page @@ -52,3 +52,4 @@ clear_page: nop .end clear_page + EXPORT_SYMBOL(clear_page) diff --git a/arch/alpha/lib/ev6-clear_user.S b/arch/alpha/lib/ev6-clear_user.S index 4f42a16b7f53d..05bef6b505984 100644 --- a/arch/alpha/lib/ev6-clear_user.S +++ b/arch/alpha/lib/ev6-clear_user.S @@ -43,6 +43,7 @@ * want to leave a hole (and we also want to avoid repeating lots of work) */ +#include /* Allow an exception for an insn; exit if we get one. */ #define EX(x,y...) \ 99: x,##y; \ @@ -222,4 +223,4 @@ $exception: # Destination for exception recovery(?) nop # .. E .. .. : ret $31, ($28), 1 # L0 .. .. .. : L U L U .end __do_clear_user - + EXPORT_SYMBOL(__do_clear_user) diff --git a/arch/alpha/lib/ev6-copy_page.S b/arch/alpha/lib/ev6-copy_page.S index b789db1927544..77935061bddbb 100644 --- a/arch/alpha/lib/ev6-copy_page.S +++ b/arch/alpha/lib/ev6-copy_page.S @@ -56,7 +56,7 @@ destination pages are in the dcache, but it is my guess that this is less important than the dcache miss case. */ - +#include .text .align 4 .global copy_page @@ -201,3 +201,4 @@ copy_page: nop .end copy_page + EXPORT_SYMBOL(copy_page) diff --git a/arch/alpha/lib/ev6-copy_user.S b/arch/alpha/lib/ev6-copy_user.S index db42ffe9c350b..debcc3b6b7049 100644 --- a/arch/alpha/lib/ev6-copy_user.S +++ b/arch/alpha/lib/ev6-copy_user.S @@ -37,6 +37,7 @@ * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 */ +#include /* Allow an exception for an insn; exit if we get one. */ #define EXI(x,y...) \ 99: x,##y; \ @@ -256,4 +257,4 @@ $101: ret $31,($28),1 # L0 .end __copy_user - + EXPORT_SYMBOL(__copy_user) diff --git a/arch/alpha/lib/ev6-csum_ipv6_magic.S b/arch/alpha/lib/ev6-csum_ipv6_magic.S index fc0bc399f872d..de62627ac4fe1 100644 --- a/arch/alpha/lib/ev6-csum_ipv6_magic.S +++ b/arch/alpha/lib/ev6-csum_ipv6_magic.S @@ -52,6 +52,7 @@ * may cause additional delay in rare cases (load-load replay traps). */ +#include .globl csum_ipv6_magic .align 4 .ent csum_ipv6_magic @@ -148,3 +149,4 @@ csum_ipv6_magic: ret # L0 : L U L U .end csum_ipv6_magic + EXPORT_SYMBOL(csum_ipv6_magic) diff --git a/arch/alpha/lib/ev6-divide.S b/arch/alpha/lib/ev6-divide.S index 2a82b9be93fa2..d18dc0e96e3d7 100644 --- a/arch/alpha/lib/ev6-divide.S +++ b/arch/alpha/lib/ev6-divide.S @@ -55,6 +55,7 @@ * Try not to change the actual algorithm if possible for consistency. */ +#include #define halt .long 0 /* @@ -205,6 +206,7 @@ ufunction: addq $30,STACK,$30 # E : ret $31,($23),1 # L0 : L U U L .end ufunction +EXPORT_SYMBOL(ufunction) /* * Uhh.. Ugly signed division. I'd rather not have it at all, but @@ -257,3 +259,4 @@ sfunction: addq $30,STACK,$30 # E : ret $31,($23),1 # L0 : L U U L .end sfunction +EXPORT_SYMBOL(sfunction) diff --git a/arch/alpha/lib/ev6-memchr.S b/arch/alpha/lib/ev6-memchr.S index 1a5f71b9d8b10..419adc53ccb4e 100644 --- a/arch/alpha/lib/ev6-memchr.S +++ b/arch/alpha/lib/ev6-memchr.S @@ -27,7 +27,7 @@ * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 * Try not to change the actual algorithm if possible for consistency. */ - +#include .set noreorder .set noat @@ -189,3 +189,4 @@ $not_found: ret # L0 : .end memchr + EXPORT_SYMBOL(memchr) diff --git a/arch/alpha/lib/ev6-memcpy.S b/arch/alpha/lib/ev6-memcpy.S index 52b37b0f2af51..b19798b2efc09 100644 --- a/arch/alpha/lib/ev6-memcpy.S +++ b/arch/alpha/lib/ev6-memcpy.S @@ -19,7 +19,7 @@ * Temp usage notes: * $1,$2, - scratch */ - +#include .set noreorder .set noat @@ -242,6 +242,7 @@ $nomoredata: nop # E : .end memcpy + EXPORT_SYMBOL(memcpy) /* For backwards module compatibility. */ __memcpy = memcpy diff --git a/arch/alpha/lib/ev6-memset.S b/arch/alpha/lib/ev6-memset.S index 356bb2fdd7056..fed21c6893e8e 100644 --- a/arch/alpha/lib/ev6-memset.S +++ b/arch/alpha/lib/ev6-memset.S @@ -26,7 +26,7 @@ * as fixes will need to be made in multiple places. The performance gain * is worth it. */ - +#include .set noat .set noreorder .text @@ -229,6 +229,7 @@ end_b: nop ret $31,($26),1 # L0 : .end ___memset + EXPORT_SYMBOL(___memset) /* * This is the original body of code, prior to replication and @@ -406,6 +407,7 @@ end: nop ret $31,($26),1 # L0 : .end __constant_c_memset + EXPORT_SYMBOL(__constant_c_memset) /* * This is a replicant of the __constant_c_memset code, rescheduled @@ -594,6 +596,9 @@ end_w: ret $31,($26),1 # L0 : .end __memsetw + EXPORT_SYMBOL(__memsetw) memset = ___memset __memset = ___memset + EXPORT_SYMBOL(memset) + EXPORT_SYMBOL(__memset) diff --git a/arch/alpha/lib/ev67-strcat.S b/arch/alpha/lib/ev67-strcat.S index c426fe3ed72f4..b69f60419be1b 100644 --- a/arch/alpha/lib/ev67-strcat.S +++ b/arch/alpha/lib/ev67-strcat.S @@ -19,7 +19,7 @@ * string once. */ - +#include .text .align 4 @@ -52,3 +52,4 @@ $found: cttz $2, $3 # U0 : br __stxcpy # L0 : .end strcat + EXPORT_SYMBOL(strcat) diff --git a/arch/alpha/lib/ev67-strchr.S b/arch/alpha/lib/ev67-strchr.S index fbb7b4ffade9e..ea8f2f35db9ce 100644 --- a/arch/alpha/lib/ev67-strchr.S +++ b/arch/alpha/lib/ev67-strchr.S @@ -15,7 +15,7 @@ * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 * Try not to change the actual algorithm if possible for consistency. */ - +#include #include .set noreorder @@ -86,3 +86,4 @@ $found: negq t0, t1 # E : clear all but least set bit ret # L0 : .end strchr + EXPORT_SYMBOL(strchr) diff --git a/arch/alpha/lib/ev67-strlen.S b/arch/alpha/lib/ev67-strlen.S index 503928072523e..736fd41884a8c 100644 --- a/arch/alpha/lib/ev67-strlen.S +++ b/arch/alpha/lib/ev67-strlen.S @@ -17,7 +17,7 @@ * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 */ - +#include .set noreorder .set noat @@ -47,3 +47,4 @@ $found: ret $31, ($26) # L0 : .end strlen + EXPORT_SYMBOL(strlen) diff --git a/arch/alpha/lib/ev67-strncat.S b/arch/alpha/lib/ev67-strncat.S index 4ae716cd2bfbf..cd35cbade73ae 100644 --- a/arch/alpha/lib/ev67-strncat.S +++ b/arch/alpha/lib/ev67-strncat.S @@ -20,7 +20,7 @@ * Try not to change the actual algorithm if possible for consistency. */ - +#include .text .align 4 @@ -92,3 +92,4 @@ $zerocount: ret # L0 : .end strncat + EXPORT_SYMBOL(strncat) diff --git a/arch/alpha/lib/ev67-strrchr.S b/arch/alpha/lib/ev67-strrchr.S index dd0d8c6b9f59f..747455f0328cf 100644 --- a/arch/alpha/lib/ev67-strrchr.S +++ b/arch/alpha/lib/ev67-strrchr.S @@ -18,7 +18,7 @@ * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 */ - +#include #include .set noreorder @@ -107,3 +107,4 @@ $eos: nop .end strrchr + EXPORT_SYMBOL(strrchr) diff --git a/arch/alpha/lib/fpreg.c b/arch/alpha/lib/fpreg.c index 05017ba34c3cc..4aa6dbfa14eec 100644 --- a/arch/alpha/lib/fpreg.c +++ b/arch/alpha/lib/fpreg.c @@ -4,6 +4,9 @@ * (C) Copyright 1998 Linus Torvalds */ +#include +#include + #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67) #define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val)); #else @@ -52,6 +55,7 @@ alpha_read_fp_reg (unsigned long reg) } return val; } +EXPORT_SYMBOL(alpha_read_fp_reg); #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67) #define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val)); @@ -97,6 +101,7 @@ alpha_write_fp_reg (unsigned long reg, unsigned long val) case 31: LDT(31, val); break; } } +EXPORT_SYMBOL(alpha_write_fp_reg); #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67) #define STS(reg,val) asm volatile ("ftois $f"#reg",%0" : "=r"(val)); @@ -146,6 +151,7 @@ alpha_read_fp_reg_s (unsigned long reg) } return val; } +EXPORT_SYMBOL(alpha_read_fp_reg_s); #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67) #define LDS(reg,val) asm volatile ("itofs %0,$f"#reg : : "r"(val)); @@ -191,3 +197,4 @@ alpha_write_fp_reg_s (unsigned long reg, unsigned long val) case 31: LDS(31, val); break; } } +EXPORT_SYMBOL(alpha_write_fp_reg_s); diff --git a/arch/alpha/lib/memchr.S b/arch/alpha/lib/memchr.S index 14427eeb555e6..c13d3eca2e059 100644 --- a/arch/alpha/lib/memchr.S +++ b/arch/alpha/lib/memchr.S @@ -31,7 +31,7 @@ For correctness consider that: - only minimum number of quadwords may be accessed - the third argument is an unsigned long */ - +#include .set noreorder .set noat @@ -162,3 +162,4 @@ $not_found: ret # .. e1 : .end memchr + EXPORT_SYMBOL(memchr) diff --git a/arch/alpha/lib/memcpy.c b/arch/alpha/lib/memcpy.c index 64083fc732389..57d9291ad172c 100644 --- a/arch/alpha/lib/memcpy.c +++ b/arch/alpha/lib/memcpy.c @@ -16,6 +16,7 @@ */ #include +#include /* * This should be done in one go with ldq_u*2/mask/stq_u. Do it @@ -158,6 +159,4 @@ void * memcpy(void * dest, const void *src, size_t n) __memcpy_unaligned_up ((unsigned long) dest, (unsigned long) src, n); return dest; } - -/* For backward modules compatibility, define __memcpy. */ -asm("__memcpy = memcpy; .globl __memcpy"); +EXPORT_SYMBOL(memcpy); diff --git a/arch/alpha/lib/memmove.S b/arch/alpha/lib/memmove.S index eb3b6e02242f4..6872c85cb5e54 100644 --- a/arch/alpha/lib/memmove.S +++ b/arch/alpha/lib/memmove.S @@ -6,7 +6,7 @@ * This is hand-massaged output from the original memcpy.c. We defer to * memcpy whenever possible; the backwards copy loops are not unrolled. */ - +#include .set noat .set noreorder .text @@ -179,3 +179,4 @@ $egress: nop .end memmove + EXPORT_SYMBOL(memmove) diff --git a/arch/alpha/lib/memset.S b/arch/alpha/lib/memset.S index 76ccc6d1f364d..89a26f5e89de3 100644 --- a/arch/alpha/lib/memset.S +++ b/arch/alpha/lib/memset.S @@ -13,7 +13,7 @@ * The scheduling comments are according to the EV5 documentation (and done by * hand, so they might well be incorrect, please do tell me about it..) */ - +#include .set noat .set noreorder .text @@ -106,6 +106,8 @@ within_one_quad: end: ret $31,($26),1 /* E1 */ .end ___memset +EXPORT_SYMBOL(___memset) +EXPORT_SYMBOL(__constant_c_memset) .align 5 .ent __memsetw @@ -122,6 +124,9 @@ __memsetw: br __constant_c_memset /* .. E1 */ .end __memsetw +EXPORT_SYMBOL(__memsetw) memset = ___memset __memset = ___memset + EXPORT_SYMBOL(memset) + EXPORT_SYMBOL(__memset) diff --git a/arch/alpha/lib/strcat.S b/arch/alpha/lib/strcat.S index 393f50384878f..249837b03d4b9 100644 --- a/arch/alpha/lib/strcat.S +++ b/arch/alpha/lib/strcat.S @@ -4,6 +4,7 @@ * * Append a null-terminated string from SRC to DST. */ +#include .text @@ -50,3 +51,4 @@ $found: negq $2, $3 # clear all but least set bit br __stxcpy .end strcat +EXPORT_SYMBOL(strcat); diff --git a/arch/alpha/lib/strchr.S b/arch/alpha/lib/strchr.S index 011a175e83292..7412a173ea393 100644 --- a/arch/alpha/lib/strchr.S +++ b/arch/alpha/lib/strchr.S @@ -5,7 +5,7 @@ * Return the address of a given character within a null-terminated * string, or null if it is not found. */ - +#include #include .set noreorder @@ -68,3 +68,4 @@ $retnull: ret # .. e1 : .end strchr + EXPORT_SYMBOL(strchr) diff --git a/arch/alpha/lib/strcpy.S b/arch/alpha/lib/strcpy.S index e0728e4ad21fd..98deae1e4d085 100644 --- a/arch/alpha/lib/strcpy.S +++ b/arch/alpha/lib/strcpy.S @@ -5,7 +5,7 @@ * Copy a null-terminated string from SRC to DST. Return a pointer * to the null-terminator in the source. */ - +#include .text .align 3 @@ -21,3 +21,4 @@ strcpy: br __stxcpy # do the copy .end strcpy + EXPORT_SYMBOL(strcpy) diff --git a/arch/alpha/lib/strlen.S b/arch/alpha/lib/strlen.S index fe63353de152d..79c416f71bacd 100644 --- a/arch/alpha/lib/strlen.S +++ b/arch/alpha/lib/strlen.S @@ -11,7 +11,7 @@ * do this instead of the 9 instructions that * binary search needs). */ - +#include .set noreorder .set noat @@ -55,3 +55,4 @@ done: subq $0, $16, $0 ret $31, ($26) .end strlen + EXPORT_SYMBOL(strlen) diff --git a/arch/alpha/lib/strncat.S b/arch/alpha/lib/strncat.S index a8278163c9720..6c29ea60869ae 100644 --- a/arch/alpha/lib/strncat.S +++ b/arch/alpha/lib/strncat.S @@ -9,7 +9,7 @@ * past count, whereas libc may write to count+1. This follows the generic * implementation in lib/string.c and is, IMHO, more sensible. */ - +#include .text .align 3 @@ -82,3 +82,4 @@ $zerocount: ret .end strncat + EXPORT_SYMBOL(strncat) diff --git a/arch/alpha/lib/strncpy.S b/arch/alpha/lib/strncpy.S index a46f7f3ad8c73..e102cf1567ddd 100644 --- a/arch/alpha/lib/strncpy.S +++ b/arch/alpha/lib/strncpy.S @@ -10,7 +10,7 @@ * version has cropped that bit o' nastiness as well as assuming that * __stxncpy is in range of a branch. */ - +#include .set noat .set noreorder @@ -79,3 +79,4 @@ $zerolen: ret .end strncpy + EXPORT_SYMBOL(strncpy) diff --git a/arch/alpha/lib/strrchr.S b/arch/alpha/lib/strrchr.S index 1970dc07cfd12..4bc6cb4b9812e 100644 --- a/arch/alpha/lib/strrchr.S +++ b/arch/alpha/lib/strrchr.S @@ -5,7 +5,7 @@ * Return the address of the last occurrence of a given character * within a null-terminated string, or null if it is not found. */ - +#include #include .set noreorder @@ -85,3 +85,4 @@ $retnull: ret # .. e1 : .end strrchr + EXPORT_SYMBOL(strrchr) -- GitLab From d13ffb5630443e6112df0263969cbdfc8ab9ab57 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 11 Jan 2016 13:04:04 -0500 Subject: [PATCH 0007/1167] m68k: move exports to definitions Acked-by: Geert Uytterhoeven Signed-off-by: Al Viro --- arch/m68k/include/asm/export.h | 3 +++ arch/m68k/kernel/Makefile | 2 +- arch/m68k/kernel/m68k_ksyms.c | 32 -------------------------------- arch/m68k/lib/ashldi3.c | 4 ++++ arch/m68k/lib/ashrdi3.c | 4 ++++ arch/m68k/lib/divsi3.S | 3 +++ arch/m68k/lib/lshrdi3.c | 4 ++++ arch/m68k/lib/modsi3.S | 3 +++ arch/m68k/lib/muldi3.c | 4 ++++ arch/m68k/lib/mulsi3.S | 4 ++-- arch/m68k/lib/udivsi3.S | 4 ++-- arch/m68k/lib/umodsi3.S | 4 ++-- 12 files changed, 32 insertions(+), 39 deletions(-) create mode 100644 arch/m68k/include/asm/export.h delete mode 100644 arch/m68k/kernel/m68k_ksyms.c diff --git a/arch/m68k/include/asm/export.h b/arch/m68k/include/asm/export.h new file mode 100644 index 0000000000000..0af20f48bd076 --- /dev/null +++ b/arch/m68k/include/asm/export.h @@ -0,0 +1,3 @@ +#define KSYM_ALIGN 2 +#define KCRC_ALIGN 2 +#include diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index e47778f8588da..3600500beab50 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -13,7 +13,7 @@ extra-$(CONFIG_SUN3X) := head.o extra-$(CONFIG_SUN3) := sun3-head.o extra-y += vmlinux.lds -obj-y := entry.o irq.o m68k_ksyms.o module.o process.o ptrace.o +obj-y := entry.o irq.o module.o process.o ptrace.o obj-y += setup.o signal.o sys_m68k.o syscalltable.o time.o traps.o obj-$(CONFIG_MMU_MOTOROLA) += ints.o vectors.o diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c deleted file mode 100644 index 774c1bd59c365..0000000000000 --- a/arch/m68k/kernel/m68k_ksyms.c +++ /dev/null @@ -1,32 +0,0 @@ -#include - -asmlinkage long long __ashldi3 (long long, int); -asmlinkage long long __ashrdi3 (long long, int); -asmlinkage long long __lshrdi3 (long long, int); -asmlinkage long long __muldi3 (long long, long long); - -/* The following are special because they're not called - explicitly (the C compiler generates them). Fortunately, - their interface isn't gonna change any time soon now, so - it's OK to leave it out of version control. */ -EXPORT_SYMBOL(__ashldi3); -EXPORT_SYMBOL(__ashrdi3); -EXPORT_SYMBOL(__lshrdi3); -EXPORT_SYMBOL(__muldi3); - -#if defined(CONFIG_CPU_HAS_NO_MULDIV64) -/* - * Simpler 68k and ColdFire parts also need a few other gcc functions. - */ -extern long long __divsi3(long long, long long); -extern long long __modsi3(long long, long long); -extern long long __mulsi3(long long, long long); -extern long long __udivsi3(long long, long long); -extern long long __umodsi3(long long, long long); - -EXPORT_SYMBOL(__divsi3); -EXPORT_SYMBOL(__modsi3); -EXPORT_SYMBOL(__mulsi3); -EXPORT_SYMBOL(__udivsi3); -EXPORT_SYMBOL(__umodsi3); -#endif diff --git a/arch/m68k/lib/ashldi3.c b/arch/m68k/lib/ashldi3.c index 37234c2df47f6..8dffd36ec4f24 100644 --- a/arch/m68k/lib/ashldi3.c +++ b/arch/m68k/lib/ashldi3.c @@ -13,6 +13,9 @@ 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. */ +#include +#include + #define BITS_PER_UNIT 8 typedef int SItype __attribute__ ((mode (SI))); @@ -55,3 +58,4 @@ __ashldi3 (DItype u, word_type b) return w.ll; } +EXPORT_SYMBOL(__ashldi3); diff --git a/arch/m68k/lib/ashrdi3.c b/arch/m68k/lib/ashrdi3.c index 1d59345f36c63..e6565a3ee2c37 100644 --- a/arch/m68k/lib/ashrdi3.c +++ b/arch/m68k/lib/ashrdi3.c @@ -13,6 +13,9 @@ 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. */ +#include +#include + #define BITS_PER_UNIT 8 typedef int SItype __attribute__ ((mode (SI))); @@ -56,3 +59,4 @@ __ashrdi3 (DItype u, word_type b) return w.ll; } +EXPORT_SYMBOL(__ashrdi3); diff --git a/arch/m68k/lib/divsi3.S b/arch/m68k/lib/divsi3.S index 2c0ec85ac6615..3a2143f51631a 100644 --- a/arch/m68k/lib/divsi3.S +++ b/arch/m68k/lib/divsi3.S @@ -33,6 +33,8 @@ General Public License for more details. */ D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 */ +#include + /* These are predefined by new versions of GNU cpp. */ #ifndef __USER_LABEL_PREFIX__ @@ -118,3 +120,4 @@ L2: movel d1, sp@- L3: movel sp@+, d2 rts + EXPORT_SYMBOL(__divsi3) diff --git a/arch/m68k/lib/lshrdi3.c b/arch/m68k/lib/lshrdi3.c index 49e1ec8f2cc27..039779737c7d2 100644 --- a/arch/m68k/lib/lshrdi3.c +++ b/arch/m68k/lib/lshrdi3.c @@ -13,6 +13,9 @@ 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. */ +#include +#include + #define BITS_PER_UNIT 8 typedef int SItype __attribute__ ((mode (SI))); @@ -55,3 +58,4 @@ __lshrdi3 (DItype u, word_type b) return w.ll; } +EXPORT_SYMBOL(__lshrdi3); diff --git a/arch/m68k/lib/modsi3.S b/arch/m68k/lib/modsi3.S index 1d9e0efdf31d2..1c967649a4e0e 100644 --- a/arch/m68k/lib/modsi3.S +++ b/arch/m68k/lib/modsi3.S @@ -33,6 +33,8 @@ General Public License for more details. */ D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 */ +#include + /* These are predefined by new versions of GNU cpp. */ #ifndef __USER_LABEL_PREFIX__ @@ -106,3 +108,4 @@ SYM (__modsi3): movel d1, d0 rts + EXPORT_SYMBOL(__modsi3) diff --git a/arch/m68k/lib/muldi3.c b/arch/m68k/lib/muldi3.c index 9006d15b87218..6459af5b2af0a 100644 --- a/arch/m68k/lib/muldi3.c +++ b/arch/m68k/lib/muldi3.c @@ -14,6 +14,9 @@ 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. */ +#include +#include + #ifdef CONFIG_CPU_HAS_NO_MULDIV64 #define SI_TYPE_SIZE 32 @@ -90,3 +93,4 @@ __muldi3 (DItype u, DItype v) return w.ll; } +EXPORT_SYMBOL(__muldi3); diff --git a/arch/m68k/lib/mulsi3.S b/arch/m68k/lib/mulsi3.S index c39ad4e738e9a..855675e69a8a2 100644 --- a/arch/m68k/lib/mulsi3.S +++ b/arch/m68k/lib/mulsi3.S @@ -32,7 +32,7 @@ General Public License for more details. */ Some of this code comes from MINIX, via the folks at ericsson. D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 */ - +#include /* These are predefined by new versions of GNU cpp. */ #ifndef __USER_LABEL_PREFIX__ @@ -102,4 +102,4 @@ SYM (__mulsi3): addl d1, d0 rts - + EXPORT_SYMBOL(__mulsi3) diff --git a/arch/m68k/lib/udivsi3.S b/arch/m68k/lib/udivsi3.S index 35a5446572a5e..78440ae513bf3 100644 --- a/arch/m68k/lib/udivsi3.S +++ b/arch/m68k/lib/udivsi3.S @@ -32,7 +32,7 @@ General Public License for more details. */ Some of this code comes from MINIX, via the folks at ericsson. D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 */ - +#include /* These are predefined by new versions of GNU cpp. */ #ifndef __USER_LABEL_PREFIX__ @@ -154,4 +154,4 @@ L2: subql IMM (1),d4 unlk a6 | and return rts #endif /* __mcf5200__ || __mcoldfire__ */ - + EXPORT_SYMBOL(__udivsi3) diff --git a/arch/m68k/lib/umodsi3.S b/arch/m68k/lib/umodsi3.S index 099da514a8fd8..b6fd11f58948d 100644 --- a/arch/m68k/lib/umodsi3.S +++ b/arch/m68k/lib/umodsi3.S @@ -32,7 +32,7 @@ General Public License for more details. */ Some of this code comes from MINIX, via the folks at ericsson. D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 */ - +#include /* These are predefined by new versions of GNU cpp. */ #ifndef __USER_LABEL_PREFIX__ @@ -105,4 +105,4 @@ SYM (__umodsi3): subl d0, d1 /* d1 = a - (a/b)*b */ movel d1, d0 rts - + EXPORT_SYMBOL(__umodsi3) -- GitLab From 711f5df7bf3ae7657e15edf76d671042c051ce95 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 12 Jan 2016 13:30:03 -0500 Subject: [PATCH 0008/1167] s390: move exports to definitions Acked-by: Heiko Carstens Signed-off-by: Al Viro --- arch/s390/include/asm/Kbuild | 1 + arch/s390/kernel/Makefile | 2 +- arch/s390/kernel/entry.S | 6 ++++++ arch/s390/kernel/mcount.S | 3 +++ arch/s390/kernel/s390_ksyms.c | 15 --------------- arch/s390/lib/mem.S | 3 +++ 6 files changed, 14 insertions(+), 16 deletions(-) delete mode 100644 arch/s390/kernel/s390_ksyms.c diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild index 9043d2e1e2ae0..20f196b82a6e6 100644 --- a/arch/s390/include/asm/Kbuild +++ b/arch/s390/include/asm/Kbuild @@ -1,6 +1,7 @@ generic-y += clkdev.h +generic-y += export.h generic-y += irq_work.h generic-y += mcs_spinlock.h generic-y += mm-arch-hooks.h diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 3234817c7d471..e2a63f0c6e3ea 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -58,7 +58,7 @@ obj-y += entry.o reipl.o relocate_kernel.o extra-y += head.o head64.o vmlinux.lds -obj-$(CONFIG_MODULES) += s390_ksyms.o module.o +obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SCHED_TOPOLOGY) += topology.o obj-$(CONFIG_HIBERNATION) += suspend.o swsusp.o diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index c51650a1ed167..49a30737addef 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -23,6 +23,7 @@ #include #include #include +#include __PT_R0 = __PT_GPRS __PT_R1 = __PT_GPRS + 8 @@ -259,6 +260,8 @@ sie_exit: EX_TABLE(.Lrewind_pad,.Lsie_fault) EX_TABLE(sie_exit,.Lsie_fault) +EXPORT_SYMBOL(sie64a) +EXPORT_SYMBOL(sie_exit) #endif /* @@ -825,6 +828,9 @@ ENTRY(save_fpu_regs) oi __LC_CPU_FLAGS+7,_CIF_FPU br %r14 .Lsave_fpu_regs_end: +#if IS_ENABLED(CONFIG_KVM) +EXPORT_SYMBOL(save_fpu_regs) +#endif /* * Load floating-point controls and floating-point or vector registers. diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index e499370fbccb3..9a17e4475d277 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S @@ -9,6 +9,7 @@ #include #include #include +#include .section .kprobes.text, "ax" @@ -23,6 +24,8 @@ ENTRY(ftrace_stub) ENTRY(_mcount) br %r14 +EXPORT_SYMBOL(_mcount) + ENTRY(ftrace_caller) .globl ftrace_regs_caller .set ftrace_regs_caller,ftrace_caller diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c deleted file mode 100644 index e67453b73c3c7..0000000000000 --- a/arch/s390/kernel/s390_ksyms.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include -#include - -#ifdef CONFIG_FUNCTION_TRACER -EXPORT_SYMBOL(_mcount); -#endif -#if IS_ENABLED(CONFIG_KVM) -EXPORT_SYMBOL(sie64a); -EXPORT_SYMBOL(sie_exit); -EXPORT_SYMBOL(save_fpu_regs); -#endif -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memset); diff --git a/arch/s390/lib/mem.S b/arch/s390/lib/mem.S index c6d553e85ab11..be9fa65bfac4e 100644 --- a/arch/s390/lib/mem.S +++ b/arch/s390/lib/mem.S @@ -5,6 +5,7 @@ */ #include +#include /* * memset implementation @@ -60,6 +61,7 @@ ENTRY(memset) xc 0(1,%r1),0(%r1) .Lmemset_mvc: mvc 1(1,%r1),0(%r1) +EXPORT_SYMBOL(memset) /* * memcpy implementation @@ -86,3 +88,4 @@ ENTRY(memcpy) j .Lmemcpy_rest .Lmemcpy_mvc: mvc 0(1,%r1),0(%r3) +EXPORT_SYMBOL(memcpy) -- GitLab From 4dd1837d7589f468ed109556513f476e7a7f9121 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 13 Jan 2016 13:46:22 -0500 Subject: [PATCH 0009/1167] arm: move exports to definitions Signed-off-by: Al Viro --- arch/arm/include/asm/Kbuild | 1 + arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/armksyms.c | 183 -------------------------- arch/arm/kernel/entry-ftrace.S | 3 + arch/arm/kernel/head.S | 3 + arch/arm/kernel/smccc-call.S | 3 + arch/arm/lib/ashldi3.S | 3 + arch/arm/lib/ashrdi3.S | 3 + arch/arm/lib/bitops.h | 5 + arch/arm/lib/bswapsdi2.S | 3 + arch/arm/lib/clear_user.S | 4 + arch/arm/lib/copy_from_user.S | 2 + arch/arm/lib/copy_page.S | 2 + arch/arm/lib/copy_to_user.S | 4 + arch/arm/lib/csumipv6.S | 3 +- arch/arm/lib/csumpartial.S | 2 + arch/arm/lib/csumpartialcopy.S | 1 + arch/arm/lib/csumpartialcopygeneric.S | 2 + arch/arm/lib/csumpartialcopyuser.S | 1 + arch/arm/lib/delay.c | 2 + arch/arm/lib/div64.S | 2 + arch/arm/lib/findbit.S | 9 ++ arch/arm/lib/getuser.S | 9 ++ arch/arm/lib/io-readsb.S | 2 + arch/arm/lib/io-readsl.S | 2 + arch/arm/lib/io-readsw-armv3.S | 3 +- arch/arm/lib/io-readsw-armv4.S | 2 + arch/arm/lib/io-writesb.S | 2 + arch/arm/lib/io-writesl.S | 2 + arch/arm/lib/io-writesw-armv3.S | 2 + arch/arm/lib/io-writesw-armv4.S | 2 + arch/arm/lib/lib1funcs.S | 9 ++ arch/arm/lib/lshrdi3.S | 3 + arch/arm/lib/memchr.S | 2 + arch/arm/lib/memcpy.S | 3 + arch/arm/lib/memmove.S | 2 + arch/arm/lib/memset.S | 3 + arch/arm/lib/memzero.S | 2 + arch/arm/lib/muldi3.S | 3 + arch/arm/lib/putuser.S | 5 + arch/arm/lib/strchr.S | 2 + arch/arm/lib/strrchr.S | 2 + arch/arm/lib/uaccess_with_memcpy.c | 3 + arch/arm/lib/ucmpdi2.S | 3 + arch/arm/mach-imx/Makefile | 1 - arch/arm/mach-imx/ssi-fiq-ksym.c | 20 --- arch/arm/mach-imx/ssi-fiq.S | 7 +- 47 files changed, 131 insertions(+), 208 deletions(-) delete mode 100644 arch/arm/kernel/armksyms.c delete mode 100644 arch/arm/mach-imx/ssi-fiq-ksym.c diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index 55e0e3ea9cb6b..0745538b26d3f 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@ -8,6 +8,7 @@ generic-y += early_ioremap.h generic-y += emergency-restart.h generic-y += errno.h generic-y += exec.h +generic-y += export.h generic-y += ioctl.h generic-y += ipcbuf.h generic-y += irq_regs.h diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index ad325a8c7e1e5..68c2c097cffea 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -33,7 +33,7 @@ endif obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_FIQ) += fiq.o fiqasm.o -obj-$(CONFIG_MODULES) += armksyms.o module.o +obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_ARM_MODULE_PLTS) += module-plts.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c deleted file mode 100644 index 7e45f69a0ddc9..0000000000000 --- a/arch/arm/kernel/armksyms.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * linux/arch/arm/kernel/armksyms.c - * - * Copyright (C) 2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* - * libgcc functions - functions that are used internally by the - * compiler... (prototypes are not correct though, but that - * doesn't really matter since they're not versioned). - */ -extern void __ashldi3(void); -extern void __ashrdi3(void); -extern void __divsi3(void); -extern void __lshrdi3(void); -extern void __modsi3(void); -extern void __muldi3(void); -extern void __ucmpdi2(void); -extern void __udivsi3(void); -extern void __umodsi3(void); -extern void __do_div64(void); -extern void __bswapsi2(void); -extern void __bswapdi2(void); - -extern void __aeabi_idiv(void); -extern void __aeabi_idivmod(void); -extern void __aeabi_lasr(void); -extern void __aeabi_llsl(void); -extern void __aeabi_llsr(void); -extern void __aeabi_lmul(void); -extern void __aeabi_uidiv(void); -extern void __aeabi_uidivmod(void); -extern void __aeabi_ulcmp(void); - -extern void fpundefinstr(void); - -void mmioset(void *, unsigned int, size_t); -void mmiocpy(void *, const void *, size_t); - - /* platform dependent support */ -EXPORT_SYMBOL(arm_delay_ops); - - /* networking */ -EXPORT_SYMBOL(csum_partial); -EXPORT_SYMBOL(csum_partial_copy_from_user); -EXPORT_SYMBOL(csum_partial_copy_nocheck); -EXPORT_SYMBOL(__csum_ipv6_magic); - - /* io */ -#ifndef __raw_readsb -EXPORT_SYMBOL(__raw_readsb); -#endif -#ifndef __raw_readsw -EXPORT_SYMBOL(__raw_readsw); -#endif -#ifndef __raw_readsl -EXPORT_SYMBOL(__raw_readsl); -#endif -#ifndef __raw_writesb -EXPORT_SYMBOL(__raw_writesb); -#endif -#ifndef __raw_writesw -EXPORT_SYMBOL(__raw_writesw); -#endif -#ifndef __raw_writesl -EXPORT_SYMBOL(__raw_writesl); -#endif - - /* string / mem functions */ -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memchr); -EXPORT_SYMBOL(__memzero); - -EXPORT_SYMBOL(mmioset); -EXPORT_SYMBOL(mmiocpy); - -#ifdef CONFIG_MMU -EXPORT_SYMBOL(copy_page); - -EXPORT_SYMBOL(arm_copy_from_user); -EXPORT_SYMBOL(arm_copy_to_user); -EXPORT_SYMBOL(arm_clear_user); - -EXPORT_SYMBOL(__get_user_1); -EXPORT_SYMBOL(__get_user_2); -EXPORT_SYMBOL(__get_user_4); -EXPORT_SYMBOL(__get_user_8); - -#ifdef __ARMEB__ -EXPORT_SYMBOL(__get_user_64t_1); -EXPORT_SYMBOL(__get_user_64t_2); -EXPORT_SYMBOL(__get_user_64t_4); -EXPORT_SYMBOL(__get_user_32t_8); -#endif - -EXPORT_SYMBOL(__put_user_1); -EXPORT_SYMBOL(__put_user_2); -EXPORT_SYMBOL(__put_user_4); -EXPORT_SYMBOL(__put_user_8); -#endif - - /* gcc lib functions */ -EXPORT_SYMBOL(__ashldi3); -EXPORT_SYMBOL(__ashrdi3); -EXPORT_SYMBOL(__divsi3); -EXPORT_SYMBOL(__lshrdi3); -EXPORT_SYMBOL(__modsi3); -EXPORT_SYMBOL(__muldi3); -EXPORT_SYMBOL(__ucmpdi2); -EXPORT_SYMBOL(__udivsi3); -EXPORT_SYMBOL(__umodsi3); -EXPORT_SYMBOL(__do_div64); -EXPORT_SYMBOL(__bswapsi2); -EXPORT_SYMBOL(__bswapdi2); - -#ifdef CONFIG_AEABI -EXPORT_SYMBOL(__aeabi_idiv); -EXPORT_SYMBOL(__aeabi_idivmod); -EXPORT_SYMBOL(__aeabi_lasr); -EXPORT_SYMBOL(__aeabi_llsl); -EXPORT_SYMBOL(__aeabi_llsr); -EXPORT_SYMBOL(__aeabi_lmul); -EXPORT_SYMBOL(__aeabi_uidiv); -EXPORT_SYMBOL(__aeabi_uidivmod); -EXPORT_SYMBOL(__aeabi_ulcmp); -#endif - - /* bitops */ -EXPORT_SYMBOL(_set_bit); -EXPORT_SYMBOL(_test_and_set_bit); -EXPORT_SYMBOL(_clear_bit); -EXPORT_SYMBOL(_test_and_clear_bit); -EXPORT_SYMBOL(_change_bit); -EXPORT_SYMBOL(_test_and_change_bit); -EXPORT_SYMBOL(_find_first_zero_bit_le); -EXPORT_SYMBOL(_find_next_zero_bit_le); -EXPORT_SYMBOL(_find_first_bit_le); -EXPORT_SYMBOL(_find_next_bit_le); - -#ifdef __ARMEB__ -EXPORT_SYMBOL(_find_first_zero_bit_be); -EXPORT_SYMBOL(_find_next_zero_bit_be); -EXPORT_SYMBOL(_find_first_bit_be); -EXPORT_SYMBOL(_find_next_bit_be); -#endif - -#ifdef CONFIG_FUNCTION_TRACER -#ifdef CONFIG_OLD_MCOUNT -EXPORT_SYMBOL(mcount); -#endif -EXPORT_SYMBOL(__gnu_mcount_nc); -#endif - -#ifdef CONFIG_ARM_PATCH_PHYS_VIRT -EXPORT_SYMBOL(__pv_phys_pfn_offset); -EXPORT_SYMBOL(__pv_offset); -#endif - -#ifdef CONFIG_HAVE_ARM_SMCCC -EXPORT_SYMBOL(arm_smccc_smc); -EXPORT_SYMBOL(arm_smccc_hvc); -#endif diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S index c73c4030ca5dd..b629d3f11c3da 100644 --- a/arch/arm/kernel/entry-ftrace.S +++ b/arch/arm/kernel/entry-ftrace.S @@ -7,6 +7,7 @@ #include #include #include +#include #include "entry-header.S" @@ -153,6 +154,7 @@ ENTRY(mcount) __mcount _old #endif ENDPROC(mcount) +EXPORT_SYMBOL(mcount) #ifdef CONFIG_DYNAMIC_FTRACE ENTRY(ftrace_caller_old) @@ -205,6 +207,7 @@ UNWIND(.fnstart) #endif UNWIND(.fnend) ENDPROC(__gnu_mcount_nc) +EXPORT_SYMBOL(__gnu_mcount_nc) #ifdef CONFIG_DYNAMIC_FTRACE ENTRY(ftrace_caller) diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 04286fd9e09ce..f41cee4c57467 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -22,6 +22,7 @@ #include #include #include +#include #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_SEMIHOSTING) #include CONFIG_DEBUG_LL_INCLUDE @@ -727,6 +728,8 @@ __pv_phys_pfn_offset: __pv_offset: .quad 0 .size __pv_offset, . -__pv_offset +EXPORT_SYMBOL(__pv_phys_pfn_offset) +EXPORT_SYMBOL(__pv_offset) #endif #include "head-common.S" diff --git a/arch/arm/kernel/smccc-call.S b/arch/arm/kernel/smccc-call.S index 2e48b674aab19..37669e7e13afd 100644 --- a/arch/arm/kernel/smccc-call.S +++ b/arch/arm/kernel/smccc-call.S @@ -16,6 +16,7 @@ #include #include #include +#include /* * Wrap c macros in asm macros to delay expansion until after the @@ -51,6 +52,7 @@ UNWIND( .fnend) ENTRY(arm_smccc_smc) SMCCC SMCCC_SMC ENDPROC(arm_smccc_smc) +EXPORT_SYMBOL(arm_smccc_smc) /* * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, @@ -60,3 +62,4 @@ ENDPROC(arm_smccc_smc) ENTRY(arm_smccc_hvc) SMCCC SMCCC_HVC ENDPROC(arm_smccc_hvc) +EXPORT_SYMBOL(arm_smccc_hvc) diff --git a/arch/arm/lib/ashldi3.S b/arch/arm/lib/ashldi3.S index b05e95840651d..a7e7de89bd75c 100644 --- a/arch/arm/lib/ashldi3.S +++ b/arch/arm/lib/ashldi3.S @@ -28,6 +28,7 @@ Boston, MA 02110-1301, USA. */ #include #include +#include #ifdef __ARMEB__ #define al r1 @@ -52,3 +53,5 @@ ENTRY(__aeabi_llsl) ENDPROC(__ashldi3) ENDPROC(__aeabi_llsl) +EXPORT_SYMBOL(__ashldi3) +EXPORT_SYMBOL(__aeabi_llsl) diff --git a/arch/arm/lib/ashrdi3.S b/arch/arm/lib/ashrdi3.S index 275d7d2341a4e..490336e42518d 100644 --- a/arch/arm/lib/ashrdi3.S +++ b/arch/arm/lib/ashrdi3.S @@ -28,6 +28,7 @@ Boston, MA 02110-1301, USA. */ #include #include +#include #ifdef __ARMEB__ #define al r1 @@ -52,3 +53,5 @@ ENTRY(__aeabi_lasr) ENDPROC(__ashrdi3) ENDPROC(__aeabi_lasr) +EXPORT_SYMBOL(__ashrdi3) +EXPORT_SYMBOL(__aeabi_lasr) diff --git a/arch/arm/lib/bitops.h b/arch/arm/lib/bitops.h index 7d807cfd8ef57..df06638b327cd 100644 --- a/arch/arm/lib/bitops.h +++ b/arch/arm/lib/bitops.h @@ -1,5 +1,6 @@ #include #include +#include #if __LINUX_ARM_ARCH__ >= 6 .macro bitop, name, instr @@ -25,6 +26,7 @@ UNWIND( .fnstart ) bx lr UNWIND( .fnend ) ENDPROC(\name ) +EXPORT_SYMBOL(\name ) .endm .macro testop, name, instr, store @@ -55,6 +57,7 @@ UNWIND( .fnstart ) 2: bx lr UNWIND( .fnend ) ENDPROC(\name ) +EXPORT_SYMBOL(\name ) .endm #else .macro bitop, name, instr @@ -74,6 +77,7 @@ UNWIND( .fnstart ) ret lr UNWIND( .fnend ) ENDPROC(\name ) +EXPORT_SYMBOL(\name ) .endm /** @@ -102,5 +106,6 @@ UNWIND( .fnstart ) ret lr UNWIND( .fnend ) ENDPROC(\name ) +EXPORT_SYMBOL(\name ) .endm #endif diff --git a/arch/arm/lib/bswapsdi2.S b/arch/arm/lib/bswapsdi2.S index 07cda737bb11f..f05f78247304b 100644 --- a/arch/arm/lib/bswapsdi2.S +++ b/arch/arm/lib/bswapsdi2.S @@ -1,5 +1,6 @@ #include #include +#include #if __LINUX_ARM_ARCH__ >= 6 ENTRY(__bswapsi2) @@ -35,3 +36,5 @@ ENTRY(__bswapdi2) ret lr ENDPROC(__bswapdi2) #endif +EXPORT_SYMBOL(__bswapsi2) +EXPORT_SYMBOL(__bswapdi2) diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S index e936352ccb001..b566154f5cf4e 100644 --- a/arch/arm/lib/clear_user.S +++ b/arch/arm/lib/clear_user.S @@ -10,6 +10,7 @@ #include #include #include +#include .text @@ -50,6 +51,9 @@ USER( strnebt r2, [r0]) UNWIND(.fnend) ENDPROC(arm_clear_user) ENDPROC(__clear_user_std) +#ifndef CONFIG_UACCESS_WITH_MEMCPY +EXPORT_SYMBOL(arm_clear_user) +#endif .pushsection .text.fixup,"ax" .align 0 diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index 1512bebfbf1b1..f549c57ea4359 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S @@ -13,6 +13,7 @@ #include #include #include +#include /* * Prototype: @@ -94,6 +95,7 @@ ENTRY(arm_copy_from_user) #include "copy_template.S" ENDPROC(arm_copy_from_user) +EXPORT_SYMBOL(arm_copy_from_user) .pushsection .fixup,"ax" .align 0 diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S index 6ee2f6706f869..d97851d4af7a4 100644 --- a/arch/arm/lib/copy_page.S +++ b/arch/arm/lib/copy_page.S @@ -13,6 +13,7 @@ #include #include #include +#include #define COPY_COUNT (PAGE_SZ / (2 * L1_CACHE_BYTES) PLD( -1 )) @@ -45,3 +46,4 @@ ENTRY(copy_page) PLD( beq 2b ) ldmfd sp!, {r4, pc} @ 3 ENDPROC(copy_page) +EXPORT_SYMBOL(copy_page) diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S index caf5019d8161e..592c179112d1b 100644 --- a/arch/arm/lib/copy_to_user.S +++ b/arch/arm/lib/copy_to_user.S @@ -13,6 +13,7 @@ #include #include #include +#include /* * Prototype: @@ -99,6 +100,9 @@ WEAK(arm_copy_to_user) ENDPROC(arm_copy_to_user) ENDPROC(__copy_to_user_std) +#ifndef CONFIG_UACCESS_WITH_MEMCPY +EXPORT_SYMBOL(arm_copy_to_user) +#endif .pushsection .text.fixup,"ax" .align 0 diff --git a/arch/arm/lib/csumipv6.S b/arch/arm/lib/csumipv6.S index 3ac6ef01bc43a..68603b5ee5372 100644 --- a/arch/arm/lib/csumipv6.S +++ b/arch/arm/lib/csumipv6.S @@ -9,6 +9,7 @@ */ #include #include +#include .text @@ -30,4 +31,4 @@ ENTRY(__csum_ipv6_magic) adcs r0, r0, #0 ldmfd sp!, {pc} ENDPROC(__csum_ipv6_magic) - +EXPORT_SYMBOL(__csum_ipv6_magic) diff --git a/arch/arm/lib/csumpartial.S b/arch/arm/lib/csumpartial.S index 984e0f29d548b..830b20e81c378 100644 --- a/arch/arm/lib/csumpartial.S +++ b/arch/arm/lib/csumpartial.S @@ -9,6 +9,7 @@ */ #include #include +#include .text @@ -140,3 +141,4 @@ ENTRY(csum_partial) bne 4b b .Lless4 ENDPROC(csum_partial) +EXPORT_SYMBOL(csum_partial) diff --git a/arch/arm/lib/csumpartialcopy.S b/arch/arm/lib/csumpartialcopy.S index d03fc71fc88c9..9c3383fed129b 100644 --- a/arch/arm/lib/csumpartialcopy.S +++ b/arch/arm/lib/csumpartialcopy.S @@ -49,5 +49,6 @@ #define FN_ENTRY ENTRY(csum_partial_copy_nocheck) #define FN_EXIT ENDPROC(csum_partial_copy_nocheck) +#define FN_EXPORT EXPORT_SYMBOL(csum_partial_copy_nocheck) #include "csumpartialcopygeneric.S" diff --git a/arch/arm/lib/csumpartialcopygeneric.S b/arch/arm/lib/csumpartialcopygeneric.S index 10b45909610ca..8b94d20e51d17 100644 --- a/arch/arm/lib/csumpartialcopygeneric.S +++ b/arch/arm/lib/csumpartialcopygeneric.S @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ #include +#include /* * unsigned int @@ -331,3 +332,4 @@ FN_ENTRY mov r5, r4, get_byte_1 b .Lexit FN_EXIT +FN_EXPORT diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S index 1712f132b80d2..5d495edf3d83f 100644 --- a/arch/arm/lib/csumpartialcopyuser.S +++ b/arch/arm/lib/csumpartialcopyuser.S @@ -73,6 +73,7 @@ #define FN_ENTRY ENTRY(csum_partial_copy_from_user) #define FN_EXIT ENDPROC(csum_partial_copy_from_user) +#define FN_EXPORT EXPORT_SYMBOL(csum_partial_copy_from_user) #include "csumpartialcopygeneric.S" diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c index 8044591dca729..e60ce1549759c 100644 --- a/arch/arm/lib/delay.c +++ b/arch/arm/lib/delay.c @@ -24,6 +24,7 @@ #include #include #include +#include #include /* @@ -34,6 +35,7 @@ struct arm_delay_ops arm_delay_ops = { .const_udelay = __loop_const_udelay, .udelay = __loop_udelay, }; +EXPORT_SYMBOL(arm_delay_ops); static const struct delay_timer *delay_timer; static bool delay_calibrated; diff --git a/arch/arm/lib/div64.S b/arch/arm/lib/div64.S index a9eafe4981eb8..0c9e1c18fc9ec 100644 --- a/arch/arm/lib/div64.S +++ b/arch/arm/lib/div64.S @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef __ARMEB__ #define xh r0 @@ -210,3 +211,4 @@ Ldiv0_64: UNWIND(.fnend) ENDPROC(__do_div64) +EXPORT_SYMBOL(__do_div64) diff --git a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S index 7848780e88347..26302b8cd38fb 100644 --- a/arch/arm/lib/findbit.S +++ b/arch/arm/lib/findbit.S @@ -15,6 +15,7 @@ */ #include #include +#include .text /* @@ -37,6 +38,7 @@ ENTRY(_find_first_zero_bit_le) 3: mov r0, r1 @ no free bits ret lr ENDPROC(_find_first_zero_bit_le) +EXPORT_SYMBOL(_find_first_zero_bit_le) /* * Purpose : Find next 'zero' bit @@ -57,6 +59,7 @@ ENTRY(_find_next_zero_bit_le) add r2, r2, #1 @ align bit pointer b 2b @ loop for next bit ENDPROC(_find_next_zero_bit_le) +EXPORT_SYMBOL(_find_next_zero_bit_le) /* * Purpose : Find a 'one' bit @@ -78,6 +81,7 @@ ENTRY(_find_first_bit_le) 3: mov r0, r1 @ no free bits ret lr ENDPROC(_find_first_bit_le) +EXPORT_SYMBOL(_find_first_bit_le) /* * Purpose : Find next 'one' bit @@ -97,6 +101,7 @@ ENTRY(_find_next_bit_le) add r2, r2, #1 @ align bit pointer b 2b @ loop for next bit ENDPROC(_find_next_bit_le) +EXPORT_SYMBOL(_find_next_bit_le) #ifdef __ARMEB__ @@ -116,6 +121,7 @@ ENTRY(_find_first_zero_bit_be) 3: mov r0, r1 @ no free bits ret lr ENDPROC(_find_first_zero_bit_be) +EXPORT_SYMBOL(_find_first_zero_bit_be) ENTRY(_find_next_zero_bit_be) teq r1, #0 @@ -133,6 +139,7 @@ ENTRY(_find_next_zero_bit_be) add r2, r2, #1 @ align bit pointer b 2b @ loop for next bit ENDPROC(_find_next_zero_bit_be) +EXPORT_SYMBOL(_find_next_zero_bit_be) ENTRY(_find_first_bit_be) teq r1, #0 @@ -150,6 +157,7 @@ ENTRY(_find_first_bit_be) 3: mov r0, r1 @ no free bits ret lr ENDPROC(_find_first_bit_be) +EXPORT_SYMBOL(_find_first_bit_be) ENTRY(_find_next_bit_be) teq r1, #0 @@ -166,6 +174,7 @@ ENTRY(_find_next_bit_be) add r2, r2, #1 @ align bit pointer b 2b @ loop for next bit ENDPROC(_find_next_bit_be) +EXPORT_SYMBOL(_find_next_bit_be) #endif diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index 8ecfd15c3a024..9d09a38e73af3 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -31,6 +31,7 @@ #include #include #include +#include ENTRY(__get_user_1) check_uaccess r0, 1, r1, r2, __get_user_bad @@ -38,6 +39,7 @@ ENTRY(__get_user_1) mov r0, #0 ret lr ENDPROC(__get_user_1) +EXPORT_SYMBOL(__get_user_1) ENTRY(__get_user_2) check_uaccess r0, 2, r1, r2, __get_user_bad @@ -58,6 +60,7 @@ rb .req r0 mov r0, #0 ret lr ENDPROC(__get_user_2) +EXPORT_SYMBOL(__get_user_2) ENTRY(__get_user_4) check_uaccess r0, 4, r1, r2, __get_user_bad @@ -65,6 +68,7 @@ ENTRY(__get_user_4) mov r0, #0 ret lr ENDPROC(__get_user_4) +EXPORT_SYMBOL(__get_user_4) ENTRY(__get_user_8) check_uaccess r0, 8, r1, r2, __get_user_bad @@ -78,6 +82,7 @@ ENTRY(__get_user_8) mov r0, #0 ret lr ENDPROC(__get_user_8) +EXPORT_SYMBOL(__get_user_8) #ifdef __ARMEB__ ENTRY(__get_user_32t_8) @@ -91,6 +96,7 @@ ENTRY(__get_user_32t_8) mov r0, #0 ret lr ENDPROC(__get_user_32t_8) +EXPORT_SYMBOL(__get_user_32t_8) ENTRY(__get_user_64t_1) check_uaccess r0, 1, r1, r2, __get_user_bad8 @@ -98,6 +104,7 @@ ENTRY(__get_user_64t_1) mov r0, #0 ret lr ENDPROC(__get_user_64t_1) +EXPORT_SYMBOL(__get_user_64t_1) ENTRY(__get_user_64t_2) check_uaccess r0, 2, r1, r2, __get_user_bad8 @@ -114,6 +121,7 @@ rb .req r0 mov r0, #0 ret lr ENDPROC(__get_user_64t_2) +EXPORT_SYMBOL(__get_user_64t_2) ENTRY(__get_user_64t_4) check_uaccess r0, 4, r1, r2, __get_user_bad8 @@ -121,6 +129,7 @@ ENTRY(__get_user_64t_4) mov r0, #0 ret lr ENDPROC(__get_user_64t_4) +EXPORT_SYMBOL(__get_user_64t_4) #endif __get_user_bad8: diff --git a/arch/arm/lib/io-readsb.S b/arch/arm/lib/io-readsb.S index c31b2f3153f17..3dff7a3a2aef0 100644 --- a/arch/arm/lib/io-readsb.S +++ b/arch/arm/lib/io-readsb.S @@ -9,6 +9,7 @@ */ #include #include +#include .Linsb_align: rsb ip, ip, #4 cmp ip, r2 @@ -121,3 +122,4 @@ ENTRY(__raw_readsb) ldmfd sp!, {r4 - r6, pc} ENDPROC(__raw_readsb) +EXPORT_SYMBOL(__raw_readsb) diff --git a/arch/arm/lib/io-readsl.S b/arch/arm/lib/io-readsl.S index 2ed86fa5465f7..bfd39682325b0 100644 --- a/arch/arm/lib/io-readsl.S +++ b/arch/arm/lib/io-readsl.S @@ -9,6 +9,7 @@ */ #include #include +#include ENTRY(__raw_readsl) teq r2, #0 @ do we have to check for the zero len? @@ -77,3 +78,4 @@ ENTRY(__raw_readsl) strb r3, [r1, #0] ret lr ENDPROC(__raw_readsl) +EXPORT_SYMBOL(__raw_readsl) diff --git a/arch/arm/lib/io-readsw-armv3.S b/arch/arm/lib/io-readsw-armv3.S index 413da99145292..b3af3db6caac8 100644 --- a/arch/arm/lib/io-readsw-armv3.S +++ b/arch/arm/lib/io-readsw-armv3.S @@ -9,6 +9,7 @@ */ #include #include +#include .Linsw_bad_alignment: adr r0, .Linsw_bad_align_msg @@ -103,4 +104,4 @@ ENTRY(__raw_readsw) ldmfd sp!, {r4, r5, r6, pc} - +EXPORT_SYMBOL(__raw_readsw) diff --git a/arch/arm/lib/io-readsw-armv4.S b/arch/arm/lib/io-readsw-armv4.S index d9a45e9692aee..3c7a7a40b33ea 100644 --- a/arch/arm/lib/io-readsw-armv4.S +++ b/arch/arm/lib/io-readsw-armv4.S @@ -9,6 +9,7 @@ */ #include #include +#include .macro pack, rd, hw1, hw2 #ifndef __ARMEB__ @@ -129,3 +130,4 @@ ENTRY(__raw_readsw) strneb ip, [r1] ldmfd sp!, {r4, pc} ENDPROC(__raw_readsw) +EXPORT_SYMBOL(__raw_readsw) diff --git a/arch/arm/lib/io-writesb.S b/arch/arm/lib/io-writesb.S index a46bbc9b168b4..fa36335944159 100644 --- a/arch/arm/lib/io-writesb.S +++ b/arch/arm/lib/io-writesb.S @@ -9,6 +9,7 @@ */ #include #include +#include .macro outword, rd #ifndef __ARMEB__ @@ -92,3 +93,4 @@ ENTRY(__raw_writesb) ldmfd sp!, {r4, r5, pc} ENDPROC(__raw_writesb) +EXPORT_SYMBOL(__raw_writesb) diff --git a/arch/arm/lib/io-writesl.S b/arch/arm/lib/io-writesl.S index 4ea2435988c1f..98ed6aec0b476 100644 --- a/arch/arm/lib/io-writesl.S +++ b/arch/arm/lib/io-writesl.S @@ -9,6 +9,7 @@ */ #include #include +#include ENTRY(__raw_writesl) teq r2, #0 @ do we have to check for the zero len? @@ -65,3 +66,4 @@ ENTRY(__raw_writesl) bne 6b ret lr ENDPROC(__raw_writesl) +EXPORT_SYMBOL(__raw_writesl) diff --git a/arch/arm/lib/io-writesw-armv3.S b/arch/arm/lib/io-writesw-armv3.S index 121789eb68023..577184c082bb6 100644 --- a/arch/arm/lib/io-writesw-armv3.S +++ b/arch/arm/lib/io-writesw-armv3.S @@ -9,6 +9,7 @@ */ #include #include +#include .Loutsw_bad_alignment: adr r0, .Loutsw_bad_align_msg @@ -124,3 +125,4 @@ ENTRY(__raw_writesw) strne ip, [r0] ldmfd sp!, {r4, r5, r6, pc} +EXPORT_SYMBOL(__raw_writesw) diff --git a/arch/arm/lib/io-writesw-armv4.S b/arch/arm/lib/io-writesw-armv4.S index 269f90c51ad27..e335f489d1fcd 100644 --- a/arch/arm/lib/io-writesw-armv4.S +++ b/arch/arm/lib/io-writesw-armv4.S @@ -9,6 +9,7 @@ */ #include #include +#include .macro outword, rd #ifndef __ARMEB__ @@ -98,3 +99,4 @@ ENTRY(__raw_writesw) strneh ip, [r0] ret lr ENDPROC(__raw_writesw) +EXPORT_SYMBOL(__raw_writesw) diff --git a/arch/arm/lib/lib1funcs.S b/arch/arm/lib/lib1funcs.S index 9397b2e532afa..f541bc013bff6 100644 --- a/arch/arm/lib/lib1funcs.S +++ b/arch/arm/lib/lib1funcs.S @@ -36,6 +36,7 @@ Boston, MA 02111-1307, USA. */ #include #include #include +#include .macro ARM_DIV_BODY dividend, divisor, result, curbit @@ -238,6 +239,8 @@ UNWIND(.fnstart) UNWIND(.fnend) ENDPROC(__udivsi3) ENDPROC(__aeabi_uidiv) +EXPORT_SYMBOL(__udivsi3) +EXPORT_SYMBOL(__aeabi_uidiv) ENTRY(__umodsi3) UNWIND(.fnstart) @@ -256,6 +259,7 @@ UNWIND(.fnstart) UNWIND(.fnend) ENDPROC(__umodsi3) +EXPORT_SYMBOL(__umodsi3) #ifdef CONFIG_ARM_PATCH_IDIV .align 3 @@ -303,6 +307,8 @@ UNWIND(.fnstart) UNWIND(.fnend) ENDPROC(__divsi3) ENDPROC(__aeabi_idiv) +EXPORT_SYMBOL(__divsi3) +EXPORT_SYMBOL(__aeabi_idiv) ENTRY(__modsi3) UNWIND(.fnstart) @@ -327,6 +333,7 @@ UNWIND(.fnstart) UNWIND(.fnend) ENDPROC(__modsi3) +EXPORT_SYMBOL(__modsi3) #ifdef CONFIG_AEABI @@ -343,6 +350,7 @@ UNWIND(.save {r0, r1, ip, lr} ) UNWIND(.fnend) ENDPROC(__aeabi_uidivmod) +EXPORT_SYMBOL(__aeabi_uidivmod) ENTRY(__aeabi_idivmod) UNWIND(.fnstart) @@ -356,6 +364,7 @@ UNWIND(.save {r0, r1, ip, lr} ) UNWIND(.fnend) ENDPROC(__aeabi_idivmod) +EXPORT_SYMBOL(__aeabi_idivmod) #endif diff --git a/arch/arm/lib/lshrdi3.S b/arch/arm/lib/lshrdi3.S index 922dcd88b02b7..e408339814174 100644 --- a/arch/arm/lib/lshrdi3.S +++ b/arch/arm/lib/lshrdi3.S @@ -28,6 +28,7 @@ Boston, MA 02110-1301, USA. */ #include #include +#include #ifdef __ARMEB__ #define al r1 @@ -52,3 +53,5 @@ ENTRY(__aeabi_llsr) ENDPROC(__lshrdi3) ENDPROC(__aeabi_llsr) +EXPORT_SYMBOL(__lshrdi3) +EXPORT_SYMBOL(__aeabi_llsr) diff --git a/arch/arm/lib/memchr.S b/arch/arm/lib/memchr.S index 74a5bed6d9999..44182bf686a51 100644 --- a/arch/arm/lib/memchr.S +++ b/arch/arm/lib/memchr.S @@ -11,6 +11,7 @@ */ #include #include +#include .text .align 5 @@ -24,3 +25,4 @@ ENTRY(memchr) 2: movne r0, #0 ret lr ENDPROC(memchr) +EXPORT_SYMBOL(memchr) diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S index 64111bd4440b1..1be5b6ddf37c8 100644 --- a/arch/arm/lib/memcpy.S +++ b/arch/arm/lib/memcpy.S @@ -13,6 +13,7 @@ #include #include #include +#include #define LDR1W_SHIFT 0 #define STR1W_SHIFT 0 @@ -68,3 +69,5 @@ ENTRY(memcpy) ENDPROC(memcpy) ENDPROC(mmiocpy) +EXPORT_SYMBOL(memcpy) +EXPORT_SYMBOL(mmiocpy) diff --git a/arch/arm/lib/memmove.S b/arch/arm/lib/memmove.S index 69a9d47fc5abd..71dcc5400d025 100644 --- a/arch/arm/lib/memmove.S +++ b/arch/arm/lib/memmove.S @@ -13,6 +13,7 @@ #include #include #include +#include .text @@ -225,3 +226,4 @@ ENTRY(memmove) 18: backward_copy_shift push=24 pull=8 ENDPROC(memmove) +EXPORT_SYMBOL(memmove) diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S index 3c65e3bd790fe..7b72044cba62f 100644 --- a/arch/arm/lib/memset.S +++ b/arch/arm/lib/memset.S @@ -12,6 +12,7 @@ #include #include #include +#include .text .align 5 @@ -135,3 +136,5 @@ UNWIND( .fnstart ) UNWIND( .fnend ) ENDPROC(memset) ENDPROC(mmioset) +EXPORT_SYMBOL(memset) +EXPORT_SYMBOL(mmioset) diff --git a/arch/arm/lib/memzero.S b/arch/arm/lib/memzero.S index 0eded952e0896..6dec26ed5bccd 100644 --- a/arch/arm/lib/memzero.S +++ b/arch/arm/lib/memzero.S @@ -10,6 +10,7 @@ #include #include #include +#include .text .align 5 @@ -135,3 +136,4 @@ UNWIND( .fnstart ) ret lr @ 1 UNWIND( .fnend ) ENDPROC(__memzero) +EXPORT_SYMBOL(__memzero) diff --git a/arch/arm/lib/muldi3.S b/arch/arm/lib/muldi3.S index 2043059569250..b8f12388ccaca 100644 --- a/arch/arm/lib/muldi3.S +++ b/arch/arm/lib/muldi3.S @@ -12,6 +12,7 @@ #include #include +#include #ifdef __ARMEB__ #define xh r0 @@ -46,3 +47,5 @@ ENTRY(__aeabi_lmul) ENDPROC(__muldi3) ENDPROC(__aeabi_lmul) +EXPORT_SYMBOL(__muldi3) +EXPORT_SYMBOL(__aeabi_lmul) diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S index 38d660d3705f4..11de126e2ed6b 100644 --- a/arch/arm/lib/putuser.S +++ b/arch/arm/lib/putuser.S @@ -31,6 +31,7 @@ #include #include #include +#include ENTRY(__put_user_1) check_uaccess r0, 1, r1, ip, __put_user_bad @@ -38,6 +39,7 @@ ENTRY(__put_user_1) mov r0, #0 ret lr ENDPROC(__put_user_1) +EXPORT_SYMBOL(__put_user_1) ENTRY(__put_user_2) check_uaccess r0, 2, r1, ip, __put_user_bad @@ -62,6 +64,7 @@ ENTRY(__put_user_2) mov r0, #0 ret lr ENDPROC(__put_user_2) +EXPORT_SYMBOL(__put_user_2) ENTRY(__put_user_4) check_uaccess r0, 4, r1, ip, __put_user_bad @@ -69,6 +72,7 @@ ENTRY(__put_user_4) mov r0, #0 ret lr ENDPROC(__put_user_4) +EXPORT_SYMBOL(__put_user_4) ENTRY(__put_user_8) check_uaccess r0, 8, r1, ip, __put_user_bad @@ -82,6 +86,7 @@ ENTRY(__put_user_8) mov r0, #0 ret lr ENDPROC(__put_user_8) +EXPORT_SYMBOL(__put_user_8) __put_user_bad: mov r0, #-EFAULT diff --git a/arch/arm/lib/strchr.S b/arch/arm/lib/strchr.S index 013d64c71e8d6..7301f6e6046c1 100644 --- a/arch/arm/lib/strchr.S +++ b/arch/arm/lib/strchr.S @@ -11,6 +11,7 @@ */ #include #include +#include .text .align 5 @@ -25,3 +26,4 @@ ENTRY(strchr) subeq r0, r0, #1 ret lr ENDPROC(strchr) +EXPORT_SYMBOL(strchr) diff --git a/arch/arm/lib/strrchr.S b/arch/arm/lib/strrchr.S index 3cec1c7482c49..aaf9fd98b7548 100644 --- a/arch/arm/lib/strrchr.S +++ b/arch/arm/lib/strrchr.S @@ -11,6 +11,7 @@ */ #include #include +#include .text .align 5 @@ -24,3 +25,4 @@ ENTRY(strrchr) mov r0, r3 ret lr ENDPROC(strrchr) +EXPORT_SYMBOL(strrchr) diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c index 6bd1089b07e09..1626e3a551a14 100644 --- a/arch/arm/lib/uaccess_with_memcpy.c +++ b/arch/arm/lib/uaccess_with_memcpy.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -156,6 +157,7 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n) } return n; } +EXPORT_SYMBOL(arm_copy_to_user); static unsigned long noinline __clear_user_memset(void __user *addr, unsigned long n) @@ -213,6 +215,7 @@ unsigned long arm_clear_user(void __user *addr, unsigned long n) } return n; } +EXPORT_SYMBOL(arm_clear_user); #if 0 diff --git a/arch/arm/lib/ucmpdi2.S b/arch/arm/lib/ucmpdi2.S index ad4a6309141a5..127a91af46f3a 100644 --- a/arch/arm/lib/ucmpdi2.S +++ b/arch/arm/lib/ucmpdi2.S @@ -12,6 +12,7 @@ #include #include +#include #ifdef __ARMEB__ #define xh r0 @@ -35,6 +36,7 @@ ENTRY(__ucmpdi2) ret lr ENDPROC(__ucmpdi2) +EXPORT_SYMBOL(__ucmpdi2) #ifdef CONFIG_AEABI @@ -48,6 +50,7 @@ ENTRY(__aeabi_ulcmp) ret lr ENDPROC(__aeabi_ulcmp) +EXPORT_SYMBOL(__aeabi_ulcmp) #endif diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 9f5fffd627026..8ed8ab56bb78f 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -32,7 +32,6 @@ endif ifdef CONFIG_SND_IMX_SOC obj-y += ssi-fiq.o -obj-y += ssi-fiq-ksym.o endif # i.MX1 based machines diff --git a/arch/arm/mach-imx/ssi-fiq-ksym.c b/arch/arm/mach-imx/ssi-fiq-ksym.c deleted file mode 100644 index 792090f9a032b..0000000000000 --- a/arch/arm/mach-imx/ssi-fiq-ksym.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Exported ksyms for the SSI FIQ handler - * - * Copyright (C) 2009, Sascha Hauer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include - -#include - -EXPORT_SYMBOL(imx_ssi_fiq_tx_buffer); -EXPORT_SYMBOL(imx_ssi_fiq_rx_buffer); -EXPORT_SYMBOL(imx_ssi_fiq_start); -EXPORT_SYMBOL(imx_ssi_fiq_end); -EXPORT_SYMBOL(imx_ssi_fiq_base); - diff --git a/arch/arm/mach-imx/ssi-fiq.S b/arch/arm/mach-imx/ssi-fiq.S index a8b93c5f29b53..fd7917f1c2041 100644 --- a/arch/arm/mach-imx/ssi-fiq.S +++ b/arch/arm/mach-imx/ssi-fiq.S @@ -8,6 +8,7 @@ #include #include +#include /* * r8 = bit 0-15: tx offset, bit 16-31: tx buffer size @@ -144,4 +145,8 @@ imx_ssi_fiq_tx_buffer: .word 0x0 .L_imx_ssi_fiq_end: imx_ssi_fiq_end: - +EXPORT_SYMBOL(imx_ssi_fiq_tx_buffer) +EXPORT_SYMBOL(imx_ssi_fiq_rx_buffer) +EXPORT_SYMBOL(imx_ssi_fiq_start) +EXPORT_SYMBOL(imx_ssi_fiq_end) +EXPORT_SYMBOL(imx_ssi_fiq_base) -- GitLab From 9445aa1a3062a75a4d9de78026816ebc941e7b99 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 13 Jan 2016 23:33:46 -0500 Subject: [PATCH 0010/1167] ppc: move exports to definitions Signed-off-by: Al Viro --- arch/powerpc/include/asm/Kbuild | 1 + arch/powerpc/kernel/Makefile | 4 -- arch/powerpc/kernel/entry_32.S | 2 + arch/powerpc/kernel/entry_64.S | 3 ++ arch/powerpc/kernel/epapr_hcalls.S | 2 + arch/powerpc/kernel/fpu.S | 3 ++ arch/powerpc/kernel/head_32.S | 5 +++ arch/powerpc/kernel/head_40x.S | 2 + arch/powerpc/kernel/head_44x.S | 2 + arch/powerpc/kernel/head_64.S | 2 + arch/powerpc/kernel/head_8xx.S | 2 + arch/powerpc/kernel/head_fsl_booke.S | 2 + arch/powerpc/kernel/misc.S | 2 + arch/powerpc/kernel/misc_32.S | 11 +++++ arch/powerpc/kernel/misc_64.S | 4 ++ arch/powerpc/kernel/pci-common.c | 1 + arch/powerpc/kernel/pci_32.c | 2 + arch/powerpc/kernel/ppc_ksyms.c | 37 ----------------- arch/powerpc/kernel/ppc_ksyms_32.c | 60 ---------------------------- arch/powerpc/kernel/setup_32.c | 6 +++ arch/powerpc/kernel/time.c | 1 + arch/powerpc/kernel/vector.S | 3 ++ arch/powerpc/lib/Makefile | 2 +- arch/powerpc/lib/checksum_32.S | 3 ++ arch/powerpc/lib/checksum_64.S | 3 ++ arch/powerpc/lib/copy_32.S | 5 +++ arch/powerpc/lib/copypage_64.S | 2 + arch/powerpc/lib/copyuser_64.S | 2 + arch/powerpc/lib/hweight_64.S | 5 +++ arch/powerpc/lib/mem_64.S | 3 ++ arch/powerpc/lib/memcmp_64.S | 2 + arch/powerpc/lib/memcpy_64.S | 2 + arch/powerpc/lib/ppc_ksyms.c | 29 -------------- arch/powerpc/lib/string.S | 6 +++ arch/powerpc/lib/string_64.S | 2 + arch/powerpc/mm/hash_low_32.S | 3 ++ arch/powerpc/sysdev/dcr-low.S | 3 ++ 37 files changed, 98 insertions(+), 131 deletions(-) delete mode 100644 arch/powerpc/kernel/ppc_ksyms.c delete mode 100644 arch/powerpc/kernel/ppc_ksyms_32.c delete mode 100644 arch/powerpc/lib/ppc_ksyms.c diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild index ab9f4e0ed4cfc..5c4fbc80dc6ce 100644 --- a/arch/powerpc/include/asm/Kbuild +++ b/arch/powerpc/include/asm/Kbuild @@ -1,5 +1,6 @@ generic-y += clkdev.h generic-y += div64.h +generic-y += export.h generic-y += irq_regs.h generic-y += irq_work.h generic-y += local64.h diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index b2027a5cf5081..68e074e85ec9f 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -91,10 +91,6 @@ obj-$(CONFIG_RELOCATABLE) += reloc_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_PPC32) += entry_32.o setup_32.o obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o obj-$(CONFIG_KGDB) += kgdb.o -obj-$(CONFIG_MODULES) += ppc_ksyms.o -ifeq ($(CONFIG_PPC32),y) -obj-$(CONFIG_MODULES) += ppc_ksyms_32.o -endif obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 9899032230b4b..c2c0bf003dd15 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -33,6 +33,7 @@ #include #include #include +#include /* * MSR_KERNEL is > 0x10000 on 4xx/Book-E since it include MSR_CE. @@ -1359,6 +1360,7 @@ _GLOBAL(_mcount) MCOUNT_RESTORE_FRAME bctr #endif +EXPORT_SYMBOL(_mcount) _GLOBAL(ftrace_stub) blr diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 6b8bc0dd09d4a..254518d466f07 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -38,6 +38,7 @@ #include #include #include +#include /* * System calls. @@ -1180,6 +1181,7 @@ _GLOBAL(enter_prom) #ifdef CONFIG_DYNAMIC_FTRACE _GLOBAL(mcount) _GLOBAL(_mcount) +EXPORT_SYMBOL(_mcount) mflr r12 mtctr r12 mtlr r0 @@ -1416,6 +1418,7 @@ livepatch_handler: #else _GLOBAL_TOC(_mcount) +EXPORT_SYMBOL(_mcount) /* Taken from output of objdump from lib64/glibc */ mflr r3 ld r11, 0(r1) diff --git a/arch/powerpc/kernel/epapr_hcalls.S b/arch/powerpc/kernel/epapr_hcalls.S index 9f1ebf7338f10..52ca2471ee1a4 100644 --- a/arch/powerpc/kernel/epapr_hcalls.S +++ b/arch/powerpc/kernel/epapr_hcalls.S @@ -16,6 +16,7 @@ #include #include #include +#include #ifndef CONFIG_PPC64 /* epapr_ev_idle() was derived from e500_idle() */ @@ -53,3 +54,4 @@ epapr_hypercall_start: nop nop blr +EXPORT_SYMBOL(epapr_hypercall_start) diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 15da2b5df85e6..aa52b6be90265 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef CONFIG_VSX #define __REST_32FPVSRS(n,c,base) \ @@ -85,6 +86,7 @@ _GLOBAL(load_fp_state) MTFSF_L(fr0) REST_32FPVSRS(0, R4, R3) blr +EXPORT_SYMBOL(load_fp_state) /* * Store FP state into memory, including FPSCR @@ -95,6 +97,7 @@ _GLOBAL(store_fp_state) mffs fr0 stfd fr0,FPSTATE_FPSCR(r3) blr +EXPORT_SYMBOL(store_fp_state) /* * This task wants to use the FPU now. diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index dc0488b6f6e15..590fe4aa26c9a 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -34,6 +34,7 @@ #include #include #include +#include /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ #define LOAD_BAT(n, reg, RA, RB) \ @@ -739,6 +740,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU) .globl mol_trampoline .set mol_trampoline, i0x2f00 + EXPORT_SYMBOL(mol_trampoline) . = 0x3000 @@ -1048,6 +1050,7 @@ _ENTRY(switch_mmu_context) 4: trap EMIT_BUG_ENTRY 4b,__FILE__,__LINE__,0 blr +EXPORT_SYMBOL(switch_mmu_context) /* * An undocumented "feature" of 604e requires that the v bit @@ -1275,6 +1278,7 @@ sdata: .globl empty_zero_page empty_zero_page: .space 4096 +EXPORT_SYMBOL(empty_zero_page) .globl swapper_pg_dir swapper_pg_dir: @@ -1288,6 +1292,7 @@ intercept_table: .long 0, 0, 0, 0, 0, 0, 0, 0 .long 0, 0, 0, 0, 0, 0, 0, 0 .long 0, 0, 0, 0, 0, 0, 0, 0 +EXPORT_SYMBOL(intercept_table) /* Room for two PTE pointers, usually the kernel and current user pointers * to their respective root page table. diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index 7d7d8635227ac..41374a468d1c1 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S @@ -41,6 +41,7 @@ #include #include #include +#include /* As with the other PowerPC ports, it is expected that when code * execution begins here, the following registers contain valid, yet @@ -971,6 +972,7 @@ sdata: .globl empty_zero_page empty_zero_page: .space 4096 +EXPORT_SYMBOL(empty_zero_page) .globl swapper_pg_dir swapper_pg_dir: .space PGD_TABLE_SIZE diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 9cdf5c71e4263..37e4a7cf0065b 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -39,6 +39,7 @@ #include #include #include +#include #include "head_booke.h" @@ -1254,6 +1255,7 @@ sdata: .globl empty_zero_page empty_zero_page: .space PAGE_SIZE +EXPORT_SYMBOL(empty_zero_page) /* * To support >32-bit physical addresses, we use an 8KB pgdir. diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index f765b0434731c..09655eaa46fff 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -42,6 +42,7 @@ #include #include #include +#include /* The physical memory is laid out such that the secondary processor * spin code sits at 0x0000...0x00ff. On server, the vectors follow @@ -983,3 +984,4 @@ swapper_pg_dir: .globl empty_zero_page empty_zero_page: .space PAGE_SIZE +EXPORT_SYMBOL(empty_zero_page) diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 43ddaae42baf7..863251511b42f 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -31,6 +31,7 @@ #include #include #include +#include /* Macro to make the code more readable. */ #ifdef CONFIG_8xx_CPU6 @@ -895,6 +896,7 @@ sdata: .align PAGE_SHIFT empty_zero_page: .space PAGE_SIZE +EXPORT_SYMBOL(empty_zero_page) .globl swapper_pg_dir swapper_pg_dir: diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 3bfa3150911f7..bf4c6021515f8 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -42,6 +42,7 @@ #include #include #include +#include #include "head_booke.h" /* As with the other PowerPC ports, it is expected that when code @@ -1223,6 +1224,7 @@ sdata: .globl empty_zero_page empty_zero_page: .space 4096 +EXPORT_SYMBOL(empty_zero_page) .globl swapper_pg_dir swapper_pg_dir: .space PGD_TABLE_SIZE diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index 0d432194c0182..384357cb8bc00 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S @@ -18,6 +18,7 @@ #include #include #include +#include .text @@ -118,3 +119,4 @@ _GLOBAL(longjmp) _GLOBAL(current_stack_pointer) PPC_LL r3,0(r1) blr +EXPORT_SYMBOL(current_stack_pointer) diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index d9c912b6e6325..ea26a9181586a 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -33,6 +33,7 @@ #include #include #include +#include .text @@ -319,6 +320,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE) #endif /* CONFIG_4xx */ isync blr +EXPORT_SYMBOL(flush_instruction_cache) #endif /* CONFIG_PPC_8xx */ /* @@ -358,6 +360,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) sync /* additional sync needed on g4 */ isync blr +EXPORT_SYMBOL(flush_icache_range) /* * Flush a particular page from the data cache to RAM. * Note: this is necessary because the instruction cache does *not* @@ -450,6 +453,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) stw r7,8(r3); \ stw r8,12(r3); \ stwu r9,16(r3) +EXPORT_SYMBOL(clear_pages) _GLOBAL(copy_page) addi r3,r3,-4 @@ -495,6 +499,7 @@ _GLOBAL(copy_page) li r0,MAX_COPY_PREFETCH li r11,4 b 2b +EXPORT_SYMBOL(copy_page) /* * Extended precision shifts. @@ -522,6 +527,7 @@ _GLOBAL(__ashrdi3) sraw r3,r3,r5 # MSW = MSW >> count or r4,r4,r7 # LSW |= t2 blr +EXPORT_SYMBOL(__ashrdi3) _GLOBAL(__ashldi3) subfic r6,r5,32 @@ -533,6 +539,7 @@ _GLOBAL(__ashldi3) slw r4,r4,r5 # LSW = LSW << count or r3,r3,r7 # MSW |= t2 blr +EXPORT_SYMBOL(__ashldi3) _GLOBAL(__lshrdi3) subfic r6,r5,32 @@ -544,6 +551,7 @@ _GLOBAL(__lshrdi3) srw r3,r3,r5 # MSW = MSW >> count or r4,r4,r7 # LSW |= t2 blr +EXPORT_SYMBOL(__lshrdi3) /* * 64-bit comparison: __cmpdi2(s64 a, s64 b) @@ -559,6 +567,7 @@ _GLOBAL(__cmpdi2) bltlr li r3,2 blr +EXPORT_SYMBOL(__cmpdi2) /* * 64-bit comparison: __ucmpdi2(u64 a, u64 b) * Returns 0 if a < b, 1 if a == b, 2 if a > b. @@ -573,6 +582,7 @@ _GLOBAL(__ucmpdi2) bltlr li r3,2 blr +EXPORT_SYMBOL(__ucmpdi2) _GLOBAL(__bswapdi2) rotlwi r9,r4,8 @@ -584,6 +594,7 @@ _GLOBAL(__bswapdi2) mr r3,r9 mr r4,r10 blr +EXPORT_SYMBOL(__bswapdi2) #ifdef CONFIG_SMP _GLOBAL(start_secondary_resume) diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index cb195157b318e..8b526846e72ac 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -27,6 +27,7 @@ #include #include #include +#include .text @@ -110,6 +111,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) isync blr .previous .text +EXPORT_SYMBOL(flush_icache_range) /* * Like above, but only do the D-cache. * @@ -139,6 +141,7 @@ _GLOBAL(flush_dcache_range) bdnz 0b sync blr +EXPORT_SYMBOL(flush_dcache_range) /* * Like above, but works on non-mapped physical addresses. @@ -242,6 +245,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) blr _GLOBAL(__bswapdi2) +EXPORT_SYMBOL(__bswapdi2) srdi r8,r3,32 rlwinm r7,r3,8,0xffffffff rlwimi r7,r3,24,0,7 diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index a5c0153ede37f..7c63811fcdab6 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -56,6 +56,7 @@ static DECLARE_BITMAP(phb_bitmap, MAX_PHBS); /* ISA Memory physical address */ resource_size_t isa_mem_base; +EXPORT_SYMBOL(isa_mem_base); static struct dma_map_ops *pci_dma_ops = &dma_direct_ops; diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 1f7930037cb7d..678f87a636457 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -32,6 +32,8 @@ unsigned long isa_io_base = 0; unsigned long pci_dram_offset = 0; int pcibios_assign_bus_offset = 1; +EXPORT_SYMBOL(isa_io_base); +EXPORT_SYMBOL(pci_dram_offset); void pcibios_make_OF_bus_map(void); diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c deleted file mode 100644 index 9f01e28ecef35..0000000000000 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -#include -#include -#include -#include - -#ifdef CONFIG_PPC64 -EXPORT_SYMBOL(flush_dcache_range); -#endif -EXPORT_SYMBOL(flush_icache_range); - -EXPORT_SYMBOL(empty_zero_page); - -long long __bswapdi2(long long); -EXPORT_SYMBOL(__bswapdi2); - -#ifdef CONFIG_FUNCTION_TRACER -EXPORT_SYMBOL(_mcount); -#endif - -#ifdef CONFIG_PPC_FPU -EXPORT_SYMBOL(load_fp_state); -EXPORT_SYMBOL(store_fp_state); -#endif - -#ifdef CONFIG_ALTIVEC -EXPORT_SYMBOL(load_vr_state); -EXPORT_SYMBOL(store_vr_state); -#endif - -#ifdef CONFIG_EPAPR_PARAVIRT -EXPORT_SYMBOL(epapr_hypercall_start); -#endif - -EXPORT_SYMBOL(current_stack_pointer); diff --git a/arch/powerpc/kernel/ppc_ksyms_32.c b/arch/powerpc/kernel/ppc_ksyms_32.c deleted file mode 100644 index 2bfaafe5be99e..0000000000000 --- a/arch/powerpc/kernel/ppc_ksyms_32.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -EXPORT_SYMBOL(ISA_DMA_THRESHOLD); -EXPORT_SYMBOL(DMA_MODE_READ); -EXPORT_SYMBOL(DMA_MODE_WRITE); - -#if defined(CONFIG_PCI) -EXPORT_SYMBOL(isa_io_base); -EXPORT_SYMBOL(isa_mem_base); -EXPORT_SYMBOL(pci_dram_offset); -#endif - -#ifdef CONFIG_SMP -EXPORT_SYMBOL(smp_hw_index); -#endif - -long long __ashrdi3(long long, int); -long long __ashldi3(long long, int); -long long __lshrdi3(long long, int); -int __ucmpdi2(unsigned long long, unsigned long long); -int __cmpdi2(long long, long long); -EXPORT_SYMBOL(__ashrdi3); -EXPORT_SYMBOL(__ashldi3); -EXPORT_SYMBOL(__lshrdi3); -EXPORT_SYMBOL(__ucmpdi2); -EXPORT_SYMBOL(__cmpdi2); - -EXPORT_SYMBOL(timer_interrupt); -EXPORT_SYMBOL(tb_ticks_per_jiffy); - -EXPORT_SYMBOL(switch_mmu_context); - -#ifdef CONFIG_PPC_STD_MMU_32 -extern long mol_trampoline; -EXPORT_SYMBOL(mol_trampoline); /* For MOL */ -EXPORT_SYMBOL(flush_hash_pages); /* For MOL */ -#ifdef CONFIG_SMP -extern int mmu_hash_lock; -EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */ -#endif /* CONFIG_SMP */ -extern long *intercept_table; -EXPORT_SYMBOL(intercept_table); -#endif /* CONFIG_PPC_STD_MMU_32 */ - -#ifdef CONFIG_PPC_DCR_NATIVE -EXPORT_SYMBOL(__mtdcr); -EXPORT_SYMBOL(__mfdcr); -#endif - -EXPORT_SYMBOL(flush_instruction_cache); diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index c3e861df4b203..c842b8e31cb9c 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -47,11 +48,16 @@ int boot_cpuid_phys; EXPORT_SYMBOL_GPL(boot_cpuid_phys); int smp_hw_index[NR_CPUS]; +EXPORT_SYMBOL(smp_hw_index); unsigned long ISA_DMA_THRESHOLD; unsigned int DMA_MODE_READ; unsigned int DMA_MODE_WRITE; +EXPORT_SYMBOL(ISA_DMA_THRESHOLD); +EXPORT_SYMBOL(DMA_MODE_READ); +EXPORT_SYMBOL(DMA_MODE_WRITE); + /* * These are used in binfmt_elf.c to put aux entries on the stack * for each elf executable being started. diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 3efbedefba6a9..0ce8b76c61508 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -595,6 +595,7 @@ void timer_interrupt(struct pt_regs * regs) irq_exit(); set_irq_regs(old_regs); } +EXPORT_SYMBOL(timer_interrupt); /* * Hypervisor decrementer interrupts shouldn't occur but are sometimes diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 616a6d854638f..388ec6477fc44 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef CONFIG_PPC_TRANSACTIONAL_MEM /* void do_load_up_transact_altivec(struct thread_struct *thread) @@ -42,6 +43,7 @@ _GLOBAL(load_vr_state) mtvscr v0 REST_32VRS(0,r4,r3) blr +EXPORT_SYMBOL(load_vr_state) /* * Store VMX state into memory, including VSCR. @@ -53,6 +55,7 @@ _GLOBAL(store_vr_state) li r4, VRSTATE_VSCR stvx v0, r4, r3 blr +EXPORT_SYMBOL(store_vr_state) /* * Disable VMX for the task which had it previously, diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index ba21be15310f3..555ff1a61c5e2 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -9,7 +9,7 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) CFLAGS_REMOVE_code-patching.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_feature-fixups.o = $(CC_FLAGS_FTRACE) -obj-y += string.o alloc.o crtsavres.o ppc_ksyms.o code-patching.o \ +obj-y += string.o alloc.o crtsavres.o code-patching.o \ feature-fixups.o obj-$(CONFIG_PPC32) += div64.o copy_32.o diff --git a/arch/powerpc/lib/checksum_32.S b/arch/powerpc/lib/checksum_32.S index d90870a66b60b..da678bdfc4ac1 100644 --- a/arch/powerpc/lib/checksum_32.S +++ b/arch/powerpc/lib/checksum_32.S @@ -17,6 +17,7 @@ #include #include #include +#include .text @@ -68,6 +69,7 @@ _GLOBAL(__csum_partial) adde r5,r5,r0 5: addze r3,r5 /* add in final carry */ blr +EXPORT_SYMBOL(__csum_partial) /* * Computes the checksum of a memory block at src, length len, @@ -295,3 +297,4 @@ dst_error: .long 41b,dst_error .long 50b,src_error .long 51b,dst_error +EXPORT_SYMBOL(csum_partial_copy_generic) diff --git a/arch/powerpc/lib/checksum_64.S b/arch/powerpc/lib/checksum_64.S index fdec6e613e954..fd9176671f9fb 100644 --- a/arch/powerpc/lib/checksum_64.S +++ b/arch/powerpc/lib/checksum_64.S @@ -16,6 +16,7 @@ #include #include #include +#include /* * Computes the checksum of a memory block at buff, length len, @@ -176,6 +177,7 @@ _GLOBAL(__csum_partial) add r3,r4,r0 srdi r3,r3,32 blr +EXPORT_SYMBOL(__csum_partial) .macro srcnr @@ -430,3 +432,4 @@ dstnr; stb r6,0(r4) li r6,-EFAULT stw r6,0(r8) blr +EXPORT_SYMBOL(csum_partial_copy_generic) diff --git a/arch/powerpc/lib/copy_32.S b/arch/powerpc/lib/copy_32.S index 99f37f24185ca..40cce33b08d6a 100644 --- a/arch/powerpc/lib/copy_32.S +++ b/arch/powerpc/lib/copy_32.S @@ -12,6 +12,7 @@ #include #include #include +#include #define COPY_16_BYTES \ lwz r7,4(r4); \ @@ -92,6 +93,7 @@ _GLOBAL(memset) subf r6,r0,r6 cmplwi 0,r4,0 bne 2f /* Use normal procedure if r4 is not zero */ +EXPORT_SYMBOL(memset) _GLOBAL(memset_nocache_branch) b 2f /* Skip optimised bloc until cache is enabled */ @@ -216,6 +218,8 @@ _GLOBAL(memcpy) stbu r0,1(r6) bdnz 40b 65: blr +EXPORT_SYMBOL(memcpy) +EXPORT_SYMBOL(memmove) generic_memcpy: srwi. r7,r5,3 @@ -507,3 +511,4 @@ _GLOBAL(__copy_tofrom_user) .long 112b,120b .long 114b,120b .text +EXPORT_SYMBOL(__copy_tofrom_user) diff --git a/arch/powerpc/lib/copypage_64.S b/arch/powerpc/lib/copypage_64.S index a3c4dc4defdd8..21367b3a81465 100644 --- a/arch/powerpc/lib/copypage_64.S +++ b/arch/powerpc/lib/copypage_64.S @@ -10,6 +10,7 @@ #include #include #include +#include .section ".toc","aw" PPC64_CACHES: @@ -110,3 +111,4 @@ END_FTR_SECTION_IFSET(CPU_FTR_CP_USE_DCBTZ) std r11,120(r3) std r12,128(r3) blr +EXPORT_SYMBOL(copy_page) diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S index f09899e359917..f19a15b0cff9a 100644 --- a/arch/powerpc/lib/copyuser_64.S +++ b/arch/powerpc/lib/copyuser_64.S @@ -8,6 +8,7 @@ */ #include #include +#include #ifdef __BIG_ENDIAN__ #define sLd sld /* Shift towards low-numbered address. */ @@ -671,3 +672,4 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) .llong 89b,100b .llong 90b,100b .llong 91b,100b +EXPORT_SYMBOL(__copy_tofrom_user) diff --git a/arch/powerpc/lib/hweight_64.S b/arch/powerpc/lib/hweight_64.S index 19e66001a4f9d..3de7ac154f24e 100644 --- a/arch/powerpc/lib/hweight_64.S +++ b/arch/powerpc/lib/hweight_64.S @@ -19,6 +19,7 @@ */ #include #include +#include /* Note: This code relies on -mminimal-toc */ @@ -32,6 +33,7 @@ FTR_SECTION_ELSE clrldi r3,r3,64-8 blr ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POPCNTB) +EXPORT_SYMBOL(__arch_hweight8) _GLOBAL(__arch_hweight16) BEGIN_FTR_SECTION @@ -54,6 +56,7 @@ FTR_SECTION_ELSE blr ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_POPCNTD, 50) ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POPCNTB) +EXPORT_SYMBOL(__arch_hweight16) _GLOBAL(__arch_hweight32) BEGIN_FTR_SECTION @@ -79,6 +82,7 @@ FTR_SECTION_ELSE blr ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_POPCNTD, 51) ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POPCNTB) +EXPORT_SYMBOL(__arch_hweight32) _GLOBAL(__arch_hweight64) BEGIN_FTR_SECTION @@ -108,3 +112,4 @@ FTR_SECTION_ELSE blr ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_POPCNTD, 52) ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POPCNTB) +EXPORT_SYMBOL(__arch_hweight64) diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S index 43435c6892fb0..2d128df161ec5 100644 --- a/arch/powerpc/lib/mem_64.S +++ b/arch/powerpc/lib/mem_64.S @@ -11,6 +11,7 @@ #include #include #include +#include _GLOBAL(memset) neg r0,r3 @@ -76,6 +77,7 @@ _GLOBAL(memset) 10: bflr 31 stb r4,0(r6) blr +EXPORT_SYMBOL(memset) _GLOBAL_TOC(memmove) cmplw 0,r3,r4 @@ -117,3 +119,4 @@ _GLOBAL(backwards_memcpy) beq 2b mtctr r7 b 1b +EXPORT_SYMBOL(memmove) diff --git a/arch/powerpc/lib/memcmp_64.S b/arch/powerpc/lib/memcmp_64.S index 8953d2382a653..d75d18b7bd554 100644 --- a/arch/powerpc/lib/memcmp_64.S +++ b/arch/powerpc/lib/memcmp_64.S @@ -8,6 +8,7 @@ * 2 of the License, or (at your option) any later version. */ #include +#include #define off8 r6 #define off16 r7 @@ -231,3 +232,4 @@ _GLOBAL(memcmp) ld r28,-32(r1) ld r27,-40(r1) blr +EXPORT_SYMBOL(memcmp) diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S index 32a06ec395d21..f4d6088e2d539 100644 --- a/arch/powerpc/lib/memcpy_64.S +++ b/arch/powerpc/lib/memcpy_64.S @@ -8,6 +8,7 @@ */ #include #include +#include .align 7 _GLOBAL_TOC(memcpy) @@ -219,3 +220,4 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 4: ld r3,-STACKFRAMESIZE+STK_REG(R31)(r1) /* return dest pointer */ blr #endif +EXPORT_SYMBOL(memcpy) diff --git a/arch/powerpc/lib/ppc_ksyms.c b/arch/powerpc/lib/ppc_ksyms.c deleted file mode 100644 index ae69d846a8416..0000000000000 --- a/arch/powerpc/lib/ppc_ksyms.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include -#include - -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memchr); - -EXPORT_SYMBOL(strncpy); -EXPORT_SYMBOL(strncmp); - -#ifndef CONFIG_GENERIC_CSUM -EXPORT_SYMBOL(__csum_partial); -EXPORT_SYMBOL(csum_partial_copy_generic); -#endif - -EXPORT_SYMBOL(__copy_tofrom_user); -EXPORT_SYMBOL(__clear_user); -EXPORT_SYMBOL(copy_page); - -#ifdef CONFIG_PPC64 -EXPORT_SYMBOL(__arch_hweight8); -EXPORT_SYMBOL(__arch_hweight16); -EXPORT_SYMBOL(__arch_hweight32); -EXPORT_SYMBOL(__arch_hweight64); -#endif diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S index beabc68d9a1e4..d13e076035195 100644 --- a/arch/powerpc/lib/string.S +++ b/arch/powerpc/lib/string.S @@ -11,6 +11,7 @@ #include #include #include +#include .section __ex_table,"a" PPC_LONG_ALIGN @@ -36,6 +37,7 @@ _GLOBAL(strncpy) 2: stbu r0,1(r6) /* clear it out if so */ bdnz 2b blr +EXPORT_SYMBOL(strncpy) _GLOBAL(strncmp) PPC_LCMPI 0,r5,0 @@ -53,6 +55,7 @@ _GLOBAL(strncmp) blr 2: li r3,0 blr +EXPORT_SYMBOL(strncmp) #ifdef CONFIG_PPC32 _GLOBAL(memcmp) @@ -68,6 +71,7 @@ _GLOBAL(memcmp) blr 2: li r3,0 blr +EXPORT_SYMBOL(memcmp) #endif _GLOBAL(memchr) @@ -82,6 +86,7 @@ _GLOBAL(memchr) beqlr 2: li r3,0 blr +EXPORT_SYMBOL(memchr) #ifdef CONFIG_PPC32 _GLOBAL(__clear_user) @@ -125,4 +130,5 @@ _GLOBAL(__clear_user) PPC_LONG 1b,91b PPC_LONG 8b,92b .text +EXPORT_SYMBOL(__clear_user) #endif diff --git a/arch/powerpc/lib/string_64.S b/arch/powerpc/lib/string_64.S index 7bd9549a90a23..57ace356c9490 100644 --- a/arch/powerpc/lib/string_64.S +++ b/arch/powerpc/lib/string_64.S @@ -20,6 +20,7 @@ #include #include +#include .section ".toc","aw" PPC64_CACHES: @@ -200,3 +201,4 @@ err1; dcbz r0,r3 cmpdi r4,32 blt .Lshort_clear b .Lmedium_clear +EXPORT_SYMBOL(__clear_user) diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S index 115347f74ce58..09cc50c8dace3 100644 --- a/arch/powerpc/mm/hash_low_32.S +++ b/arch/powerpc/mm/hash_low_32.S @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef CONFIG_SMP .section .bss @@ -33,6 +34,7 @@ .globl mmu_hash_lock mmu_hash_lock: .space 4 +EXPORT_SYMBOL(mmu_hash_lock) #endif /* CONFIG_SMP */ /* @@ -575,6 +577,7 @@ _GLOBAL(flush_hash_pages) rlwinm r8,r8,0,31,29 /* clear HASHPTE bit */ stwcx. r8,0,r5 /* update the pte */ bne- 33b +EXPORT_SYMBOL(flush_hash_pages) /* Get the address of the primary PTE group in the hash table (r3) */ _GLOBAL(flush_hash_patch_A) diff --git a/arch/powerpc/sysdev/dcr-low.S b/arch/powerpc/sysdev/dcr-low.S index d3098ef1404a2..e687bb2003ff0 100644 --- a/arch/powerpc/sysdev/dcr-low.S +++ b/arch/powerpc/sysdev/dcr-low.S @@ -12,6 +12,7 @@ #include #include #include +#include #define DCR_ACCESS_PROLOG(table) \ cmpli cr0,r3,1024; \ @@ -28,9 +29,11 @@ _GLOBAL(__mfdcr) DCR_ACCESS_PROLOG(__mfdcr_table) +EXPORT_SYMBOL(__mfdcr) _GLOBAL(__mtdcr) DCR_ACCESS_PROLOG(__mtdcr_table) +EXPORT_SYMBOL(__mtdcr) __mfdcr_table: mfdcr r3,0; blr -- GitLab From d3867f0483103b8ff7edfdea3ef1981c03d96891 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 16 Jan 2016 21:39:30 -0500 Subject: [PATCH 0011/1167] sparc: move exports to definitions Acked-by: David S. Miller Signed-off-by: Al Viro --- arch/sparc/include/asm/Kbuild | 1 + arch/sparc/kernel/Makefile | 2 +- arch/sparc/kernel/entry.S | 3 + arch/sparc/kernel/head_32.S | 3 + arch/sparc/kernel/head_64.S | 7 +- arch/sparc/kernel/helpers.S | 2 + arch/sparc/kernel/hvcalls.S | 5 + arch/sparc/kernel/sparc_ksyms.c | 12 ++ arch/sparc/kernel/sparc_ksyms_32.c | 31 ----- arch/sparc/kernel/sparc_ksyms_64.c | 53 --------- arch/sparc/lib/Makefile | 1 - arch/sparc/lib/U1memcpy.S | 2 + arch/sparc/lib/VISsave.S | 2 + arch/sparc/lib/ashldi3.S | 2 + arch/sparc/lib/ashrdi3.S | 2 + arch/sparc/lib/atomic_64.S | 16 ++- arch/sparc/lib/bitops.S | 7 ++ arch/sparc/lib/blockops.S | 3 + arch/sparc/lib/bzero.S | 4 + arch/sparc/lib/checksum_32.S | 3 + arch/sparc/lib/checksum_64.S | 2 + arch/sparc/lib/clear_page.S | 3 + arch/sparc/lib/copy_in_user.S | 2 + arch/sparc/lib/copy_page.S | 2 + arch/sparc/lib/copy_user.S | 2 + arch/sparc/lib/csum_copy.S | 3 + arch/sparc/lib/divdi3.S | 2 + arch/sparc/lib/ffs.S | 3 + arch/sparc/lib/hweight.S | 5 + arch/sparc/lib/ipcsum.S | 2 + arch/sparc/lib/ksyms.c | 174 ----------------------------- arch/sparc/lib/locks.S | 5 + arch/sparc/lib/lshrdi3.S | 2 + arch/sparc/lib/mcount.S | 2 + arch/sparc/lib/memcmp.S | 2 + arch/sparc/lib/memcpy.S | 4 + arch/sparc/lib/memmove.S | 2 + arch/sparc/lib/memscan_32.S | 4 + arch/sparc/lib/memscan_64.S | 4 + arch/sparc/lib/memset.S | 3 + arch/sparc/lib/muldi3.S | 2 + arch/sparc/lib/strlen.S | 2 + arch/sparc/lib/strncmp_32.S | 2 + arch/sparc/lib/strncmp_64.S | 2 + arch/sparc/lib/xor.S | 9 ++ 45 files changed, 141 insertions(+), 265 deletions(-) create mode 100644 arch/sparc/kernel/sparc_ksyms.c delete mode 100644 arch/sparc/kernel/sparc_ksyms_32.c delete mode 100644 arch/sparc/kernel/sparc_ksyms_64.c delete mode 100644 arch/sparc/lib/ksyms.c diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild index 6024c26c05856..cfc918067f80a 100644 --- a/arch/sparc/include/asm/Kbuild +++ b/arch/sparc/include/asm/Kbuild @@ -6,6 +6,7 @@ generic-y += cputime.h generic-y += div64.h generic-y += emergency-restart.h generic-y += exec.h +generic-y += export.h generic-y += irq_regs.h generic-y += irq_work.h generic-y += linkage.h diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index fdb13327fded3..fa3c02d411389 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -86,7 +86,7 @@ obj-y += auxio_$(BITS).o obj-$(CONFIG_SUN_PM) += apc.o pmc.o obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_MODULES) += sparc_ksyms_$(BITS).o +obj-$(CONFIG_MODULES) += sparc_ksyms.o obj-$(CONFIG_SPARC_LED) += led.o obj-$(CONFIG_KGDB) += kgdb_$(BITS).o diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 07918ab3062e1..d85bdb9998193 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -29,6 +29,7 @@ #include #include +#include #define curptr g6 @@ -1207,6 +1208,8 @@ delay_continue: ret restore +EXPORT_SYMBOL(__udelay) +EXPORT_SYMBOL(__ndelay) /* Handle a software breakpoint */ /* We have to inform parent that child has stopped */ diff --git a/arch/sparc/kernel/head_32.S b/arch/sparc/kernel/head_32.S index 3d92c0a8f6c49..7bb317b87ddeb 100644 --- a/arch/sparc/kernel/head_32.S +++ b/arch/sparc/kernel/head_32.S @@ -24,6 +24,7 @@ #include /* TI_UWINMASK */ #include #include /* SRMMU_PGDIR_SHIFT */ +#include .data /* The following are used with the prom_vector node-ops to figure out @@ -60,6 +61,7 @@ sun4e_notsup: */ .globl empty_zero_page empty_zero_page: .skip PAGE_SIZE +EXPORT_SYMBOL(empty_zero_page) .global root_flags .global ram_flags @@ -813,3 +815,4 @@ lvl14_save: __ret_efault: ret restore %g0, -EFAULT, %o0 +EXPORT_SYMBOL(__ret_efault) diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S index a076b4249e622..beba6c11554cb 100644 --- a/arch/sparc/kernel/head_64.S +++ b/arch/sparc/kernel/head_64.S @@ -32,7 +32,8 @@ #include #include #include - +#include + /* This section from from _start to sparc64_boot_end should fit into * 0x0000000000404000 to 0x0000000000408000. */ @@ -143,6 +144,7 @@ prom_cpu_compatible: .skip 64 prom_root_node: .word 0 +EXPORT_SYMBOL(prom_root_node) prom_mmu_ihandle_cache: .word 0 prom_boot_mapped_pc: @@ -158,6 +160,7 @@ is_sun4v: .word 0 sun4v_chip_type: .word SUN4V_CHIP_INVALID +EXPORT_SYMBOL(sun4v_chip_type) 1: rd %pc, %l0 @@ -920,6 +923,7 @@ swapper_4m_tsb: .globl prom_tba, tlb_type prom_tba: .xword 0 tlb_type: .word 0 /* Must NOT end up in BSS */ +EXPORT_SYMBOL(tlb_type) .section ".fixup",#alloc,#execinstr .globl __ret_efault, __retl_efault, __ret_one, __retl_one @@ -927,6 +931,7 @@ ENTRY(__ret_efault) ret restore %g0, -EFAULT, %o0 ENDPROC(__ret_efault) +EXPORT_SYMBOL(__ret_efault) ENTRY(__retl_efault) retl diff --git a/arch/sparc/kernel/helpers.S b/arch/sparc/kernel/helpers.S index 314dd0c9fc5b2..e4e5b832fcb6f 100644 --- a/arch/sparc/kernel/helpers.S +++ b/arch/sparc/kernel/helpers.S @@ -15,6 +15,7 @@ __flushw_user: 2: retl nop .size __flushw_user,.-__flushw_user +EXPORT_SYMBOL(__flushw_user) /* Flush %fp and %i7 to the stack for all register * windows active inside of the cpu. This allows @@ -61,3 +62,4 @@ real_hard_smp_processor_id: .size hard_smp_processor_id,.-hard_smp_processor_id #endif .size real_hard_smp_processor_id,.-real_hard_smp_processor_id +EXPORT_SYMBOL_GPL(real_hard_smp_processor_id) diff --git a/arch/sparc/kernel/hvcalls.S b/arch/sparc/kernel/hvcalls.S index d127130bf4246..4116ee5c77913 100644 --- a/arch/sparc/kernel/hvcalls.S +++ b/arch/sparc/kernel/hvcalls.S @@ -343,6 +343,7 @@ ENTRY(sun4v_mach_set_watchdog) 0: retl nop ENDPROC(sun4v_mach_set_watchdog) +EXPORT_SYMBOL(sun4v_mach_set_watchdog) /* No inputs and does not return. */ ENTRY(sun4v_mach_sir) @@ -776,6 +777,7 @@ ENTRY(sun4v_niagara_getperf) retl nop ENDPROC(sun4v_niagara_getperf) +EXPORT_SYMBOL(sun4v_niagara_getperf) ENTRY(sun4v_niagara_setperf) mov HV_FAST_SET_PERFREG, %o5 @@ -783,6 +785,7 @@ ENTRY(sun4v_niagara_setperf) retl nop ENDPROC(sun4v_niagara_setperf) +EXPORT_SYMBOL(sun4v_niagara_setperf) ENTRY(sun4v_niagara2_getperf) mov %o0, %o4 @@ -792,6 +795,7 @@ ENTRY(sun4v_niagara2_getperf) retl nop ENDPROC(sun4v_niagara2_getperf) +EXPORT_SYMBOL(sun4v_niagara2_getperf) ENTRY(sun4v_niagara2_setperf) mov HV_FAST_N2_SET_PERFREG, %o5 @@ -799,6 +803,7 @@ ENTRY(sun4v_niagara2_setperf) retl nop ENDPROC(sun4v_niagara2_setperf) +EXPORT_SYMBOL(sun4v_niagara2_setperf) ENTRY(sun4v_reboot_data_set) mov HV_FAST_REBOOT_DATA_SET, %o5 diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c new file mode 100644 index 0000000000000..09aa69e422e5e --- /dev/null +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -0,0 +1,12 @@ +/* + * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + */ + +#include +#include + +/* This is needed only for drivers/sbus/char/openprom.c */ +EXPORT_SYMBOL(saved_command_line); diff --git a/arch/sparc/kernel/sparc_ksyms_32.c b/arch/sparc/kernel/sparc_ksyms_32.c deleted file mode 100644 index bf4ccb10a78c6..0000000000000 --- a/arch/sparc/kernel/sparc_ksyms_32.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) - */ - -#include - -#include -#include -#include -#include -#include - -struct poll { - int fd; - short events; - short revents; -}; - -/* from entry.S */ -EXPORT_SYMBOL(__udelay); -EXPORT_SYMBOL(__ndelay); - -/* from head_32.S */ -EXPORT_SYMBOL(__ret_efault); -EXPORT_SYMBOL(empty_zero_page); - -/* Exporting a symbol from /init/main.c */ -EXPORT_SYMBOL(saved_command_line); diff --git a/arch/sparc/kernel/sparc_ksyms_64.c b/arch/sparc/kernel/sparc_ksyms_64.c deleted file mode 100644 index 9e034f29dcc52..0000000000000 --- a/arch/sparc/kernel/sparc_ksyms_64.c +++ /dev/null @@ -1,53 +0,0 @@ -/* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. - * - * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net) - * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -struct poll { - int fd; - short events; - short revents; -}; - -/* from helpers.S */ -EXPORT_SYMBOL(__flushw_user); -EXPORT_SYMBOL_GPL(real_hard_smp_processor_id); - -/* from head_64.S */ -EXPORT_SYMBOL(__ret_efault); -EXPORT_SYMBOL(tlb_type); -EXPORT_SYMBOL(sun4v_chip_type); -EXPORT_SYMBOL(prom_root_node); - -/* from hvcalls.S */ -EXPORT_SYMBOL(sun4v_niagara_getperf); -EXPORT_SYMBOL(sun4v_niagara_setperf); -EXPORT_SYMBOL(sun4v_niagara2_getperf); -EXPORT_SYMBOL(sun4v_niagara2_setperf); -EXPORT_SYMBOL(sun4v_mach_set_watchdog); - -/* from hweight.S */ -EXPORT_SYMBOL(__arch_hweight8); -EXPORT_SYMBOL(__arch_hweight16); -EXPORT_SYMBOL(__arch_hweight32); -EXPORT_SYMBOL(__arch_hweight64); - -/* from ffs_ffz.S */ -EXPORT_SYMBOL(ffs); -EXPORT_SYMBOL(__ffs); - -/* Exporting a symbol from /init/main.c */ -EXPORT_SYMBOL(saved_command_line); diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index 3269b0234093b..885f00e81d1ab 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -43,5 +43,4 @@ lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o obj-$(CONFIG_SPARC64) += iomap.o obj-$(CONFIG_SPARC32) += atomic32.o ucmpdi2.o -obj-y += ksyms.o obj-$(CONFIG_SPARC64) += PeeCeeI.o diff --git a/arch/sparc/lib/U1memcpy.S b/arch/sparc/lib/U1memcpy.S index 3e6209ebb7d78..97e1b211090c2 100644 --- a/arch/sparc/lib/U1memcpy.S +++ b/arch/sparc/lib/U1memcpy.S @@ -7,6 +7,7 @@ #ifdef __KERNEL__ #include #include +#include #define GLOBAL_SPARE g7 #else #define GLOBAL_SPARE g5 @@ -567,3 +568,4 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ mov EX_RETVAL(%o4), %o0 .size FUNC_NAME, .-FUNC_NAME +EXPORT_SYMBOL(FUNC_NAME) diff --git a/arch/sparc/lib/VISsave.S b/arch/sparc/lib/VISsave.S index 62c2647bd5cef..1c7b6a39b9424 100644 --- a/arch/sparc/lib/VISsave.S +++ b/arch/sparc/lib/VISsave.S @@ -13,6 +13,7 @@ #include #include #include +#include /* On entry: %o5=current FPRS value, %g7 is callers address */ /* May clobber %o5, %g1, %g2, %g3, %g7, %icc, %xcc */ @@ -79,3 +80,4 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3 80: jmpl %g7 + %g0, %g0 nop ENDPROC(VISenter) +EXPORT_SYMBOL(VISenter) diff --git a/arch/sparc/lib/ashldi3.S b/arch/sparc/lib/ashldi3.S index 86f60de07b0a3..c8b1cf71bc732 100644 --- a/arch/sparc/lib/ashldi3.S +++ b/arch/sparc/lib/ashldi3.S @@ -6,6 +6,7 @@ */ #include +#include .text ENTRY(__ashldi3) @@ -33,3 +34,4 @@ ENTRY(__ashldi3) retl nop ENDPROC(__ashldi3) +EXPORT_SYMBOL(__ashldi3) diff --git a/arch/sparc/lib/ashrdi3.S b/arch/sparc/lib/ashrdi3.S index 6eb8ba2dd50e0..4310256e79647 100644 --- a/arch/sparc/lib/ashrdi3.S +++ b/arch/sparc/lib/ashrdi3.S @@ -6,6 +6,7 @@ */ #include +#include .text ENTRY(__ashrdi3) @@ -35,3 +36,4 @@ ENTRY(__ashrdi3) jmpl %o7 + 8, %g0 nop ENDPROC(__ashrdi3) +EXPORT_SYMBOL(__ashrdi3) diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index a5c5a0279cccc..1c6a1bde51388 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S @@ -6,6 +6,7 @@ #include #include #include +#include .text @@ -29,6 +30,7 @@ ENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ nop; \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ ENDPROC(atomic_##op); \ +EXPORT_SYMBOL(atomic_##op); #define ATOMIC_OP_RETURN(op) \ ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ @@ -42,7 +44,8 @@ ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ retl; \ sra %g1, 0, %o0; \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ -ENDPROC(atomic_##op##_return); +ENDPROC(atomic_##op##_return); \ +EXPORT_SYMBOL(atomic_##op##_return); #define ATOMIC_FETCH_OP(op) \ ENTRY(atomic_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ @@ -56,7 +59,8 @@ ENTRY(atomic_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ retl; \ sra %g1, 0, %o0; \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ -ENDPROC(atomic_fetch_##op); +ENDPROC(atomic_fetch_##op); \ +EXPORT_SYMBOL(atomic_fetch_##op); #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) @@ -88,6 +92,7 @@ ENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ nop; \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ ENDPROC(atomic64_##op); \ +EXPORT_SYMBOL(atomic64_##op); #define ATOMIC64_OP_RETURN(op) \ ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ @@ -101,7 +106,8 @@ ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ retl; \ op %g1, %o0, %o0; \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ -ENDPROC(atomic64_##op##_return); +ENDPROC(atomic64_##op##_return); \ +EXPORT_SYMBOL(atomic64_##op##_return); #define ATOMIC64_FETCH_OP(op) \ ENTRY(atomic64_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ @@ -115,7 +121,8 @@ ENTRY(atomic64_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ retl; \ mov %g1, %o0; \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ -ENDPROC(atomic64_fetch_##op); +ENDPROC(atomic64_fetch_##op); \ +EXPORT_SYMBOL(atomic64_fetch_##op); #define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) ATOMIC64_FETCH_OP(op) @@ -147,3 +154,4 @@ ENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */ sub %g1, 1, %o0 2: BACKOFF_SPIN(%o2, %o3, 1b) ENDPROC(atomic64_dec_if_positive) +EXPORT_SYMBOL(atomic64_dec_if_positive) diff --git a/arch/sparc/lib/bitops.S b/arch/sparc/lib/bitops.S index 36f72cc0e67e6..7031bf1587cb6 100644 --- a/arch/sparc/lib/bitops.S +++ b/arch/sparc/lib/bitops.S @@ -6,6 +6,7 @@ #include #include #include +#include .text @@ -29,6 +30,7 @@ ENTRY(test_and_set_bit) /* %o0=nr, %o1=addr */ nop 2: BACKOFF_SPIN(%o3, %o4, 1b) ENDPROC(test_and_set_bit) +EXPORT_SYMBOL(test_and_set_bit) ENTRY(test_and_clear_bit) /* %o0=nr, %o1=addr */ BACKOFF_SETUP(%o3) @@ -50,6 +52,7 @@ ENTRY(test_and_clear_bit) /* %o0=nr, %o1=addr */ nop 2: BACKOFF_SPIN(%o3, %o4, 1b) ENDPROC(test_and_clear_bit) +EXPORT_SYMBOL(test_and_clear_bit) ENTRY(test_and_change_bit) /* %o0=nr, %o1=addr */ BACKOFF_SETUP(%o3) @@ -71,6 +74,7 @@ ENTRY(test_and_change_bit) /* %o0=nr, %o1=addr */ nop 2: BACKOFF_SPIN(%o3, %o4, 1b) ENDPROC(test_and_change_bit) +EXPORT_SYMBOL(test_and_change_bit) ENTRY(set_bit) /* %o0=nr, %o1=addr */ BACKOFF_SETUP(%o3) @@ -90,6 +94,7 @@ ENTRY(set_bit) /* %o0=nr, %o1=addr */ nop 2: BACKOFF_SPIN(%o3, %o4, 1b) ENDPROC(set_bit) +EXPORT_SYMBOL(set_bit) ENTRY(clear_bit) /* %o0=nr, %o1=addr */ BACKOFF_SETUP(%o3) @@ -109,6 +114,7 @@ ENTRY(clear_bit) /* %o0=nr, %o1=addr */ nop 2: BACKOFF_SPIN(%o3, %o4, 1b) ENDPROC(clear_bit) +EXPORT_SYMBOL(clear_bit) ENTRY(change_bit) /* %o0=nr, %o1=addr */ BACKOFF_SETUP(%o3) @@ -128,3 +134,4 @@ ENTRY(change_bit) /* %o0=nr, %o1=addr */ nop 2: BACKOFF_SPIN(%o3, %o4, 1b) ENDPROC(change_bit) +EXPORT_SYMBOL(change_bit) diff --git a/arch/sparc/lib/blockops.S b/arch/sparc/lib/blockops.S index 3c771011ff4b0..1f2692d59d18e 100644 --- a/arch/sparc/lib/blockops.S +++ b/arch/sparc/lib/blockops.S @@ -6,6 +6,7 @@ #include #include +#include /* Zero out 64 bytes of memory at (buf + offset). * Assumes %g1 contains zero. @@ -64,6 +65,7 @@ ENTRY(bzero_1page) retl nop ENDPROC(bzero_1page) +EXPORT_SYMBOL(bzero_1page) ENTRY(__copy_1page) /* NOTE: If you change the number of insns of this routine, please check @@ -87,3 +89,4 @@ ENTRY(__copy_1page) retl nop ENDPROC(__copy_1page) +EXPORT_SYMBOL(__copy_1page) diff --git a/arch/sparc/lib/bzero.S b/arch/sparc/lib/bzero.S index 8c058114b6490..3bb1914c4fa48 100644 --- a/arch/sparc/lib/bzero.S +++ b/arch/sparc/lib/bzero.S @@ -5,6 +5,7 @@ */ #include +#include .text @@ -78,6 +79,8 @@ __bzero_done: mov %o3, %o0 ENDPROC(__bzero) ENDPROC(memset) +EXPORT_SYMBOL(__bzero) +EXPORT_SYMBOL(memset) #define EX_ST(x,y) \ 98: x,y; \ @@ -143,3 +146,4 @@ __clear_user_done: retl clr %o0 ENDPROC(__clear_user) +EXPORT_SYMBOL(__clear_user) diff --git a/arch/sparc/lib/checksum_32.S b/arch/sparc/lib/checksum_32.S index 0084c3361e15a..c9d8b62321116 100644 --- a/arch/sparc/lib/checksum_32.S +++ b/arch/sparc/lib/checksum_32.S @@ -14,6 +14,7 @@ */ #include +#include #define CSUM_BIGCHUNK(buf, offset, sum, t0, t1, t2, t3, t4, t5) \ ldd [buf + offset + 0x00], t0; \ @@ -104,6 +105,7 @@ csum_partial_fix_alignment: * buffer of size 0x20. Follow the code path for that case. */ .globl csum_partial + EXPORT_SYMBOL(csum_partial) csum_partial: /* %o0=buf, %o1=len, %o2=sum */ andcc %o0, 0x7, %g0 ! alignment problems? bne csum_partial_fix_alignment ! yep, handle it @@ -335,6 +337,7 @@ cc_dword_align: */ .align 8 .globl __csum_partial_copy_sparc_generic + EXPORT_SYMBOL(__csum_partial_copy_sparc_generic) __csum_partial_copy_sparc_generic: /* %o0=src, %o1=dest, %g1=len, %g7=sum */ xor %o0, %o1, %o4 ! get changing bits diff --git a/arch/sparc/lib/checksum_64.S b/arch/sparc/lib/checksum_64.S index 1d230f693dc4b..f6732174fe6bd 100644 --- a/arch/sparc/lib/checksum_64.S +++ b/arch/sparc/lib/checksum_64.S @@ -13,6 +13,7 @@ * BSD4.4 portable checksum routine */ +#include .text csum_partial_fix_alignment: @@ -37,6 +38,7 @@ csum_partial_fix_alignment: .align 32 .globl csum_partial + EXPORT_SYMBOL(csum_partial) csum_partial: /* %o0=buff, %o1=len, %o2=sum */ prefetch [%o0 + 0x000], #n_reads clr %o4 diff --git a/arch/sparc/lib/clear_page.S b/arch/sparc/lib/clear_page.S index 46272dfc26e81..f30d6b78afbd6 100644 --- a/arch/sparc/lib/clear_page.S +++ b/arch/sparc/lib/clear_page.S @@ -10,6 +10,7 @@ #include #include #include +#include /* What we used to do was lock a TLB entry into a specific * TLB slot, clear the page with interrupts disabled, then @@ -26,6 +27,7 @@ .text .globl _clear_page + EXPORT_SYMBOL(_clear_page) _clear_page: /* %o0=dest */ ba,pt %xcc, clear_page_common clr %o4 @@ -35,6 +37,7 @@ _clear_page: /* %o0=dest */ */ .align 32 .globl clear_user_page + EXPORT_SYMBOL(clear_user_page) clear_user_page: /* %o0=dest, %o1=vaddr */ lduw [%g6 + TI_PRE_COUNT], %o2 sethi %hi(PAGE_OFFSET), %g2 diff --git a/arch/sparc/lib/copy_in_user.S b/arch/sparc/lib/copy_in_user.S index 302c0e60dc2ce..482de093bdaeb 100644 --- a/arch/sparc/lib/copy_in_user.S +++ b/arch/sparc/lib/copy_in_user.S @@ -5,6 +5,7 @@ #include #include +#include #define XCC xcc @@ -90,3 +91,4 @@ ENTRY(___copy_in_user) /* %o0=dst, %o1=src, %o2=len */ retl clr %o0 ENDPROC(___copy_in_user) +EXPORT_SYMBOL(___copy_in_user) diff --git a/arch/sparc/lib/copy_page.S b/arch/sparc/lib/copy_page.S index dd16c61f32636..7197b72508951 100644 --- a/arch/sparc/lib/copy_page.S +++ b/arch/sparc/lib/copy_page.S @@ -10,6 +10,7 @@ #include #include #include +#include /* What we used to do was lock a TLB entry into a specific * TLB slot, clear the page with interrupts disabled, then @@ -44,6 +45,7 @@ .align 32 .globl copy_user_page .type copy_user_page,#function + EXPORT_SYMBOL(copy_user_page) copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ lduw [%g6 + TI_PRE_COUNT], %o4 sethi %hi(PAGE_OFFSET), %g2 diff --git a/arch/sparc/lib/copy_user.S b/arch/sparc/lib/copy_user.S index ef095b6c43b15..cea644dc67a62 100644 --- a/arch/sparc/lib/copy_user.S +++ b/arch/sparc/lib/copy_user.S @@ -15,6 +15,7 @@ #include #include #include +#include /* Work around cpp -rob */ #define ALLOC #alloc @@ -119,6 +120,7 @@ __copy_user_begin: .globl __copy_user + EXPORT_SYMBOL(__copy_user) dword_align: andcc %o1, 1, %g0 be 4f diff --git a/arch/sparc/lib/csum_copy.S b/arch/sparc/lib/csum_copy.S index e566c770a0f63..0ecbafc30fd00 100644 --- a/arch/sparc/lib/csum_copy.S +++ b/arch/sparc/lib/csum_copy.S @@ -3,6 +3,8 @@ * Copyright (C) 2005 David S. Miller */ +#include + #ifdef __KERNEL__ #define GLOBAL_SPARE %g7 #else @@ -63,6 +65,7 @@ add %o5, %o4, %o4 .globl FUNC_NAME + EXPORT_SYMBOL(FUNC_NAME) FUNC_NAME: /* %o0=src, %o1=dst, %o2=len, %o3=sum */ LOAD(prefetch, %o0 + 0x000, #n_reads) xor %o0, %o1, %g1 diff --git a/arch/sparc/lib/divdi3.S b/arch/sparc/lib/divdi3.S index 9614b48b6ef83..a2b5a976be336 100644 --- a/arch/sparc/lib/divdi3.S +++ b/arch/sparc/lib/divdi3.S @@ -17,6 +17,7 @@ along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include .text .align 4 .globl __divdi3 @@ -279,3 +280,4 @@ __divdi3: .LL81: ret restore +EXPORT_SYMBOL(__divdi3) diff --git a/arch/sparc/lib/ffs.S b/arch/sparc/lib/ffs.S index b39389f698995..23aab144d28e5 100644 --- a/arch/sparc/lib/ffs.S +++ b/arch/sparc/lib/ffs.S @@ -1,4 +1,5 @@ #include +#include .register %g2,#scratch @@ -65,6 +66,8 @@ ENTRY(__ffs) add %o2, %g1, %o0 ENDPROC(ffs) ENDPROC(__ffs) +EXPORT_SYMBOL(__ffs) +EXPORT_SYMBOL(ffs) .section .popc_6insn_patch, "ax" .word ffs diff --git a/arch/sparc/lib/hweight.S b/arch/sparc/lib/hweight.S index 95414e0a6808d..f9985f129fb68 100644 --- a/arch/sparc/lib/hweight.S +++ b/arch/sparc/lib/hweight.S @@ -1,4 +1,5 @@ #include +#include .text .align 32 @@ -7,6 +8,7 @@ ENTRY(__arch_hweight8) nop nop ENDPROC(__arch_hweight8) +EXPORT_SYMBOL(__arch_hweight8) .section .popc_3insn_patch, "ax" .word __arch_hweight8 sllx %o0, 64-8, %g1 @@ -19,6 +21,7 @@ ENTRY(__arch_hweight16) nop nop ENDPROC(__arch_hweight16) +EXPORT_SYMBOL(__arch_hweight16) .section .popc_3insn_patch, "ax" .word __arch_hweight16 sllx %o0, 64-16, %g1 @@ -31,6 +34,7 @@ ENTRY(__arch_hweight32) nop nop ENDPROC(__arch_hweight32) +EXPORT_SYMBOL(__arch_hweight32) .section .popc_3insn_patch, "ax" .word __arch_hweight32 sllx %o0, 64-32, %g1 @@ -43,6 +47,7 @@ ENTRY(__arch_hweight64) nop nop ENDPROC(__arch_hweight64) +EXPORT_SYMBOL(__arch_hweight64) .section .popc_3insn_patch, "ax" .word __arch_hweight64 retl diff --git a/arch/sparc/lib/ipcsum.S b/arch/sparc/lib/ipcsum.S index 4742d59029ee3..5d61648b53dd2 100644 --- a/arch/sparc/lib/ipcsum.S +++ b/arch/sparc/lib/ipcsum.S @@ -1,4 +1,5 @@ #include +#include .text ENTRY(ip_fast_csum) /* %o0 = iph, %o1 = ihl */ @@ -31,3 +32,4 @@ ENTRY(ip_fast_csum) /* %o0 = iph, %o1 = ihl */ retl and %o2, %o1, %o0 ENDPROC(ip_fast_csum) +EXPORT_SYMBOL(ip_fast_csum) diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c deleted file mode 100644 index de5e97817bdb6..0000000000000 --- a/arch/sparc/lib/ksyms.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Export of symbols defined in assembler - */ - -/* Tell string.h we don't want memcpy etc. as cpp defines */ -#define EXPORT_SYMTAB_STROPS - -#include -#include -#include - -#include -#include -#include - -/* string functions */ -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strncmp); - -/* mem* functions */ -extern void *__memscan_zero(void *, size_t); -extern void *__memscan_generic(void *, int, size_t); -extern void *__bzero(void *, size_t); - -EXPORT_SYMBOL(memscan); -EXPORT_SYMBOL(__memscan_zero); -EXPORT_SYMBOL(__memscan_generic); -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(__bzero); - -/* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial); - -#ifdef CONFIG_MCOUNT -EXPORT_SYMBOL(_mcount); -#endif - -/* - * sparc - */ -#ifdef CONFIG_SPARC32 -extern int __ashrdi3(int, int); -extern int __ashldi3(int, int); -extern int __lshrdi3(int, int); -extern int __muldi3(int, int); -extern int __divdi3(int, int); - -extern void (*__copy_1page)(void *, const void *); -extern void (*bzero_1page)(void *); - -extern void ___rw_read_enter(void); -extern void ___rw_read_try(void); -extern void ___rw_read_exit(void); -extern void ___rw_write_enter(void); - -/* Networking helper routines. */ -EXPORT_SYMBOL(__csum_partial_copy_sparc_generic); - -/* Special internal versions of library functions. */ -EXPORT_SYMBOL(__copy_1page); -EXPORT_SYMBOL(__memmove); -EXPORT_SYMBOL(bzero_1page); - -/* Moving data to/from/in userspace. */ -EXPORT_SYMBOL(__copy_user); - -/* Used by asm/spinlock.h */ -#ifdef CONFIG_SMP -EXPORT_SYMBOL(___rw_read_enter); -EXPORT_SYMBOL(___rw_read_try); -EXPORT_SYMBOL(___rw_read_exit); -EXPORT_SYMBOL(___rw_write_enter); -#endif - -EXPORT_SYMBOL(__ashrdi3); -EXPORT_SYMBOL(__ashldi3); -EXPORT_SYMBOL(__lshrdi3); -EXPORT_SYMBOL(__muldi3); -EXPORT_SYMBOL(__divdi3); -#endif - -/* - * sparc64 - */ -#ifdef CONFIG_SPARC64 -/* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy_nocheck); -EXPORT_SYMBOL(__csum_partial_copy_from_user); -EXPORT_SYMBOL(__csum_partial_copy_to_user); -EXPORT_SYMBOL(ip_fast_csum); - -/* Moving data to/from/in userspace. */ -EXPORT_SYMBOL(___copy_to_user); -EXPORT_SYMBOL(___copy_from_user); -EXPORT_SYMBOL(___copy_in_user); -EXPORT_SYMBOL(__clear_user); - -/* Atomic counter implementation. */ -#define ATOMIC_OP(op) \ -EXPORT_SYMBOL(atomic_##op); \ -EXPORT_SYMBOL(atomic64_##op); - -#define ATOMIC_OP_RETURN(op) \ -EXPORT_SYMBOL(atomic_##op##_return); \ -EXPORT_SYMBOL(atomic64_##op##_return); - -#define ATOMIC_FETCH_OP(op) \ -EXPORT_SYMBOL(atomic_fetch_##op); \ -EXPORT_SYMBOL(atomic64_fetch_##op); - -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) - -ATOMIC_OPS(add) -ATOMIC_OPS(sub) - -#undef ATOMIC_OPS -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) - -ATOMIC_OPS(and) -ATOMIC_OPS(or) -ATOMIC_OPS(xor) - -#undef ATOMIC_OPS -#undef ATOMIC_FETCH_OP -#undef ATOMIC_OP_RETURN -#undef ATOMIC_OP - -EXPORT_SYMBOL(atomic64_dec_if_positive); - -/* Atomic bit operations. */ -EXPORT_SYMBOL(test_and_set_bit); -EXPORT_SYMBOL(test_and_clear_bit); -EXPORT_SYMBOL(test_and_change_bit); -EXPORT_SYMBOL(set_bit); -EXPORT_SYMBOL(clear_bit); -EXPORT_SYMBOL(change_bit); - -/* Special internal versions of library functions. */ -EXPORT_SYMBOL(_clear_page); -EXPORT_SYMBOL(clear_user_page); -EXPORT_SYMBOL(copy_user_page); - -/* RAID code needs this */ -void VISenter(void); -EXPORT_SYMBOL(VISenter); - -extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); -extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *, - unsigned long *); -extern void xor_vis_4(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *); -extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *, unsigned long *); -EXPORT_SYMBOL(xor_vis_2); -EXPORT_SYMBOL(xor_vis_3); -EXPORT_SYMBOL(xor_vis_4); -EXPORT_SYMBOL(xor_vis_5); - -extern void xor_niagara_2(unsigned long, unsigned long *, unsigned long *); -extern void xor_niagara_3(unsigned long, unsigned long *, unsigned long *, - unsigned long *); -extern void xor_niagara_4(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *); -extern void xor_niagara_5(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *, unsigned long *); - -EXPORT_SYMBOL(xor_niagara_2); -EXPORT_SYMBOL(xor_niagara_3); -EXPORT_SYMBOL(xor_niagara_4); -EXPORT_SYMBOL(xor_niagara_5); -#endif diff --git a/arch/sparc/lib/locks.S b/arch/sparc/lib/locks.S index 64f53f2b673de..f38c4e59d078f 100644 --- a/arch/sparc/lib/locks.S +++ b/arch/sparc/lib/locks.S @@ -10,6 +10,7 @@ #include #include #include +#include .text .align 4 @@ -48,6 +49,7 @@ ___rw_write_enter_spin_on_wlock: ld [%g1], %g2 .globl ___rw_read_enter +EXPORT_SYMBOL(___rw_read_enter) ___rw_read_enter: orcc %g2, 0x0, %g0 bne,a ___rw_read_enter_spin_on_wlock @@ -59,6 +61,7 @@ ___rw_read_enter: mov %g4, %o7 .globl ___rw_read_exit +EXPORT_SYMBOL(___rw_read_exit) ___rw_read_exit: orcc %g2, 0x0, %g0 bne,a ___rw_read_exit_spin_on_wlock @@ -70,6 +73,7 @@ ___rw_read_exit: mov %g4, %o7 .globl ___rw_read_try +EXPORT_SYMBOL(___rw_read_try) ___rw_read_try: orcc %g2, 0x0, %g0 bne ___rw_read_try_spin_on_wlock @@ -81,6 +85,7 @@ ___rw_read_try: mov %g4, %o7 .globl ___rw_write_enter +EXPORT_SYMBOL(___rw_write_enter) ___rw_write_enter: orcc %g2, 0x0, %g0 bne ___rw_write_enter_spin_on_wlock diff --git a/arch/sparc/lib/lshrdi3.S b/arch/sparc/lib/lshrdi3.S index 60ebc7cdbee04..c9b9373f8d810 100644 --- a/arch/sparc/lib/lshrdi3.S +++ b/arch/sparc/lib/lshrdi3.S @@ -1,4 +1,5 @@ #include +#include ENTRY(__lshrdi3) cmp %o2, 0 @@ -25,3 +26,4 @@ ENTRY(__lshrdi3) retl nop ENDPROC(__lshrdi3) +EXPORT_SYMBOL(__lshrdi3) diff --git a/arch/sparc/lib/mcount.S b/arch/sparc/lib/mcount.S index 0b0ed4d34219b..194f383611c02 100644 --- a/arch/sparc/lib/mcount.S +++ b/arch/sparc/lib/mcount.S @@ -6,6 +6,7 @@ */ #include +#include /* * This is the main variant and is called by C code. GCC's -pg option @@ -16,6 +17,7 @@ .align 32 .globl _mcount .type _mcount,#function + EXPORT_SYMBOL(_mcount) .globl mcount .type mcount,#function _mcount: diff --git a/arch/sparc/lib/memcmp.S b/arch/sparc/lib/memcmp.S index efa106c41ed0a..cee7f30dbb613 100644 --- a/arch/sparc/lib/memcmp.S +++ b/arch/sparc/lib/memcmp.S @@ -6,6 +6,7 @@ #include #include +#include .text ENTRY(memcmp) @@ -25,3 +26,4 @@ ENTRY(memcmp) 2: retl mov 0, %o0 ENDPROC(memcmp) +EXPORT_SYMBOL(memcmp) diff --git a/arch/sparc/lib/memcpy.S b/arch/sparc/lib/memcpy.S index 4d8c497517bd6..1dc8ec5b6bd9f 100644 --- a/arch/sparc/lib/memcpy.S +++ b/arch/sparc/lib/memcpy.S @@ -7,6 +7,7 @@ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#include #define FUNC(x) \ .globl x; \ .type x,@function; \ @@ -143,8 +144,10 @@ x: #ifdef __KERNEL__ FUNC(amemmove) FUNC(__memmove) +EXPORT_SYMBOL(__memmove) #endif FUNC(memmove) +EXPORT_SYMBOL(memmove) cmp %o0, %o1 mov %o0, %g7 bleu 9f @@ -202,6 +205,7 @@ FUNC(memmove) add %o0, 2, %o0 FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ +EXPORT_SYMBOL(memcpy) sub %o0, %o1, %o4 mov %o0, %g7 diff --git a/arch/sparc/lib/memmove.S b/arch/sparc/lib/memmove.S index 857ad4f8905f9..012cdb6ca4677 100644 --- a/arch/sparc/lib/memmove.S +++ b/arch/sparc/lib/memmove.S @@ -5,6 +5,7 @@ */ #include +#include .text ENTRY(memmove) /* o0=dst o1=src o2=len */ @@ -57,3 +58,4 @@ ENTRY(memmove) /* o0=dst o1=src o2=len */ stb %g7, [%o0 - 0x1] ba,a,pt %xcc, 99b ENDPROC(memmove) +EXPORT_SYMBOL(memmove) diff --git a/arch/sparc/lib/memscan_32.S b/arch/sparc/lib/memscan_32.S index 4ff1657dfc246..51ce690c42a8e 100644 --- a/arch/sparc/lib/memscan_32.S +++ b/arch/sparc/lib/memscan_32.S @@ -4,6 +4,8 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ +#include + /* In essence, this is just a fancy strlen. */ #define LO_MAGIC 0x01010101 @@ -13,6 +15,8 @@ .align 4 .globl __memscan_zero, __memscan_generic .globl memscan +EXPORT_SYMBOL(__memscan_zero) +EXPORT_SYMBOL(__memscan_generic) __memscan_zero: /* %o0 = addr, %o1 = size */ cmp %o1, 0 diff --git a/arch/sparc/lib/memscan_64.S b/arch/sparc/lib/memscan_64.S index 5686dfa5dc159..daa96f4b03e60 100644 --- a/arch/sparc/lib/memscan_64.S +++ b/arch/sparc/lib/memscan_64.S @@ -5,6 +5,8 @@ * Copyright (C) 1998 David S. Miller (davem@redhat.com) */ + #include + #define HI_MAGIC 0x8080808080808080 #define LO_MAGIC 0x0101010101010101 #define ASI_PL 0x88 @@ -13,6 +15,8 @@ .align 32 .globl __memscan_zero, __memscan_generic .globl memscan + EXPORT_SYMBOL(__memscan_zero) + EXPORT_SYMBOL(__memscan_generic) __memscan_zero: /* %o0 = bufp, %o1 = size */ diff --git a/arch/sparc/lib/memset.S b/arch/sparc/lib/memset.S index f75e6906df146..bb539b42b088a 100644 --- a/arch/sparc/lib/memset.S +++ b/arch/sparc/lib/memset.S @@ -9,6 +9,7 @@ */ #include +#include /* Work around cpp -rob */ #define ALLOC #alloc @@ -63,6 +64,8 @@ __bzero_begin: .globl __bzero .globl memset + EXPORT_SYMBOL(__bzero) + EXPORT_SYMBOL(memset) .globl __memset_start, __memset_end __memset_start: memset: diff --git a/arch/sparc/lib/muldi3.S b/arch/sparc/lib/muldi3.S index 9794939d1c126..17a0f49aef3c0 100644 --- a/arch/sparc/lib/muldi3.S +++ b/arch/sparc/lib/muldi3.S @@ -17,6 +17,7 @@ along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include .text .align 4 .globl __muldi3 @@ -74,3 +75,4 @@ __muldi3: add %l2, %l0, %i0 ret restore %g0, %l3, %o1 +EXPORT_SYMBOL(__muldi3) diff --git a/arch/sparc/lib/strlen.S b/arch/sparc/lib/strlen.S index 536f83507fbff..ca0e7077e8713 100644 --- a/arch/sparc/lib/strlen.S +++ b/arch/sparc/lib/strlen.S @@ -7,6 +7,7 @@ #include #include +#include #define LO_MAGIC 0x01010101 #define HI_MAGIC 0x80808080 @@ -78,3 +79,4 @@ ENTRY(strlen) retl mov 2, %o0 ENDPROC(strlen) +EXPORT_SYMBOL(strlen) diff --git a/arch/sparc/lib/strncmp_32.S b/arch/sparc/lib/strncmp_32.S index c0d1b568c1c56..e3fe014813af8 100644 --- a/arch/sparc/lib/strncmp_32.S +++ b/arch/sparc/lib/strncmp_32.S @@ -4,6 +4,7 @@ */ #include +#include .text ENTRY(strncmp) @@ -116,3 +117,4 @@ ENTRY(strncmp) retl sub %o3, %o0, %o0 ENDPROC(strncmp) +EXPORT_SYMBOL(strncmp) diff --git a/arch/sparc/lib/strncmp_64.S b/arch/sparc/lib/strncmp_64.S index 0656627166f38..efb5f884330d7 100644 --- a/arch/sparc/lib/strncmp_64.S +++ b/arch/sparc/lib/strncmp_64.S @@ -6,6 +6,7 @@ #include #include +#include .text ENTRY(strncmp) @@ -28,3 +29,4 @@ ENTRY(strncmp) retl clr %o0 ENDPROC(strncmp) +EXPORT_SYMBOL(strncmp) diff --git a/arch/sparc/lib/xor.S b/arch/sparc/lib/xor.S index 2c05641c32639..45a49cb618b52 100644 --- a/arch/sparc/lib/xor.S +++ b/arch/sparc/lib/xor.S @@ -13,6 +13,7 @@ #include #include #include +#include /* * Requirements: @@ -90,6 +91,7 @@ ENTRY(xor_vis_2) retl wr %g0, 0, %fprs ENDPROC(xor_vis_2) +EXPORT_SYMBOL(xor_vis_2) ENTRY(xor_vis_3) rd %fprs, %o5 @@ -156,6 +158,7 @@ ENTRY(xor_vis_3) retl wr %g0, 0, %fprs ENDPROC(xor_vis_3) +EXPORT_SYMBOL(xor_vis_3) ENTRY(xor_vis_4) rd %fprs, %o5 @@ -241,6 +244,7 @@ ENTRY(xor_vis_4) retl wr %g0, 0, %fprs ENDPROC(xor_vis_4) +EXPORT_SYMBOL(xor_vis_4) ENTRY(xor_vis_5) save %sp, -192, %sp @@ -347,6 +351,7 @@ ENTRY(xor_vis_5) ret restore ENDPROC(xor_vis_5) +EXPORT_SYMBOL(xor_vis_5) /* Niagara versions. */ ENTRY(xor_niagara_2) /* %o0=bytes, %o1=dest, %o2=src */ @@ -393,6 +398,7 @@ ENTRY(xor_niagara_2) /* %o0=bytes, %o1=dest, %o2=src */ ret restore ENDPROC(xor_niagara_2) +EXPORT_SYMBOL(xor_niagara_2) ENTRY(xor_niagara_3) /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2 */ save %sp, -192, %sp @@ -454,6 +460,7 @@ ENTRY(xor_niagara_3) /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2 */ ret restore ENDPROC(xor_niagara_3) +EXPORT_SYMBOL(xor_niagara_3) ENTRY(xor_niagara_4) /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */ save %sp, -192, %sp @@ -536,6 +543,7 @@ ENTRY(xor_niagara_4) /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */ ret restore ENDPROC(xor_niagara_4) +EXPORT_SYMBOL(xor_niagara_4) ENTRY(xor_niagara_5) /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3, %o5=src4 */ save %sp, -192, %sp @@ -634,3 +642,4 @@ ENTRY(xor_niagara_5) /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3, %o5=s ret restore ENDPROC(xor_niagara_5) +EXPORT_SYMBOL(xor_niagara_5) -- GitLab From 70a6fcf3283a0ac1e11737c6d90c0753f9824e9d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 17 Jan 2016 13:09:11 -0500 Subject: [PATCH 0012/1167] [sparc] unify 32bit and 64bit string.h Acked-by: David S. Miller Signed-off-by: Al Viro --- arch/sparc/include/asm/string.h | 34 ++++++++++++++++++ arch/sparc/include/asm/string_32.h | 56 ------------------------------ arch/sparc/include/asm/string_64.h | 44 ----------------------- arch/sparc/lib/memcpy.S | 5 --- 4 files changed, 34 insertions(+), 105 deletions(-) diff --git a/arch/sparc/include/asm/string.h b/arch/sparc/include/asm/string.h index 98b72a0c8e6e6..86f34be14ce00 100644 --- a/arch/sparc/include/asm/string.h +++ b/arch/sparc/include/asm/string.h @@ -5,4 +5,38 @@ #else #include #endif + +/* First the mem*() things. */ +#define __HAVE_ARCH_MEMMOVE +void *memmove(void *, const void *, __kernel_size_t); + +#define __HAVE_ARCH_MEMCPY +#define memcpy(t, f, n) __builtin_memcpy(t, f, n) + +#define __HAVE_ARCH_MEMSET +#define memset(s, c, count) __builtin_memset(s, c, count) + +#define __HAVE_ARCH_MEMSCAN + +#define memscan(__arg0, __char, __arg2) \ +({ \ + void *__memscan_zero(void *, size_t); \ + void *__memscan_generic(void *, int, size_t); \ + void *__retval, *__addr = (__arg0); \ + size_t __size = (__arg2); \ + \ + if(__builtin_constant_p(__char) && !(__char)) \ + __retval = __memscan_zero(__addr, __size); \ + else \ + __retval = __memscan_generic(__addr, (__char), __size); \ + \ + __retval; \ +}) + +#define __HAVE_ARCH_MEMCMP +int memcmp(const void *,const void *,__kernel_size_t); + +#define __HAVE_ARCH_STRNCMP +int strncmp(const char *, const char *, __kernel_size_t); + #endif diff --git a/arch/sparc/include/asm/string_32.h b/arch/sparc/include/asm/string_32.h index 69974e9246111..649412476a694 100644 --- a/arch/sparc/include/asm/string_32.h +++ b/arch/sparc/include/asm/string_32.h @@ -11,60 +11,4 @@ #include -/* Really, userland/ksyms should not see any of this stuff. */ - -#ifdef __KERNEL__ - -void __memmove(void *,const void *,__kernel_size_t); - -#ifndef EXPORT_SYMTAB_STROPS - -/* First the mem*() things. */ -#define __HAVE_ARCH_MEMMOVE -#undef memmove -#define memmove(_to, _from, _n) \ -({ \ - void *_t = (_to); \ - __memmove(_t, (_from), (_n)); \ - _t; \ -}) - -#define __HAVE_ARCH_MEMCPY -#define memcpy(t, f, n) __builtin_memcpy(t, f, n) - -#define __HAVE_ARCH_MEMSET -#define memset(s, c, count) __builtin_memset(s, c, count) - -#define __HAVE_ARCH_MEMSCAN - -#undef memscan -#define memscan(__arg0, __char, __arg2) \ -({ \ - void *__memscan_zero(void *, size_t); \ - void *__memscan_generic(void *, int, size_t); \ - void *__retval, *__addr = (__arg0); \ - size_t __size = (__arg2); \ - \ - if(__builtin_constant_p(__char) && !(__char)) \ - __retval = __memscan_zero(__addr, __size); \ - else \ - __retval = __memscan_generic(__addr, (__char), __size); \ - \ - __retval; \ -}) - -#define __HAVE_ARCH_MEMCMP -int memcmp(const void *,const void *,__kernel_size_t); - -/* Now the str*() stuff... */ -#define __HAVE_ARCH_STRLEN -__kernel_size_t strlen(const char *); - -#define __HAVE_ARCH_STRNCMP -int strncmp(const char *, const char *, __kernel_size_t); - -#endif /* !EXPORT_SYMTAB_STROPS */ - -#endif /* __KERNEL__ */ - #endif /* !(__SPARC_STRING_H__) */ diff --git a/arch/sparc/include/asm/string_64.h b/arch/sparc/include/asm/string_64.h index 5936b8ff3c050..6b9ccb3086057 100644 --- a/arch/sparc/include/asm/string_64.h +++ b/arch/sparc/include/asm/string_64.h @@ -9,54 +9,10 @@ #ifndef __SPARC64_STRING_H__ #define __SPARC64_STRING_H__ -/* Really, userland/ksyms should not see any of this stuff. */ - -#ifdef __KERNEL__ - #include -#ifndef EXPORT_SYMTAB_STROPS - -/* First the mem*() things. */ -#define __HAVE_ARCH_MEMMOVE -void *memmove(void *, const void *, __kernel_size_t); - -#define __HAVE_ARCH_MEMCPY -#define memcpy(t, f, n) __builtin_memcpy(t, f, n) - -#define __HAVE_ARCH_MEMSET -#define memset(s, c, count) __builtin_memset(s, c, count) - -#define __HAVE_ARCH_MEMSCAN - -#undef memscan -#define memscan(__arg0, __char, __arg2) \ -({ \ - void *__memscan_zero(void *, size_t); \ - void *__memscan_generic(void *, int, size_t); \ - void *__retval, *__addr = (__arg0); \ - size_t __size = (__arg2); \ - \ - if(__builtin_constant_p(__char) && !(__char)) \ - __retval = __memscan_zero(__addr, __size); \ - else \ - __retval = __memscan_generic(__addr, (__char), __size); \ - \ - __retval; \ -}) - -#define __HAVE_ARCH_MEMCMP -int memcmp(const void *,const void *,__kernel_size_t); - /* Now the str*() stuff... */ #define __HAVE_ARCH_STRLEN __kernel_size_t strlen(const char *); -#define __HAVE_ARCH_STRNCMP -int strncmp(const char *, const char *, __kernel_size_t); - -#endif /* !EXPORT_SYMTAB_STROPS */ - -#endif /* __KERNEL__ */ - #endif /* !(__SPARC64_STRING_H__) */ diff --git a/arch/sparc/lib/memcpy.S b/arch/sparc/lib/memcpy.S index 1dc8ec5b6bd9f..d3626cd67941c 100644 --- a/arch/sparc/lib/memcpy.S +++ b/arch/sparc/lib/memcpy.S @@ -141,11 +141,6 @@ x: retl nop ! Only bcopy returns here and it retuns void... -#ifdef __KERNEL__ -FUNC(amemmove) -FUNC(__memmove) -EXPORT_SYMBOL(__memmove) -#endif FUNC(memmove) EXPORT_SYMBOL(memmove) cmp %o0, %o1 -- GitLab From fb2e6fdbbdaeb94745712a7b18b628c4349de08f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 17 Jan 2016 21:16:45 -0500 Subject: [PATCH 0013/1167] sparc32: debride memcpy.S a bit unreachable code, unused macros... Acked-by: David S. Miller Signed-off-by: Al Viro --- arch/sparc/lib/memcpy.S | 79 ----------------------------------------- 1 file changed, 79 deletions(-) diff --git a/arch/sparc/lib/memcpy.S b/arch/sparc/lib/memcpy.S index d3626cd67941c..8913feaa7ac7e 100644 --- a/arch/sparc/lib/memcpy.S +++ b/arch/sparc/lib/memcpy.S @@ -59,88 +59,9 @@ x: stb %t0, [%dst - (offset) - 0x02]; \ stb %t1, [%dst - (offset) - 0x01]; -/* Both these macros have to start with exactly the same insn */ -#define RMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldd [%src - (offset) - 0x20], %t0; \ - ldd [%src - (offset) - 0x18], %t2; \ - ldd [%src - (offset) - 0x10], %t4; \ - ldd [%src - (offset) - 0x08], %t6; \ - st %t0, [%dst - (offset) - 0x20]; \ - st %t1, [%dst - (offset) - 0x1c]; \ - st %t2, [%dst - (offset) - 0x18]; \ - st %t3, [%dst - (offset) - 0x14]; \ - st %t4, [%dst - (offset) - 0x10]; \ - st %t5, [%dst - (offset) - 0x0c]; \ - st %t6, [%dst - (offset) - 0x08]; \ - st %t7, [%dst - (offset) - 0x04]; - -#define RMOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldd [%src - (offset) - 0x20], %t0; \ - ldd [%src - (offset) - 0x18], %t2; \ - ldd [%src - (offset) - 0x10], %t4; \ - ldd [%src - (offset) - 0x08], %t6; \ - std %t0, [%dst - (offset) - 0x20]; \ - std %t2, [%dst - (offset) - 0x18]; \ - std %t4, [%dst - (offset) - 0x10]; \ - std %t6, [%dst - (offset) - 0x08]; - -#define RMOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ - ldd [%src + (offset) + 0x00], %t0; \ - ldd [%src + (offset) + 0x08], %t2; \ - st %t0, [%dst + (offset) + 0x00]; \ - st %t1, [%dst + (offset) + 0x04]; \ - st %t2, [%dst + (offset) + 0x08]; \ - st %t3, [%dst + (offset) + 0x0c]; - -#define RMOVE_SHORTCHUNK(src, dst, offset, t0, t1) \ - ldub [%src + (offset) + 0x00], %t0; \ - ldub [%src + (offset) + 0x01], %t1; \ - stb %t0, [%dst + (offset) + 0x00]; \ - stb %t1, [%dst + (offset) + 0x01]; - -#define SMOVE_CHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, prev, shil, shir, offset2) \ - ldd [%src + (offset) + 0x00], %t0; \ - ldd [%src + (offset) + 0x08], %t2; \ - srl %t0, shir, %t5; \ - srl %t1, shir, %t6; \ - sll %t0, shil, %t0; \ - or %t5, %prev, %t5; \ - sll %t1, shil, %prev; \ - or %t6, %t0, %t0; \ - srl %t2, shir, %t1; \ - srl %t3, shir, %t6; \ - sll %t2, shil, %t2; \ - or %t1, %prev, %t1; \ - std %t4, [%dst + (offset) + (offset2) - 0x04]; \ - std %t0, [%dst + (offset) + (offset2) + 0x04]; \ - sll %t3, shil, %prev; \ - or %t6, %t2, %t4; - -#define SMOVE_ALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, prev, shil, shir, offset2) \ - ldd [%src + (offset) + 0x00], %t0; \ - ldd [%src + (offset) + 0x08], %t2; \ - srl %t0, shir, %t4; \ - srl %t1, shir, %t5; \ - sll %t0, shil, %t6; \ - or %t4, %prev, %t0; \ - sll %t1, shil, %prev; \ - or %t5, %t6, %t1; \ - srl %t2, shir, %t4; \ - srl %t3, shir, %t5; \ - sll %t2, shil, %t6; \ - or %t4, %prev, %t2; \ - sll %t3, shil, %prev; \ - or %t5, %t6, %t3; \ - std %t0, [%dst + (offset) + (offset2) + 0x00]; \ - std %t2, [%dst + (offset) + (offset2) + 0x08]; - .text .align 4 -0: - retl - nop ! Only bcopy returns here and it retuns void... - FUNC(memmove) EXPORT_SYMBOL(memmove) cmp %o0, %o1 -- GitLab From e007c53397acb5554e226693e3bff54a312ccd96 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 17 Jan 2016 01:13:41 -0500 Subject: [PATCH 0014/1167] ia64: move exports to definitions Here we have another kind of deviation from the default case - a difference between exporting functions and non-functions. EXPORT_DATA_SYMBOL... is really different from EXPORT_SYMBOL... on ia64, and we need to use the right one when moving exports from *.c where C compiler has the required information to *.S, where we need to supply it manually. parisc64 will be another one like that. Tested-by: Tony Luck Signed-off-by: Al Viro --- arch/ia64/include/asm/export.h | 3 + arch/ia64/kernel/entry.S | 3 + arch/ia64/kernel/esi_stub.S | 2 + arch/ia64/kernel/head.S | 2 + arch/ia64/kernel/ia64_ksyms.c | 94 +------------------------------ arch/ia64/kernel/ivt.S | 2 + arch/ia64/kernel/pal.S | 7 +++ arch/ia64/kernel/setup.c | 4 ++ arch/ia64/lib/clear_page.S | 2 + arch/ia64/lib/clear_user.S | 2 + arch/ia64/lib/copy_page.S | 2 + arch/ia64/lib/copy_page_mck.S | 2 + arch/ia64/lib/copy_user.S | 2 + arch/ia64/lib/flush.S | 2 + arch/ia64/lib/idiv32.S | 2 + arch/ia64/lib/idiv64.S | 2 + arch/ia64/lib/ip_fast_csum.S | 3 + arch/ia64/lib/memcpy.S | 2 + arch/ia64/lib/memcpy_mck.S | 3 + arch/ia64/lib/memset.S | 2 + arch/ia64/lib/strlen.S | 2 + arch/ia64/lib/strlen_user.S | 2 + arch/ia64/lib/strncpy_from_user.S | 2 + arch/ia64/lib/strnlen_user.S | 2 + arch/ia64/lib/xor.S | 5 ++ 25 files changed, 64 insertions(+), 92 deletions(-) create mode 100644 arch/ia64/include/asm/export.h diff --git a/arch/ia64/include/asm/export.h b/arch/ia64/include/asm/export.h new file mode 100644 index 0000000000000..ad18c65832520 --- /dev/null +++ b/arch/ia64/include/asm/export.h @@ -0,0 +1,3 @@ +/* EXPORT_DATA_SYMBOL != EXPORT_SYMBOL here */ +#define KSYM_FUNC(name) @fptr(name) +#include diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index cfaa7b25084c5..6f27a663177c4 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -48,6 +48,7 @@ #include #include #include +#include #include "minstate.h" @@ -1345,12 +1346,14 @@ GLOBAL_ENTRY(unw_init_running) mov rp=loc0 br.ret.sptk.many rp END(unw_init_running) +EXPORT_SYMBOL(unw_init_running) #ifdef CONFIG_FUNCTION_TRACER #ifdef CONFIG_DYNAMIC_FTRACE GLOBAL_ENTRY(_mcount) br ftrace_stub END(_mcount) +EXPORT_SYMBOL(_mcount) .here: br.ret.sptk.many b0 diff --git a/arch/ia64/kernel/esi_stub.S b/arch/ia64/kernel/esi_stub.S index 6b3d6c1f99b6d..2c369bf77c4bc 100644 --- a/arch/ia64/kernel/esi_stub.S +++ b/arch/ia64/kernel/esi_stub.S @@ -35,6 +35,7 @@ #include #include +#include /* * Inputs: @@ -94,3 +95,4 @@ GLOBAL_ENTRY(esi_call_phys) mov gp=loc2 br.ret.sptk.many rp END(esi_call_phys) +EXPORT_SYMBOL_GPL(esi_call_phys) diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index bb748c5964433..c9b5e942f6715 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -32,6 +32,7 @@ #include #include #include +#include #ifdef CONFIG_HOTPLUG_CPU #define SAL_PSR_BITS_TO_SET \ @@ -168,6 +169,7 @@ RestRR: \ __PAGE_ALIGNED_DATA .global empty_zero_page +EXPORT_DATA_SYMBOL_GPL(empty_zero_page) empty_zero_page: .skip PAGE_SIZE diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c index 0967310495382..d111248af7191 100644 --- a/arch/ia64/kernel/ia64_ksyms.c +++ b/arch/ia64/kernel/ia64_ksyms.c @@ -1,101 +1,11 @@ /* * Architecture-specific kernel symbols - * - * Don't put any exports here unless it's defined in an assembler file. - * All other exports should be put directly after the definition. */ -#include - -#include -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(strlen); - -#include -EXPORT_SYMBOL_GPL(empty_zero_page); - -#include -EXPORT_SYMBOL(ip_fast_csum); /* hand-coded assembly */ -EXPORT_SYMBOL(csum_ipv6_magic); - -#include -EXPORT_SYMBOL(clear_page); -EXPORT_SYMBOL(copy_page); - #ifdef CONFIG_VIRTUAL_MEM_MAP +#include +#include #include EXPORT_SYMBOL(min_low_pfn); /* defined by bootmem.c, but not exported by generic code */ EXPORT_SYMBOL(max_low_pfn); /* defined by bootmem.c, but not exported by generic code */ #endif - -#include -EXPORT_SYMBOL(ia64_cpu_info); -#ifdef CONFIG_SMP -EXPORT_SYMBOL(local_per_cpu_offset); -#endif - -#include -EXPORT_SYMBOL(__copy_user); -EXPORT_SYMBOL(__do_clear_user); -EXPORT_SYMBOL(__strlen_user); -EXPORT_SYMBOL(__strncpy_from_user); -EXPORT_SYMBOL(__strnlen_user); - -/* from arch/ia64/lib */ -extern void __divsi3(void); -extern void __udivsi3(void); -extern void __modsi3(void); -extern void __umodsi3(void); -extern void __divdi3(void); -extern void __udivdi3(void); -extern void __moddi3(void); -extern void __umoddi3(void); - -EXPORT_SYMBOL(__divsi3); -EXPORT_SYMBOL(__udivsi3); -EXPORT_SYMBOL(__modsi3); -EXPORT_SYMBOL(__umodsi3); -EXPORT_SYMBOL(__divdi3); -EXPORT_SYMBOL(__udivdi3); -EXPORT_SYMBOL(__moddi3); -EXPORT_SYMBOL(__umoddi3); - -#if defined(CONFIG_MD_RAID456) || defined(CONFIG_MD_RAID456_MODULE) -extern void xor_ia64_2(void); -extern void xor_ia64_3(void); -extern void xor_ia64_4(void); -extern void xor_ia64_5(void); - -EXPORT_SYMBOL(xor_ia64_2); -EXPORT_SYMBOL(xor_ia64_3); -EXPORT_SYMBOL(xor_ia64_4); -EXPORT_SYMBOL(xor_ia64_5); -#endif - -#include -EXPORT_SYMBOL(ia64_pal_call_phys_stacked); -EXPORT_SYMBOL(ia64_pal_call_phys_static); -EXPORT_SYMBOL(ia64_pal_call_stacked); -EXPORT_SYMBOL(ia64_pal_call_static); -EXPORT_SYMBOL(ia64_load_scratch_fpregs); -EXPORT_SYMBOL(ia64_save_scratch_fpregs); - -#include -EXPORT_SYMBOL(unw_init_running); - -#if defined(CONFIG_IA64_ESI) || defined(CONFIG_IA64_ESI_MODULE) -extern void esi_call_phys (void); -EXPORT_SYMBOL_GPL(esi_call_phys); -#endif -extern char ia64_ivt[]; -EXPORT_SYMBOL(ia64_ivt); - -#include -#ifdef CONFIG_FUNCTION_TRACER -/* mcount is defined in assembly */ -EXPORT_SYMBOL(_mcount); -#endif - -#include -EXPORT_SYMBOL_GPL(flush_icache_range); diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index b1c3cfc93e715..44a103a5de2b3 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -57,6 +57,7 @@ #include #include #include +#include #if 0 # define PSR_DEFAULT_BITS psr.ac @@ -85,6 +86,7 @@ .align 32768 // align on 32KB boundary .global ia64_ivt + EXPORT_DATA_SYMBOL(ia64_ivt) ia64_ivt: ///////////////////////////////////////////////////////////////////////////////////////// // 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47) diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S index 0b533441c3c9b..94fb2e3954983 100644 --- a/arch/ia64/kernel/pal.S +++ b/arch/ia64/kernel/pal.S @@ -14,6 +14,7 @@ #include #include +#include .data pal_entry_point: @@ -87,6 +88,7 @@ GLOBAL_ENTRY(ia64_pal_call_static) srlz.d // seralize restoration of psr.l br.ret.sptk.many b0 END(ia64_pal_call_static) +EXPORT_SYMBOL(ia64_pal_call_static) /* * Make a PAL call using the stacked registers calling convention. @@ -122,6 +124,7 @@ GLOBAL_ENTRY(ia64_pal_call_stacked) srlz.d // serialize restoration of psr.l br.ret.sptk.many b0 END(ia64_pal_call_stacked) +EXPORT_SYMBOL(ia64_pal_call_stacked) /* * Make a physical mode PAL call using the static registers calling convention. @@ -193,6 +196,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static) srlz.d // seralize restoration of psr.l br.ret.sptk.many b0 END(ia64_pal_call_phys_static) +EXPORT_SYMBOL(ia64_pal_call_phys_static) /* * Make a PAL call using the stacked registers in physical mode. @@ -250,6 +254,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked) srlz.d // seralize restoration of psr.l br.ret.sptk.many b0 END(ia64_pal_call_phys_stacked) +EXPORT_SYMBOL(ia64_pal_call_phys_stacked) /* * Save scratch fp scratch regs which aren't saved in pt_regs already @@ -275,6 +280,7 @@ GLOBAL_ENTRY(ia64_save_scratch_fpregs) stf.spill [r2] = f15,32 br.ret.sptk.many rp END(ia64_save_scratch_fpregs) +EXPORT_SYMBOL(ia64_save_scratch_fpregs) /* * Load scratch fp scratch regs (fp10-fp15) @@ -296,3 +302,4 @@ GLOBAL_ENTRY(ia64_load_scratch_fpregs) ldf.fill f15 = [r2],32 br.ret.sptk.many rp END(ia64_load_scratch_fpregs) +EXPORT_SYMBOL(ia64_load_scratch_fpregs) diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index afddb3e80a299..7ec7acc844c2e 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -71,7 +71,11 @@ EXPORT_SYMBOL(__per_cpu_offset); #endif DEFINE_PER_CPU(struct cpuinfo_ia64, ia64_cpu_info); +EXPORT_SYMBOL(ia64_cpu_info); DEFINE_PER_CPU(unsigned long, local_per_cpu_offset); +#ifdef CONFIG_SMP +EXPORT_SYMBOL(local_per_cpu_offset); +#endif unsigned long ia64_cycles_per_usec; struct ia64_boot_param *ia64_boot_param; struct screen_info screen_info; diff --git a/arch/ia64/lib/clear_page.S b/arch/ia64/lib/clear_page.S index 2d814e7ed191c..3cf5b76e587ff 100644 --- a/arch/ia64/lib/clear_page.S +++ b/arch/ia64/lib/clear_page.S @@ -11,6 +11,7 @@ #include #include +#include #ifdef CONFIG_ITANIUM # define L3_LINE_SIZE 64 // Itanium L3 line size @@ -74,3 +75,4 @@ GLOBAL_ENTRY(clear_page) mov ar.lc = saved_lc // restore lc br.ret.sptk.many rp END(clear_page) +EXPORT_SYMBOL(clear_page) diff --git a/arch/ia64/lib/clear_user.S b/arch/ia64/lib/clear_user.S index eecd8577b2099..7b40731ee5d86 100644 --- a/arch/ia64/lib/clear_user.S +++ b/arch/ia64/lib/clear_user.S @@ -12,6 +12,7 @@ */ #include +#include // // arguments @@ -207,3 +208,4 @@ GLOBAL_ENTRY(__do_clear_user) mov ar.lc=saved_lc br.ret.sptk.many rp END(__do_clear_user) +EXPORT_SYMBOL(__do_clear_user) diff --git a/arch/ia64/lib/copy_page.S b/arch/ia64/lib/copy_page.S index 127d1d050d788..cbdb9e323ffbd 100644 --- a/arch/ia64/lib/copy_page.S +++ b/arch/ia64/lib/copy_page.S @@ -16,6 +16,7 @@ */ #include #include +#include #define PIPE_DEPTH 3 #define EPI p[PIPE_DEPTH-1] @@ -96,3 +97,4 @@ GLOBAL_ENTRY(copy_page) mov ar.lc=saved_lc br.ret.sptk.many rp END(copy_page) +EXPORT_SYMBOL(copy_page) diff --git a/arch/ia64/lib/copy_page_mck.S b/arch/ia64/lib/copy_page_mck.S index 3c45d60a81b44..c13f69036876c 100644 --- a/arch/ia64/lib/copy_page_mck.S +++ b/arch/ia64/lib/copy_page_mck.S @@ -61,6 +61,7 @@ */ #include #include +#include #define PREFETCH_DIST 8 // McKinley sustains 16 outstanding L2 misses (8 ld, 8 st) @@ -183,3 +184,4 @@ GLOBAL_ENTRY(copy_page) mov pr = saved_pr, -1 br.ret.sptk.many rp END(copy_page) +EXPORT_SYMBOL(copy_page) diff --git a/arch/ia64/lib/copy_user.S b/arch/ia64/lib/copy_user.S index c952bdc6a0939..66facd52e8d00 100644 --- a/arch/ia64/lib/copy_user.S +++ b/arch/ia64/lib/copy_user.S @@ -30,6 +30,7 @@ */ #include +#include // // Tuneable parameters @@ -608,3 +609,4 @@ GLOBAL_ENTRY(__copy_user) mov ar.pfs=saved_pfs br.ret.sptk.many rp END(__copy_user) +EXPORT_SYMBOL(__copy_user) diff --git a/arch/ia64/lib/flush.S b/arch/ia64/lib/flush.S index 1d8c88860063d..9a5a2f9fad132 100644 --- a/arch/ia64/lib/flush.S +++ b/arch/ia64/lib/flush.S @@ -8,6 +8,7 @@ */ #include +#include /* @@ -60,6 +61,7 @@ GLOBAL_ENTRY(flush_icache_range) mov ar.lc=r3 // restore ar.lc br.ret.sptk.many rp END(flush_icache_range) +EXPORT_SYMBOL_GPL(flush_icache_range) /* * clflush_cache_range(start,size) diff --git a/arch/ia64/lib/idiv32.S b/arch/ia64/lib/idiv32.S index c91b5b0129ff9..715aed79a9ce3 100644 --- a/arch/ia64/lib/idiv32.S +++ b/arch/ia64/lib/idiv32.S @@ -15,6 +15,7 @@ */ #include +#include #ifdef MODULO # define OP mod @@ -81,3 +82,4 @@ GLOBAL_ENTRY(NAME) getf.sig r8 = f6 // transfer result to result register br.ret.sptk.many rp END(NAME) +EXPORT_SYMBOL(NAME) diff --git a/arch/ia64/lib/idiv64.S b/arch/ia64/lib/idiv64.S index 627573c4ceb19..25840f6977532 100644 --- a/arch/ia64/lib/idiv64.S +++ b/arch/ia64/lib/idiv64.S @@ -15,6 +15,7 @@ */ #include +#include #ifdef MODULO # define OP mod @@ -78,3 +79,4 @@ GLOBAL_ENTRY(NAME) getf.sig r8 = f11 // transfer result to result register br.ret.sptk.many rp END(NAME) +EXPORT_SYMBOL(NAME) diff --git a/arch/ia64/lib/ip_fast_csum.S b/arch/ia64/lib/ip_fast_csum.S index 620d9dc5220f3..648e0d4a48390 100644 --- a/arch/ia64/lib/ip_fast_csum.S +++ b/arch/ia64/lib/ip_fast_csum.S @@ -13,6 +13,7 @@ */ #include +#include /* * Since we know that most likely this function is called with buf aligned @@ -92,6 +93,7 @@ GLOBAL_ENTRY(ip_fast_csum) mov b0=r34 br.ret.sptk.many b0 END(ip_fast_csum) +EXPORT_SYMBOL(ip_fast_csum) GLOBAL_ENTRY(csum_ipv6_magic) ld4 r20=[in0],4 @@ -142,3 +144,4 @@ GLOBAL_ENTRY(csum_ipv6_magic) andcm r8=r9,r8 br.ret.sptk.many b0 END(csum_ipv6_magic) +EXPORT_SYMBOL(csum_ipv6_magic) diff --git a/arch/ia64/lib/memcpy.S b/arch/ia64/lib/memcpy.S index 448908d80b694..ba172fd6acf4e 100644 --- a/arch/ia64/lib/memcpy.S +++ b/arch/ia64/lib/memcpy.S @@ -14,6 +14,7 @@ * David Mosberger-Tang */ #include +#include GLOBAL_ENTRY(memcpy) @@ -299,3 +300,4 @@ GLOBAL_ENTRY(memcpy) COPY(56, 0) END(memcpy) +EXPORT_SYMBOL(memcpy) diff --git a/arch/ia64/lib/memcpy_mck.S b/arch/ia64/lib/memcpy_mck.S index ab0f876397295..b264b6a7967b4 100644 --- a/arch/ia64/lib/memcpy_mck.S +++ b/arch/ia64/lib/memcpy_mck.S @@ -15,6 +15,7 @@ */ #include #include +#include #define EK(y...) EX(y) @@ -78,6 +79,7 @@ GLOBAL_ENTRY(memcpy) br.cond.sptk .common_code ;; END(memcpy) +EXPORT_SYMBOL(memcpy) GLOBAL_ENTRY(__copy_user) .prologue // check dest alignment @@ -664,3 +666,4 @@ EK(.ex_handler, (p17) st8 [dst1]=r39,8); \ /* end of McKinley specific optimization */ END(__copy_user) +EXPORT_SYMBOL(__copy_user) diff --git a/arch/ia64/lib/memset.S b/arch/ia64/lib/memset.S index f26c16aefb1cb..87b974704075f 100644 --- a/arch/ia64/lib/memset.S +++ b/arch/ia64/lib/memset.S @@ -18,6 +18,7 @@ to get peak speed when value = 0. */ #include +#include #undef ret #define dest in0 @@ -360,3 +361,4 @@ GLOBAL_ENTRY(memset) br.ret.sptk.many rp } END(memset) +EXPORT_SYMBOL(memset) diff --git a/arch/ia64/lib/strlen.S b/arch/ia64/lib/strlen.S index e0cdac0a85b87..1a6e17c657b42 100644 --- a/arch/ia64/lib/strlen.S +++ b/arch/ia64/lib/strlen.S @@ -17,6 +17,7 @@ */ #include +#include // // @@ -190,3 +191,4 @@ GLOBAL_ENTRY(strlen) mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what br.ret.sptk.many rp // end of successful recovery code END(strlen) +EXPORT_SYMBOL(strlen) diff --git a/arch/ia64/lib/strlen_user.S b/arch/ia64/lib/strlen_user.S index c71eded4285ef..9d257684e7334 100644 --- a/arch/ia64/lib/strlen_user.S +++ b/arch/ia64/lib/strlen_user.S @@ -16,6 +16,7 @@ */ #include +#include // // int strlen_user(char *) @@ -196,3 +197,4 @@ GLOBAL_ENTRY(__strlen_user) mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what br.ret.sptk.many rp END(__strlen_user) +EXPORT_SYMBOL(__strlen_user) diff --git a/arch/ia64/lib/strncpy_from_user.S b/arch/ia64/lib/strncpy_from_user.S index a504381f31ebe..ca9ccf280e2e5 100644 --- a/arch/ia64/lib/strncpy_from_user.S +++ b/arch/ia64/lib/strncpy_from_user.S @@ -17,6 +17,7 @@ */ #include +#include GLOBAL_ENTRY(__strncpy_from_user) alloc r2=ar.pfs,3,0,0,0 @@ -42,3 +43,4 @@ GLOBAL_ENTRY(__strncpy_from_user) [.Lexit:] br.ret.sptk.many rp END(__strncpy_from_user) +EXPORT_SYMBOL(__strncpy_from_user) diff --git a/arch/ia64/lib/strnlen_user.S b/arch/ia64/lib/strnlen_user.S index d09066b1e49d3..80a5dfd1d402b 100644 --- a/arch/ia64/lib/strnlen_user.S +++ b/arch/ia64/lib/strnlen_user.S @@ -13,6 +13,7 @@ */ #include +#include GLOBAL_ENTRY(__strnlen_user) .prologue @@ -43,3 +44,4 @@ GLOBAL_ENTRY(__strnlen_user) mov ar.lc=r16 // restore ar.lc br.ret.sptk.many rp END(__strnlen_user) +EXPORT_SYMBOL(__strnlen_user) diff --git a/arch/ia64/lib/xor.S b/arch/ia64/lib/xor.S index 54e3f7eab8e9a..c83f1c410691b 100644 --- a/arch/ia64/lib/xor.S +++ b/arch/ia64/lib/xor.S @@ -14,6 +14,7 @@ */ #include +#include GLOBAL_ENTRY(xor_ia64_2) .prologue @@ -51,6 +52,7 @@ GLOBAL_ENTRY(xor_ia64_2) mov pr = r29, -1 br.ret.sptk.few rp END(xor_ia64_2) +EXPORT_SYMBOL(xor_ia64_2) GLOBAL_ENTRY(xor_ia64_3) .prologue @@ -91,6 +93,7 @@ GLOBAL_ENTRY(xor_ia64_3) mov pr = r29, -1 br.ret.sptk.few rp END(xor_ia64_3) +EXPORT_SYMBOL(xor_ia64_3) GLOBAL_ENTRY(xor_ia64_4) .prologue @@ -134,6 +137,7 @@ GLOBAL_ENTRY(xor_ia64_4) mov pr = r29, -1 br.ret.sptk.few rp END(xor_ia64_4) +EXPORT_SYMBOL(xor_ia64_4) GLOBAL_ENTRY(xor_ia64_5) .prologue @@ -182,3 +186,4 @@ GLOBAL_ENTRY(xor_ia64_5) mov pr = r29, -1 br.ret.sptk.few rp END(xor_ia64_5) +EXPORT_SYMBOL(xor_ia64_5) -- GitLab From d7372cb6290eedadcf2d191b033388df3c0c39f2 Mon Sep 17 00:00:00 2001 From: Tom Yan Date: Sat, 23 Jul 2016 02:34:08 +0800 Subject: [PATCH 0015/1167] libata-scsi: use u8 array to store mode page copy ata_mselect_*() would initialize a char array for storing a copy of the current mode page. However, char could be signed char. In that case, bytes larger than 127 would be converted to negative number. For example, 0xff from def_control_mpage[] would become -1. This prevented ata_mselect_control() from working at all, since when it did the read-only bits check, there would always be a mismatch. Signed-off-by: Tom Yan Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e207b33e4ce9d..0bc4532bb60a4 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3610,7 +3610,7 @@ static int ata_mselect_caching(struct ata_queued_cmd *qc, { struct ata_taskfile *tf = &qc->tf; struct ata_device *dev = qc->dev; - char mpage[CACHE_MPAGE_LEN]; + u8 mpage[CACHE_MPAGE_LEN]; u8 wce; int i; @@ -3666,7 +3666,7 @@ static int ata_mselect_control(struct ata_queued_cmd *qc, const u8 *buf, int len, u16 *fp) { struct ata_device *dev = qc->dev; - char mpage[CONTROL_MPAGE_LEN]; + u8 mpage[CONTROL_MPAGE_LEN]; u8 d_sense; int i; -- GitLab From 535fd072202dbc8afe5a4093178132bdd4ac2424 Mon Sep 17 00:00:00 2001 From: Tom Yan Date: Fri, 22 Jul 2016 02:41:54 +0800 Subject: [PATCH 0016/1167] libata-scsi: fix MODE SELECT translation for Control mode page scsi_done() was called repeatedly and apparently because of that, the kernel would call trace when we touch the Control mode page: Call Trace: [] dump_stack+0x63/0x81 [] __warn+0xcb/0xf0 [] warn_slowpath_null+0x1d/0x20 [] ata_eh_finish+0xe0/0xf0 [libata] [] sata_pmp_error_handler+0x640/0xa50 [libata] [] ahci_error_handler+0x1d/0x70 [libahci] [] ata_scsi_port_error_handler+0x430/0x770 [libata] [] ? ata_scsi_cmd_error_handler+0xdd/0x160 [libata] [] ata_scsi_error+0xa7/0xf0 [libata] [] scsi_error_handler+0xaa/0x560 [scsi_mod] [] ? scsi_eh_get_sense+0x180/0x180 [scsi_mod] [] kthread+0xd8/0xf0 [] ret_from_fork+0x1f/0x40 [] ? kthread_worker_fn+0x170/0x170 ---[ end trace 8b7501047e928a17 ]--- Removed the unnecessary code and let ata_scsi_translate() do the job. Also, since ata_mselect_control() has no ATA command to send to the device, ata_scsi_mode_select_xlat() should return 1 for it, so that ata_scsi_translate() will finish early to avoid ata_qc_issue(). Signed-off-by: Tom Yan Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 0bc4532bb60a4..be9c76c938b22 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3701,8 +3701,6 @@ static int ata_mselect_control(struct ata_queued_cmd *qc, dev->flags |= ATA_DFLAG_D_SENSE; else dev->flags &= ~ATA_DFLAG_D_SENSE; - qc->scsicmd->result = SAM_STAT_GOOD; - qc->scsicmd->scsi_done(qc->scsicmd); return 0; } @@ -3829,6 +3827,8 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc) if (ata_mselect_control(qc, p, pg_len, &fp) < 0) { fp += hdr_len + bd_len; goto invalid_param; + } else { + goto skip; /* No ATA command to send */ } break; default: /* invalid page code */ -- GitLab From 107a077d19341b4d47ae06f0bd24883b94e64628 Mon Sep 17 00:00:00 2001 From: Tang Yuantian Date: Tue, 9 Aug 2016 09:51:21 +0800 Subject: [PATCH 0017/1167] ahci: qoriq: adjust sata parameter The default values for Port Phy2Cfg register and Port Phy3Cfg register are better, no need to overwrite them. Signed-off-by: Tang Yuantian Signed-off-by: Tejun Heo --- drivers/ata/ahci_qoriq.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index 7bdee9bd87866..ed357a184ee49 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -44,10 +44,6 @@ #define SATA_ECC_DISABLE 0x00020000 -/* for ls1043a */ -#define LS1043A_PORT_PHY2 0x28184d1f -#define LS1043A_PORT_PHY3 0x0e081509 - enum ahci_qoriq_type { AHCI_LS1021A, AHCI_LS1043A, @@ -166,8 +162,6 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv) case AHCI_LS1043A: writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); - writel(LS1043A_PORT_PHY2, reg_base + PORT_PHY2); - writel(LS1043A_PORT_PHY3, reg_base + PORT_PHY3); writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); break; -- GitLab From 16af080e47785d14919bf94bf8a4097c5c8529fb Mon Sep 17 00:00:00 2001 From: Tang Yuantian Date: Tue, 9 Aug 2016 09:51:22 +0800 Subject: [PATCH 0018/1167] ahci: qoriq: enable snoopable sata read and write By default the SATA IP on the qoriq SoCs does not generating coherent/snoopable transactions. This patch enable it in the sata axicc register. In addition, the dma-coherent property must be set on the SATA controller nodes. Signed-off-by: Tang Yuantian Signed-off-by: Tejun Heo --- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 ++- arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 2 ++ drivers/ata/ahci_qoriq.c | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index e669fbd7f9c36..e8e4c3ed1b7ec 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -495,10 +495,11 @@ }; sata: sata@3200000 { - compatible = "fsl,ls1043a-ahci", "fsl,ls1021a-ahci"; + compatible = "fsl,ls1043a-ahci"; reg = <0x0 0x3200000 0x0 0x10000>; interrupts = <0 69 0x4>; clocks = <&clockgen 4 0>; + dma-coherent; }; msi1: msi-controller1@1571000 { diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi index 21023a388c29d..5ead17c05bb83 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi @@ -679,6 +679,7 @@ reg = <0x0 0x3200000 0x0 0x10000>; interrupts = <0 133 0x4>; /* Level high type */ clocks = <&clockgen 4 3>; + dma-coherent; }; sata1: sata@3210000 { @@ -687,6 +688,7 @@ reg = <0x0 0x3210000 0x0 0x10000>; interrupts = <0 136 0x4>; /* Level high type */ clocks = <&clockgen 4 3>; + dma-coherent; }; usb0: usb3@3100000 { diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index ed357a184ee49..925c4b6a753bb 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -30,17 +30,20 @@ #define PORT_PHY3 0xB0 #define PORT_PHY4 0xB4 #define PORT_PHY5 0xB8 +#define PORT_AXICC 0xBC #define PORT_TRANS 0xC8 /* port register default value */ #define AHCI_PORT_PHY_1_CFG 0xa003fffe #define AHCI_PORT_TRANS_CFG 0x08000029 +#define AHCI_PORT_AXICC_CFG 0x3fffffff /* for ls1021a */ #define LS1021A_PORT_PHY2 0x28183414 #define LS1021A_PORT_PHY3 0x0e080e06 #define LS1021A_PORT_PHY4 0x064a080b #define LS1021A_PORT_PHY5 0x2aa86470 +#define LS1021A_AXICC_ADDR 0xC0 #define SATA_ECC_DISABLE 0x00020000 @@ -158,16 +161,19 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv) writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4); writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5); writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); + writel(AHCI_PORT_AXICC_CFG, reg_base + LS1021A_AXICC_ADDR); break; case AHCI_LS1043A: writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); + writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); break; case AHCI_LS2080A: writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); + writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); break; } -- GitLab From 0e0b2afdf644aa523f5eb10ce1f9e3c6cd8362ec Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 10 Aug 2016 11:23:43 -0400 Subject: [PATCH 0019/1167] kernfs: add dummy implementation of kernfs_path_from_node() The dummy version of kernfs_path_from_node() was missing. This currently doesn't break anything. Let's add it for consistency and to ease adding wrappers around it. v2: Removed stray ';' which was causing build failures. Signed-off-by: Tejun Heo Acked-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 96356ef012de7..7d2efd2128bbf 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -344,6 +344,11 @@ static inline int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) static inline size_t kernfs_path_len(struct kernfs_node *kn) { return 0; } +static inline int kernfs_path_from_node(struct kernfs_node *root_kn, + struct kernfs_node *kn, + char *buf, size_t buflen) +{ return -ENOSYS; } + static inline char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen) { return NULL; } -- GitLab From 3abb1d90f5d930c6183534a624aa0158a71bc5eb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 10 Aug 2016 11:23:44 -0400 Subject: [PATCH 0020/1167] kernfs: make kernfs_path*() behave in the style of strlcpy() kernfs_path*() functions always return the length of the full path but the path content is undefined if the length is larger than the provided buffer. This makes its behavior different from strlcpy() and requires error handling in all its users even when they don't care about truncation. In addition, the implementation can actully be simplified by making it behave properly in strlcpy() style. * Update kernfs_path_from_node_locked() to always fill up the buffer with path. If the buffer is not large enough, the output is truncated and terminated. * kernfs_path() no longer needs error handling. Make it a simple inline wrapper around kernfs_path_from_node(). * sysfs_warn_dup()'s use of kernfs_path() doesn't need error handling. Updated accordingly. * cgroup_path()'s use of kernfs_path() updated to retain the old behavior. Signed-off-by: Tejun Heo Acked-by: Greg Kroah-Hartman Acked-by: Serge Hallyn --- fs/kernfs/dir.c | 61 ++++++++++++------------------------------ fs/sysfs/dir.c | 6 ++--- include/linux/cgroup.h | 7 ++++- include/linux/kernfs.h | 21 +++++++++++---- 4 files changed, 42 insertions(+), 53 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index e57174d436830..09242aaa8829e 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -110,8 +110,9 @@ static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a, * kn_to: /n1/n2/n3 [depth=3] * result: /../.. * - * return value: length of the string. If greater than buflen, - * then contents of buf are undefined. On error, -1 is returned. + * Returns the length of the full path. If the full length is equal to or + * greater than @buflen, @buf contains the truncated path with the trailing + * '\0'. On error, -errno is returned. */ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, struct kernfs_node *kn_from, @@ -119,9 +120,8 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, { struct kernfs_node *kn, *common; const char parent_str[] = "/.."; - size_t depth_from, depth_to, len = 0, nlen = 0; - char *p; - int i; + size_t depth_from, depth_to, len = 0; + int i, j; if (!kn_from) kn_from = kernfs_root(kn_to)->kn; @@ -131,7 +131,7 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, common = kernfs_common_ancestor(kn_from, kn_to); if (WARN_ON(!common)) - return -1; + return -EINVAL; depth_to = kernfs_depth(common, kn_to); depth_from = kernfs_depth(common, kn_from); @@ -144,22 +144,16 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, len < buflen ? buflen - len : 0); /* Calculate how many bytes we need for the rest */ - for (kn = kn_to; kn != common; kn = kn->parent) - nlen += strlen(kn->name) + 1; - - if (len + nlen >= buflen) - return len + nlen; - - p = buf + len + nlen; - *p = '\0'; - for (kn = kn_to; kn != common; kn = kn->parent) { - size_t tmp = strlen(kn->name); - p -= tmp; - memcpy(p, kn->name, tmp); - *(--p) = '/'; + for (i = depth_to - 1; i >= 0; i--) { + for (kn = kn_to, j = 0; j < i; j++) + kn = kn->parent; + len += strlcpy(buf + len, "/", + len < buflen ? buflen - len : 0); + len += strlcpy(buf + len, kn->name, + len < buflen ? buflen - len : 0); } - return len + nlen; + return len; } /** @@ -220,8 +214,9 @@ size_t kernfs_path_len(struct kernfs_node *kn) * path (which includes '..'s) as needed to reach from @from to @to is * returned. * - * If @buf isn't long enough, the return value will be greater than @buflen - * and @buf contents are undefined. + * Returns the length of the full path. If the full length is equal to or + * greater than @buflen, @buf contains the truncated path with the trailing + * '\0'. On error, -errno is returned. */ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, char *buf, size_t buflen) @@ -236,28 +231,6 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, } EXPORT_SYMBOL_GPL(kernfs_path_from_node); -/** - * kernfs_path - build full path of a given node - * @kn: kernfs_node of interest - * @buf: buffer to copy @kn's name into - * @buflen: size of @buf - * - * Builds and returns the full path of @kn in @buf of @buflen bytes. The - * path is built from the end of @buf so the returned pointer usually - * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated - * and %NULL is returned. - */ -char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen) -{ - int ret; - - ret = kernfs_path_from_node(kn, NULL, buf, buflen); - if (ret < 0 || ret >= buflen) - return NULL; - return buf; -} -EXPORT_SYMBOL_GPL(kernfs_path); - /** * pr_cont_kernfs_name - pr_cont name of a kernfs_node * @kn: kernfs_node of interest diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 94374e4350259..2b67bda2021b9 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -21,14 +21,14 @@ DEFINE_SPINLOCK(sysfs_symlink_target_lock); void sysfs_warn_dup(struct kernfs_node *parent, const char *name) { - char *buf, *path = NULL; + char *buf; buf = kzalloc(PATH_MAX, GFP_KERNEL); if (buf) - path = kernfs_path(parent, buf, PATH_MAX); + kernfs_path(parent, buf, PATH_MAX); WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s/%s'\n", - path, name); + buf, name); kfree(buf); } diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 984f73b719a99..5a9abdee43fe8 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -541,7 +541,12 @@ static inline int cgroup_name(struct cgroup *cgrp, char *buf, size_t buflen) static inline char * __must_check cgroup_path(struct cgroup *cgrp, char *buf, size_t buflen) { - return kernfs_path(cgrp->kn, buf, buflen); + int ret; + + ret = kernfs_path(cgrp->kn, buf, buflen); + if (ret < 0 || ret >= buflen) + return NULL; + return buf; } static inline void pr_cont_cgroup_name(struct cgroup *cgrp) diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 7d2efd2128bbf..4a02b1b498214 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -272,7 +272,6 @@ int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen); size_t kernfs_path_len(struct kernfs_node *kn); int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn, char *buf, size_t buflen); -char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen); void pr_cont_kernfs_name(struct kernfs_node *kn); void pr_cont_kernfs_path(struct kernfs_node *kn); struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn); @@ -349,10 +348,6 @@ static inline int kernfs_path_from_node(struct kernfs_node *root_kn, char *buf, size_t buflen) { return -ENOSYS; } -static inline char *kernfs_path(struct kernfs_node *kn, char *buf, - size_t buflen) -{ return NULL; } - static inline void pr_cont_kernfs_name(struct kernfs_node *kn) { } static inline void pr_cont_kernfs_path(struct kernfs_node *kn) { } @@ -441,6 +436,22 @@ static inline void kernfs_init(void) { } #endif /* CONFIG_KERNFS */ +/** + * kernfs_path - build full path of a given node + * @kn: kernfs_node of interest + * @buf: buffer to copy @kn's name into + * @buflen: size of @buf + * + * Builds and returns the full path of @kn in @buf of @buflen bytes. The + * path is built from the end of @buf so the returned pointer usually + * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated + * and %NULL is returned. + */ +static inline int kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen) +{ + return kernfs_path_from_node(kn, NULL, buf, buflen); +} + static inline struct kernfs_node * kernfs_find_and_get(struct kernfs_node *kn, const char *name) { -- GitLab From bb09c8634b1e484b8840fb2384d55739bfcb68bd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 10 Aug 2016 11:23:44 -0400 Subject: [PATCH 0021/1167] kernfs: remove kernfs_path_len() It doesn't have any in-kernel user and the same result can be obtained from kernfs_path(@kn, NULL, 0). Remove it. Signed-off-by: Tejun Heo Acked-by: Greg Kroah-Hartman Cc: Serge Hallyn --- fs/kernfs/dir.c | 23 ----------------------- include/linux/kernfs.h | 4 ---- 2 files changed, 27 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 09242aaa8829e..6e7fd37615f80 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -179,29 +179,6 @@ int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) return ret; } -/** - * kernfs_path_len - determine the length of the full path of a given node - * @kn: kernfs_node of interest - * - * The returned length doesn't include the space for the terminating '\0'. - */ -size_t kernfs_path_len(struct kernfs_node *kn) -{ - size_t len = 0; - unsigned long flags; - - spin_lock_irqsave(&kernfs_rename_lock, flags); - - do { - len += strlen(kn->name) + 1; - kn = kn->parent; - } while (kn && kn->parent); - - spin_unlock_irqrestore(&kernfs_rename_lock, flags); - - return len; -} - /** * kernfs_path_from_node - build path of node @to relative to @from. * @from: parent kernfs_node relative to which we need to build the path diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 4a02b1b498214..7056238fd9f5c 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -269,7 +269,6 @@ static inline bool kernfs_ns_enabled(struct kernfs_node *kn) } int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen); -size_t kernfs_path_len(struct kernfs_node *kn); int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn, char *buf, size_t buflen); void pr_cont_kernfs_name(struct kernfs_node *kn); @@ -340,9 +339,6 @@ static inline bool kernfs_ns_enabled(struct kernfs_node *kn) static inline int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) { return -ENOSYS; } -static inline size_t kernfs_path_len(struct kernfs_node *kn) -{ return 0; } - static inline int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn, char *buf, size_t buflen) -- GitLab From 4c737b41de7f4eef2a593803bad1b918dd718b10 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 10 Aug 2016 11:23:44 -0400 Subject: [PATCH 0022/1167] cgroup: make cgroup_path() and friends behave in the style of strlcpy() cgroup_path() and friends used to format the path from the end and thus the resulting path usually didn't start at the start of the passed in buffer. Also, when the buffer was too small, the partial result was truncated from the head rather than tail and there was no way to tell how long the full path would be. These make the functions less robust and more awkward to use. With recent updates to kernfs_path(), cgroup_path() and friends can be made to behave in strlcpy() style. * cgroup_path(), cgroup_path_ns[_locked]() and task_cgroup_path() now always return the length of the full path. If buffer is too small, it contains nul terminated truncated output. * All users updated accordingly. v2: cgroup_path() usage in kernel/sched/debug.c converted. Signed-off-by: Tejun Heo Acked-by: Greg Kroah-Hartman Cc: Serge Hallyn Cc: Peter Zijlstra --- include/linux/blk-cgroup.h | 11 +-------- include/linux/cgroup.h | 16 ++++--------- kernel/cgroup.c | 48 +++++++++++++++++--------------------- kernel/cpuset.c | 12 +++++----- kernel/sched/debug.c | 3 ++- 5 files changed, 36 insertions(+), 54 deletions(-) diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h index 10648e300c930..4e8c215e185c1 100644 --- a/include/linux/blk-cgroup.h +++ b/include/linux/blk-cgroup.h @@ -343,16 +343,7 @@ static inline struct blkcg *cpd_to_blkcg(struct blkcg_policy_data *cpd) */ static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen) { - char *p; - - p = cgroup_path(blkg->blkcg->css.cgroup, buf, buflen); - if (!p) { - strncpy(buf, "", buflen); - return -ENAMETOOLONG; - } - - memmove(buf, p, buf + buflen - p); - return 0; + return cgroup_path(blkg->blkcg->css.cgroup, buf, buflen); } /** diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 5a9abdee43fe8..6df36361a4924 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -97,7 +97,7 @@ int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); int cgroup_rm_cftypes(struct cftype *cfts); void cgroup_file_notify(struct cgroup_file *cfile); -char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen); +int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen); int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry); int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *tsk); @@ -538,15 +538,9 @@ static inline int cgroup_name(struct cgroup *cgrp, char *buf, size_t buflen) return kernfs_name(cgrp->kn, buf, buflen); } -static inline char * __must_check cgroup_path(struct cgroup *cgrp, char *buf, - size_t buflen) +static inline int cgroup_path(struct cgroup *cgrp, char *buf, size_t buflen) { - int ret; - - ret = kernfs_path(cgrp->kn, buf, buflen); - if (ret < 0 || ret >= buflen) - return NULL; - return buf; + return kernfs_path(cgrp->kn, buf, buflen); } static inline void pr_cont_cgroup_name(struct cgroup *cgrp) @@ -639,8 +633,8 @@ struct cgroup_namespace *copy_cgroup_ns(unsigned long flags, struct user_namespace *user_ns, struct cgroup_namespace *old_ns); -char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, - struct cgroup_namespace *ns); +int cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, + struct cgroup_namespace *ns); #else /* !CONFIG_CGROUPS */ diff --git a/kernel/cgroup.c b/kernel/cgroup.c index d1c51b7f5221f..3861161e460f9 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2315,22 +2315,18 @@ static struct file_system_type cgroup2_fs_type = { .fs_flags = FS_USERNS_MOUNT, }; -static char *cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen, - struct cgroup_namespace *ns) +static int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen, + struct cgroup_namespace *ns) { struct cgroup *root = cset_cgroup_from_root(ns->root_cset, cgrp->root); - int ret; - ret = kernfs_path_from_node(cgrp->kn, root->kn, buf, buflen); - if (ret < 0 || ret >= buflen) - return NULL; - return buf; + return kernfs_path_from_node(cgrp->kn, root->kn, buf, buflen); } -char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, - struct cgroup_namespace *ns) +int cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, + struct cgroup_namespace *ns) { - char *ret; + int ret; mutex_lock(&cgroup_mutex); spin_lock_irq(&css_set_lock); @@ -2357,12 +2353,12 @@ EXPORT_SYMBOL_GPL(cgroup_path_ns); * * Return value is the same as kernfs_path(). */ -char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen) +int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen) { struct cgroup_root *root; struct cgroup *cgrp; int hierarchy_id = 1; - char *path = NULL; + int ret; mutex_lock(&cgroup_mutex); spin_lock_irq(&css_set_lock); @@ -2371,16 +2367,15 @@ char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen) if (root) { cgrp = task_cgroup_from_root(task, root); - path = cgroup_path_ns_locked(cgrp, buf, buflen, &init_cgroup_ns); + ret = cgroup_path_ns_locked(cgrp, buf, buflen, &init_cgroup_ns); } else { /* if no hierarchy exists, everyone is in "/" */ - if (strlcpy(buf, "/", buflen) < buflen) - path = buf; + ret = strlcpy(buf, "/", buflen); } spin_unlock_irq(&css_set_lock); mutex_unlock(&cgroup_mutex); - return path; + return ret; } EXPORT_SYMBOL_GPL(task_cgroup_path); @@ -5716,7 +5711,7 @@ core_initcall(cgroup_wq_init); int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *tsk) { - char *buf, *path; + char *buf; int retval; struct cgroup_root *root; @@ -5759,18 +5754,18 @@ int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, * " (deleted)" is appended to the cgroup path. */ if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) { - path = cgroup_path_ns_locked(cgrp, buf, PATH_MAX, + retval = cgroup_path_ns_locked(cgrp, buf, PATH_MAX, current->nsproxy->cgroup_ns); - if (!path) { + if (retval >= PATH_MAX) { retval = -ENAMETOOLONG; goto out_unlock; } + + seq_puts(m, buf); } else { - path = "/"; + seq_puts(m, "/"); } - seq_puts(m, path); - if (cgroup_on_dfl(cgrp) && cgroup_is_dead(cgrp)) seq_puts(m, " (deleted)\n"); else @@ -6035,8 +6030,9 @@ static void cgroup_release_agent(struct work_struct *work) { struct cgroup *cgrp = container_of(work, struct cgroup, release_agent_work); - char *pathbuf = NULL, *agentbuf = NULL, *path; + char *pathbuf = NULL, *agentbuf = NULL; char *argv[3], *envp[3]; + int ret; mutex_lock(&cgroup_mutex); @@ -6046,13 +6042,13 @@ static void cgroup_release_agent(struct work_struct *work) goto out; spin_lock_irq(&css_set_lock); - path = cgroup_path_ns_locked(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns); + ret = cgroup_path_ns_locked(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns); spin_unlock_irq(&css_set_lock); - if (!path) + if (ret >= PATH_MAX) goto out; argv[0] = agentbuf; - argv[1] = path; + argv[1] = pathbuf; argv[2] = NULL; /* minimal command environment */ diff --git a/kernel/cpuset.c b/kernel/cpuset.c index c7fd2778ed50e..793ae6fd96dcd 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -2689,7 +2689,7 @@ void __cpuset_memory_pressure_bump(void) int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *tsk) { - char *buf, *p; + char *buf; struct cgroup_subsys_state *css; int retval; @@ -2700,18 +2700,18 @@ int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, retval = -ENAMETOOLONG; css = task_get_css(tsk, cpuset_cgrp_id); - p = cgroup_path_ns(css->cgroup, buf, PATH_MAX, - current->nsproxy->cgroup_ns); + retval = cgroup_path_ns(css->cgroup, buf, PATH_MAX, + current->nsproxy->cgroup_ns); css_put(css); - if (!p) + if (retval >= PATH_MAX) goto out_free; - seq_puts(m, p); + seq_puts(m, buf); seq_putc(m, '\n'); retval = 0; out_free: kfree(buf); out: - return retval; + return 0; } #endif /* CONFIG_PROC_PID_CPUSET */ diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 2a0a9995256d9..23cb609ba4ebc 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -410,7 +410,8 @@ static char *task_group_path(struct task_group *tg) if (autogroup_path(tg, group_path, PATH_MAX)) return group_path; - return cgroup_path(tg->css.cgroup, group_path, PATH_MAX); + cgroup_path(tg->css.cgroup, group_path, PATH_MAX); + return group_path; } #endif -- GitLab From ed1777de25e45bfb58fad63341904f8a77911785 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 10 Aug 2016 11:23:44 -0400 Subject: [PATCH 0023/1167] cgroup: add tracepoints for basic operations Debugging what goes wrong with cgroup setup can get hairy. Add tracepoints for cgroup hierarchy mount, cgroup creation/destruction and task migration operations for better visibility. Signed-off-by: Tejun Heo --- include/trace/events/cgroup.h | 163 ++++++++++++++++++++++++++++++++++ kernel/cgroup.c | 25 ++++++ 2 files changed, 188 insertions(+) create mode 100644 include/trace/events/cgroup.h diff --git a/include/trace/events/cgroup.h b/include/trace/events/cgroup.h new file mode 100644 index 0000000000000..ab68640a18d0e --- /dev/null +++ b/include/trace/events/cgroup.h @@ -0,0 +1,163 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cgroup + +#if !defined(_TRACE_CGROUP_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_CGROUP_H + +#include +#include + +DECLARE_EVENT_CLASS(cgroup_root, + + TP_PROTO(struct cgroup_root *root), + + TP_ARGS(root), + + TP_STRUCT__entry( + __field( int, root ) + __field( u16, ss_mask ) + __string( name, root->name ) + ), + + TP_fast_assign( + __entry->root = root->hierarchy_id; + __entry->ss_mask = root->subsys_mask; + __assign_str(name, root->name); + ), + + TP_printk("root=%d ss_mask=%#x name=%s", + __entry->root, __entry->ss_mask, __get_str(name)) +); + +DEFINE_EVENT(cgroup_root, cgroup_setup_root, + + TP_PROTO(struct cgroup_root *root), + + TP_ARGS(root) +); + +DEFINE_EVENT(cgroup_root, cgroup_destroy_root, + + TP_PROTO(struct cgroup_root *root), + + TP_ARGS(root) +); + +DEFINE_EVENT(cgroup_root, cgroup_remount, + + TP_PROTO(struct cgroup_root *root), + + TP_ARGS(root) +); + +DECLARE_EVENT_CLASS(cgroup, + + TP_PROTO(struct cgroup *cgrp), + + TP_ARGS(cgrp), + + TP_STRUCT__entry( + __field( int, root ) + __field( int, id ) + __field( int, level ) + __dynamic_array(char, path, + cgrp->kn ? cgroup_path(cgrp, NULL, 0) + 1 + : strlen("(null)")) + ), + + TP_fast_assign( + __entry->root = cgrp->root->hierarchy_id; + __entry->id = cgrp->id; + __entry->level = cgrp->level; + if (cgrp->kn) + cgroup_path(cgrp, __get_dynamic_array(path), + __get_dynamic_array_len(path)); + else + __assign_str(path, "(null)"); + ), + + TP_printk("root=%d id=%d level=%d path=%s", + __entry->root, __entry->id, __entry->level, __get_str(path)) +); + +DEFINE_EVENT(cgroup, cgroup_mkdir, + + TP_PROTO(struct cgroup *cgroup), + + TP_ARGS(cgroup) +); + +DEFINE_EVENT(cgroup, cgroup_rmdir, + + TP_PROTO(struct cgroup *cgroup), + + TP_ARGS(cgroup) +); + +DEFINE_EVENT(cgroup, cgroup_release, + + TP_PROTO(struct cgroup *cgroup), + + TP_ARGS(cgroup) +); + +DEFINE_EVENT(cgroup, cgroup_rename, + + TP_PROTO(struct cgroup *cgroup), + + TP_ARGS(cgroup) +); + +DECLARE_EVENT_CLASS(cgroup_migrate, + + TP_PROTO(struct cgroup *dst_cgrp, struct task_struct *task, bool threadgroup), + + TP_ARGS(dst_cgrp, task, threadgroup), + + TP_STRUCT__entry( + __field( int, dst_root ) + __field( int, dst_id ) + __field( int, dst_level ) + __dynamic_array(char, dst_path, + dst_cgrp->kn ? cgroup_path(dst_cgrp, NULL, 0) + 1 + : strlen("(null)")) + __field( int, pid ) + __string( comm, task->comm ) + ), + + TP_fast_assign( + __entry->dst_root = dst_cgrp->root->hierarchy_id; + __entry->dst_id = dst_cgrp->id; + __entry->dst_level = dst_cgrp->level; + if (dst_cgrp->kn) + cgroup_path(dst_cgrp, __get_dynamic_array(dst_path), + __get_dynamic_array_len(dst_path)); + else + __assign_str(dst_path, "(null)"); + __entry->pid = task->pid; + __assign_str(comm, task->comm); + ), + + TP_printk("dst_root=%d dst_id=%d dst_level=%d dst_path=%s pid=%d comm=%s", + __entry->dst_root, __entry->dst_id, __entry->dst_level, + __get_str(dst_path), __entry->pid, __get_str(comm)) +); + +DEFINE_EVENT(cgroup_migrate, cgroup_attach_task, + + TP_PROTO(struct cgroup *dst_cgrp, struct task_struct *task, bool threadgroup), + + TP_ARGS(dst_cgrp, task, threadgroup) +); + +DEFINE_EVENT(cgroup_migrate, cgroup_transfer_tasks, + + TP_PROTO(struct cgroup *dst_cgrp, struct task_struct *task, bool threadgroup), + + TP_ARGS(dst_cgrp, task, threadgroup) +); + +#endif /* _TRACE_CGROUP_H */ + +/* This part must be outside protection */ +#include diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 3861161e460f9..5e2e81ad9175c 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -64,6 +64,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + /* * pidlists linger the following amount before being destroyed. The goal * is avoiding frequent destruction in the middle of consecutive read calls @@ -1176,6 +1179,8 @@ static void cgroup_destroy_root(struct cgroup_root *root) struct cgroup *cgrp = &root->cgrp; struct cgrp_cset_link *link, *tmp_link; + trace_cgroup_destroy_root(root); + cgroup_lock_and_drain_offline(&cgrp_dfl_root.cgrp); BUG_ON(atomic_read(&root->nr_cgrps)); @@ -1874,6 +1879,9 @@ static int cgroup_remount(struct kernfs_root *kf_root, int *flags, char *data) strcpy(root->release_agent_path, opts.release_agent); spin_unlock(&release_agent_path_lock); } + + trace_cgroup_remount(root); + out_unlock: kfree(opts.release_agent); kfree(opts.name); @@ -2031,6 +2039,8 @@ static int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask) if (ret) goto destroy_root; + trace_cgroup_setup_root(root); + /* * There must be no failure case after here, since rebinding takes * care of subsystems' refcounts, which are explicitly dropped in @@ -2825,6 +2835,10 @@ static int cgroup_attach_task(struct cgroup *dst_cgrp, ret = cgroup_migrate(leader, threadgroup, dst_cgrp->root); cgroup_migrate_finish(&preloaded_csets); + + if (!ret) + trace_cgroup_attach_task(dst_cgrp, leader, threadgroup); + return ret; } @@ -3587,6 +3601,8 @@ static int cgroup_rename(struct kernfs_node *kn, struct kernfs_node *new_parent, mutex_lock(&cgroup_mutex); ret = kernfs_rename(kn, new_parent, new_name_str); + if (!ret) + trace_cgroup_rename(cgrp); mutex_unlock(&cgroup_mutex); @@ -4355,6 +4371,8 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from) if (task) { ret = cgroup_migrate(task, false, to->root); + if (!ret) + trace_cgroup_transfer_tasks(to, task, false); put_task_struct(task); } } while (task && !ret); @@ -5020,6 +5038,8 @@ static void css_release_work_fn(struct work_struct *work) ss->css_released(css); } else { /* cgroup release path */ + trace_cgroup_release(cgrp); + cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id); cgrp->id = -1; @@ -5306,6 +5326,8 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name, if (ret) goto out_destroy; + trace_cgroup_mkdir(cgrp); + /* let's create and online css's */ kernfs_activate(kn); @@ -5481,6 +5503,9 @@ static int cgroup_rmdir(struct kernfs_node *kn) ret = cgroup_destroy_locked(cgrp); + if (!ret) + trace_cgroup_rmdir(cgrp); + cgroup_kn_unlock(kn); return ret; } -- GitLab From e7190699ca8c8daa52bfc62c01a71dea6decc9ee Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 10 Aug 2016 17:37:29 +0200 Subject: [PATCH 0024/1167] ahci: st: Add ports-implemented property in support Despite ST AHCI version = 1.3, reading HOST_PORTS_IMPL returns 0. So force_port_map to 1 by using ports-implemented DT property. Signed-off-by: Patrice Chotard Signed-off-by: Tejun Heo --- drivers/ata/ahci_st.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c index 8ff428fe8e0fa..bc345f2495553 100644 --- a/drivers/ata/ahci_st.c +++ b/drivers/ata/ahci_st.c @@ -147,6 +147,7 @@ static struct scsi_host_template ahci_platform_sht = { static int st_ahci_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct st_ahci_drv_data *drv_data; struct ahci_host_priv *hpriv; int err; @@ -170,6 +171,9 @@ static int st_ahci_probe(struct platform_device *pdev) st_ahci_configure_oob(hpriv->mmio); + of_property_read_u32(dev->of_node, + "ports-implemented", &hpriv->force_port_map); + err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, &ahci_platform_sht); if (err) { -- GitLab From b55d2c847454d197a7cf5ce2e1c175b080012184 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 10 Aug 2016 17:37:30 +0200 Subject: [PATCH 0025/1167] ARM: dts: STiH407-family: Add ports-implemented property in sata nodes Despite ST AHCI version = 1.3, reading HOST_PORTS_IMPL returns 0. So force HOST_PORTS_IMPL to 1 by using ports-implemented DT property. Signed-off-by: Patrice Chotard Signed-off-by: Tejun Heo --- arch/arm/boot/dts/stih407-family.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi index d294e82447a29..36d40f0516a15 100644 --- a/arch/arm/boot/dts/stih407-family.dtsi +++ b/arch/arm/boot/dts/stih407-family.dtsi @@ -608,6 +608,8 @@ clock-names = "ahci_clk"; clocks = <&clk_s_c0_flexgen CLK_ICN_REG>; + ports-implemented = <0x1>; + status = "disabled"; }; @@ -631,6 +633,8 @@ clock-names = "ahci_clk"; clocks = <&clk_s_c0_flexgen CLK_ICN_REG>; + ports-implemented = <0x1>; + status = "disabled"; }; -- GitLab From a2f5630cb737787c1bfd9aa894b1bf9f3f4554ea Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 29 Sep 2015 17:47:16 -0400 Subject: [PATCH 0026/1167] percpu_ref: remove unnecessary RCU grace period for staggered atomic switching confirmation At the beginning, percpu_ref guaranteed a RCU grace period between a call to percpu_ref_kill_and_confirm() and the invocation of the confirmation callback. This guarantee exposed internal implementation details and got rescinded while switching over to sched RCU; however, __percpu_ref_switch_to_atomic() still inserts a full sched RCU grace period even when it can simply wait for the previous attempt. Remove the unnecessary grace period and perform the confirmation synchronously for staggered atomic switching attempts. Update comments accordingly. Signed-off-by: Tejun Heo --- lib/percpu-refcount.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c index 27fe74948882e..8ade009ca2c92 100644 --- a/lib/percpu-refcount.c +++ b/lib/percpu-refcount.c @@ -177,17 +177,11 @@ static void __percpu_ref_switch_to_atomic(struct percpu_ref *ref, call_rcu_sched(&ref->rcu, percpu_ref_switch_to_atomic_rcu); } else if (confirm_switch) { /* - * Somebody already set ATOMIC. Switching may still be in - * progress. @confirm_switch must be invoked after the - * switching is complete and a full sched RCU grace period - * has passed. Wait synchronously for the previous - * switching and schedule @confirm_switch invocation. + * Somebody else already set ATOMIC. Wait for its + * completion and invoke @confirm_switch() directly. */ wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); - ref->confirm_switch = confirm_switch; - - percpu_ref_get(ref); /* put after confirmation */ - call_rcu_sched(&ref->rcu, percpu_ref_call_confirm_rcu); + confirm_switch(ref); } } @@ -211,10 +205,6 @@ static void __percpu_ref_switch_to_atomic(struct percpu_ref *ref, * but it may block if @confirm_kill is specified and @ref is already in * the process of switching to atomic mode. In such cases, @confirm_switch * will be invoked after the switching is complete. - * - * Due to the way percpu_ref is implemented, @confirm_switch will be called - * after at least one full sched RCU grace period has passed but this is an - * implementation detail and must not be depended upon. */ void percpu_ref_switch_to_atomic(struct percpu_ref *ref, percpu_ref_func_t *confirm_switch) @@ -290,11 +280,7 @@ void percpu_ref_switch_to_percpu(struct percpu_ref *ref) * * This function normally doesn't block and can be called from any context * but it may block if @confirm_kill is specified and @ref is in the - * process of switching to atomic mode by percpu_ref_switch_atomic(). - * - * Due to the way percpu_ref is implemented, @confirm_switch will be called - * after at least one full sched RCU grace period has passed but this is an - * implementation detail and must not be depended upon. + * process of switching to atomic mode by percpu_ref_switch_to_atomic(). */ void percpu_ref_kill_and_confirm(struct percpu_ref *ref, percpu_ref_func_t *confirm_kill) -- GitLab From b2302c7fdc654d249c546aac6228b8e10969bc1e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 29 Sep 2015 17:47:17 -0400 Subject: [PATCH 0027/1167] percpu_ref: reorganize __percpu_ref_switch_to_atomic() and relocate percpu_ref_switch_to_atomic() Reorganize __percpu_ref_switch_to_atomic() so that it looks structurally similar to __percpu_ref_switch_to_percpu() and relocate percpu_ref_switch_to_atomic so that the two internal functions are co-located. This patch doesn't introduce any functional differences. Signed-off-by: Tejun Heo --- lib/percpu-refcount.c | 98 ++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c index 8ade009ca2c92..599a78c0633b5 100644 --- a/lib/percpu-refcount.c +++ b/lib/percpu-refcount.c @@ -161,56 +161,30 @@ static void percpu_ref_noop_confirm_switch(struct percpu_ref *ref) static void __percpu_ref_switch_to_atomic(struct percpu_ref *ref, percpu_ref_func_t *confirm_switch) { - if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC)) { - /* switching from percpu to atomic */ - ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC; - - /* - * Non-NULL ->confirm_switch is used to indicate that - * switching is in progress. Use noop one if unspecified. - */ - WARN_ON_ONCE(ref->confirm_switch); - ref->confirm_switch = - confirm_switch ?: percpu_ref_noop_confirm_switch; - - percpu_ref_get(ref); /* put after confirmation */ - call_rcu_sched(&ref->rcu, percpu_ref_switch_to_atomic_rcu); - } else if (confirm_switch) { - /* - * Somebody else already set ATOMIC. Wait for its - * completion and invoke @confirm_switch() directly. - */ - wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); - confirm_switch(ref); + if (ref->percpu_count_ptr & __PERCPU_REF_ATOMIC) { + if (confirm_switch) { + /* + * Somebody else already set ATOMIC. Wait for its + * completion and invoke @confirm_switch() directly. + */ + wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); + confirm_switch(ref); + } + return; } -} -/** - * percpu_ref_switch_to_atomic - switch a percpu_ref to atomic mode - * @ref: percpu_ref to switch to atomic mode - * @confirm_switch: optional confirmation callback - * - * There's no reason to use this function for the usual reference counting. - * Use percpu_ref_kill[_and_confirm](). - * - * Schedule switching of @ref to atomic mode. All its percpu counts will - * be collected to the main atomic counter. On completion, when all CPUs - * are guaraneed to be in atomic mode, @confirm_switch, which may not - * block, is invoked. This function may be invoked concurrently with all - * the get/put operations and can safely be mixed with kill and reinit - * operations. Note that @ref will stay in atomic mode across kill/reinit - * cycles until percpu_ref_switch_to_percpu() is called. - * - * This function normally doesn't block and can be called from any context - * but it may block if @confirm_kill is specified and @ref is already in - * the process of switching to atomic mode. In such cases, @confirm_switch - * will be invoked after the switching is complete. - */ -void percpu_ref_switch_to_atomic(struct percpu_ref *ref, - percpu_ref_func_t *confirm_switch) -{ - ref->force_atomic = true; - __percpu_ref_switch_to_atomic(ref, confirm_switch); + /* switching from percpu to atomic */ + ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC; + + /* + * Non-NULL ->confirm_switch is used to indicate that switching is + * in progress. Use noop one if unspecified. + */ + WARN_ON_ONCE(ref->confirm_switch); + ref->confirm_switch = confirm_switch ?: percpu_ref_noop_confirm_switch; + + percpu_ref_get(ref); /* put after confirmation */ + call_rcu_sched(&ref->rcu, percpu_ref_switch_to_atomic_rcu); } static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref) @@ -240,6 +214,34 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref) ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC); } +/** + * percpu_ref_switch_to_atomic - switch a percpu_ref to atomic mode + * @ref: percpu_ref to switch to atomic mode + * @confirm_switch: optional confirmation callback + * + * There's no reason to use this function for the usual reference counting. + * Use percpu_ref_kill[_and_confirm](). + * + * Schedule switching of @ref to atomic mode. All its percpu counts will + * be collected to the main atomic counter. On completion, when all CPUs + * are guaraneed to be in atomic mode, @confirm_switch, which may not + * block, is invoked. This function may be invoked concurrently with all + * the get/put operations and can safely be mixed with kill and reinit + * operations. Note that @ref will stay in atomic mode across kill/reinit + * cycles until percpu_ref_switch_to_percpu() is called. + * + * This function normally doesn't block and can be called from any context + * but it may block if @confirm_kill is specified and @ref is already in + * the process of switching to atomic mode. In such cases, @confirm_switch + * will be invoked after the switching is complete. + */ +void percpu_ref_switch_to_atomic(struct percpu_ref *ref, + percpu_ref_func_t *confirm_switch) +{ + ref->force_atomic = true; + __percpu_ref_switch_to_atomic(ref, confirm_switch); +} + /** * percpu_ref_switch_to_percpu - switch a percpu_ref to percpu mode * @ref: percpu_ref to switch to percpu mode -- GitLab From 18808354b79622ed11857e41f9044ba17aec5b01 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 29 Sep 2015 17:47:18 -0400 Subject: [PATCH 0028/1167] percpu_ref: unify staggered atomic switching wait behavior When an atomic or percpu switching starts before the previous atomic switching finishes, the taken behaviors are * If the new atomic switching has confirmation callback, it waits for the previous atomic switching to complete. * If the new percpu switching is the first percpu switching following the previous atomic switching, it waits the previous atomic switching to complete. No percpu_ref user depends on these subtleties. The only meaningful part is that, if the caller ensures that atomic switching isn't in progress, mode switching operations can be issued from any context. This patch pulls the wait logic to the top of both switching functions so that they always wait for the previous atomic switching to complete. This makes the behavior simpler and consistent for both directions and will help allowing concurrent invocations of mode switching functions. Signed-off-by: Tejun Heo --- lib/percpu-refcount.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c index 599a78c0633b5..c3617a8525d7d 100644 --- a/lib/percpu-refcount.c +++ b/lib/percpu-refcount.c @@ -161,15 +161,19 @@ static void percpu_ref_noop_confirm_switch(struct percpu_ref *ref) static void __percpu_ref_switch_to_atomic(struct percpu_ref *ref, percpu_ref_func_t *confirm_switch) { + /* + * If the previous ATOMIC switching hasn't finished yet, wait for + * its completion. If the caller ensures that ATOMIC switching + * isn't in progress, this function can be called from any context. + * Do an extra confirm_switch test to circumvent the unconditional + * might_sleep() in wait_event(). + */ + if (ref->confirm_switch) + wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); + if (ref->percpu_count_ptr & __PERCPU_REF_ATOMIC) { - if (confirm_switch) { - /* - * Somebody else already set ATOMIC. Wait for its - * completion and invoke @confirm_switch() directly. - */ - wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); + if (confirm_switch) confirm_switch(ref); - } return; } @@ -180,7 +184,6 @@ static void __percpu_ref_switch_to_atomic(struct percpu_ref *ref, * Non-NULL ->confirm_switch is used to indicate that switching is * in progress. Use noop one if unspecified. */ - WARN_ON_ONCE(ref->confirm_switch); ref->confirm_switch = confirm_switch ?: percpu_ref_noop_confirm_switch; percpu_ref_get(ref); /* put after confirmation */ @@ -192,13 +195,21 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref) unsigned long __percpu *percpu_count = percpu_count_ptr(ref); int cpu; + /* + * If the previous ATOMIC switching hasn't finished yet, wait for + * its completion. If the caller ensures that ATOMIC switching + * isn't in progress, this function can be called from any context. + * Do an extra confirm_switch test to circumvent the unconditional + * might_sleep() in wait_event(). + */ + if (ref->confirm_switch) + wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); + BUG_ON(!percpu_count); if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC)) return; - wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); - atomic_long_add(PERCPU_COUNT_BIAS, &ref->count); /* -- GitLab From 3f49bdd95855a33eea749304d2e10530a869218b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 29 Sep 2015 17:47:19 -0400 Subject: [PATCH 0029/1167] percpu_ref: restructure operation mode switching Restructure atomic/percpu mode switching. * The users of __percpu_ref_switch_to_atomic/percpu() now call a new function __percpu_ref_switch_mode() which calls either of the original switching functions depending on the current state of ref->force_atomic and the __PERCPU_REF_DEAD flag. The callers no longer check whether switching is necessary but always invoke __percpu_ref_switch_mode(). * !ref->confirm_switch waiting is collected into __percpu_ref_switch_mode(). This patch doesn't cause any behavior differences. Signed-off-by: Tejun Heo --- lib/percpu-refcount.c | 64 ++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c index c3617a8525d7d..f3ff793691ac2 100644 --- a/lib/percpu-refcount.c +++ b/lib/percpu-refcount.c @@ -161,16 +161,6 @@ static void percpu_ref_noop_confirm_switch(struct percpu_ref *ref) static void __percpu_ref_switch_to_atomic(struct percpu_ref *ref, percpu_ref_func_t *confirm_switch) { - /* - * If the previous ATOMIC switching hasn't finished yet, wait for - * its completion. If the caller ensures that ATOMIC switching - * isn't in progress, this function can be called from any context. - * Do an extra confirm_switch test to circumvent the unconditional - * might_sleep() in wait_event(). - */ - if (ref->confirm_switch) - wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); - if (ref->percpu_count_ptr & __PERCPU_REF_ATOMIC) { if (confirm_switch) confirm_switch(ref); @@ -195,16 +185,6 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref) unsigned long __percpu *percpu_count = percpu_count_ptr(ref); int cpu; - /* - * If the previous ATOMIC switching hasn't finished yet, wait for - * its completion. If the caller ensures that ATOMIC switching - * isn't in progress, this function can be called from any context. - * Do an extra confirm_switch test to circumvent the unconditional - * might_sleep() in wait_event(). - */ - if (ref->confirm_switch) - wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); - BUG_ON(!percpu_count); if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC)) @@ -225,6 +205,25 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref) ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC); } +static void __percpu_ref_switch_mode(struct percpu_ref *ref, + percpu_ref_func_t *confirm_switch) +{ + /* + * If the previous ATOMIC switching hasn't finished yet, wait for + * its completion. If the caller ensures that ATOMIC switching + * isn't in progress, this function can be called from any context. + * Do an extra confirm_switch test to circumvent the unconditional + * might_sleep() in wait_event(). + */ + if (ref->confirm_switch) + wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); + + if (ref->force_atomic || (ref->percpu_count_ptr & __PERCPU_REF_DEAD)) + __percpu_ref_switch_to_atomic(ref, confirm_switch); + else + __percpu_ref_switch_to_percpu(ref); +} + /** * percpu_ref_switch_to_atomic - switch a percpu_ref to atomic mode * @ref: percpu_ref to switch to atomic mode @@ -241,16 +240,15 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref) * operations. Note that @ref will stay in atomic mode across kill/reinit * cycles until percpu_ref_switch_to_percpu() is called. * - * This function normally doesn't block and can be called from any context - * but it may block if @confirm_kill is specified and @ref is already in - * the process of switching to atomic mode. In such cases, @confirm_switch - * will be invoked after the switching is complete. + * This function may block if @ref is in the process of switching to atomic + * mode. If the caller ensures that @ref is not in the process of + * switching to atomic mode, this function can be called from any context. */ void percpu_ref_switch_to_atomic(struct percpu_ref *ref, percpu_ref_func_t *confirm_switch) { ref->force_atomic = true; - __percpu_ref_switch_to_atomic(ref, confirm_switch); + __percpu_ref_switch_mode(ref, confirm_switch); } /** @@ -267,17 +265,14 @@ void percpu_ref_switch_to_atomic(struct percpu_ref *ref, * dying or dead, the actual switching takes place on the following * percpu_ref_reinit(). * - * This function normally doesn't block and can be called from any context - * but it may block if @ref is in the process of switching to atomic mode - * by percpu_ref_switch_atomic(). + * This function may block if @ref is in the process of switching to atomic + * mode. If the caller ensures that @ref is not in the process of + * switching to atomic mode, this function can be called from any context. */ void percpu_ref_switch_to_percpu(struct percpu_ref *ref) { ref->force_atomic = false; - - /* a dying or dead ref can't be switched to percpu mode w/o reinit */ - if (!(ref->percpu_count_ptr & __PERCPU_REF_DEAD)) - __percpu_ref_switch_to_percpu(ref); + __percpu_ref_switch_mode(ref, NULL); } /** @@ -302,7 +297,7 @@ void percpu_ref_kill_and_confirm(struct percpu_ref *ref, "%s called more than once on %pf!", __func__, ref->release); ref->percpu_count_ptr |= __PERCPU_REF_DEAD; - __percpu_ref_switch_to_atomic(ref, confirm_kill); + __percpu_ref_switch_mode(ref, confirm_kill); percpu_ref_put(ref); } EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm); @@ -324,7 +319,6 @@ void percpu_ref_reinit(struct percpu_ref *ref) ref->percpu_count_ptr &= ~__PERCPU_REF_DEAD; percpu_ref_get(ref); - if (!ref->force_atomic) - __percpu_ref_switch_to_percpu(ref); + __percpu_ref_switch_mode(ref, NULL); } EXPORT_SYMBOL_GPL(percpu_ref_reinit); -- GitLab From 33e465ce7cb30b71c113a26f36d293b545a28e12 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 29 Sep 2015 17:47:20 -0400 Subject: [PATCH 0030/1167] percpu_ref: allow operation mode switching operations to be called concurrently percpu_ref initially didn't have explicit mode switching operations. It started out in percpu mode and switched to atomic mode on kill and then released. Ensuring that kill operation is initiated only after init completes was naturally the caller's responsibility. percpu_ref_reinit() was introduced later but it didn't shift the synchronization responsibility. Reinit can't be performed until kill is confirmed, so there was nothing to worry about synchronization-wise. Also, as both reinit and kill manipulate the base reference, invocations of the same function couldn't be allowed to race each other. The latest additions of percpu_ref_switch_to_atomic/percpu() changed the situation. These two functions can be called any time as long as the percpu_ref is between init and exit and thus there are valid valid usage scenarios where these new functions race with each other or against reinit/kill. Mostly from inertia, f47ad4578461 ("percpu_ref: decouple switching to percpu mode and reinit") still left synchronization among percpu mode switching operations to its users. That the new switch functions can be freely mixed with kill/reinit but the operations themselves should be synchronized is too subtle a requirement and led to a very subtle race condition in blk-mq freezing path. This patch fixes the situation by introducing percpu_ref_switch_lock to protect mode switching operations. This ensures that percpu-ref users don't have to worry about mode changing operations racing against each other, e.g. switch_to_percpu against kill, as long as the sequence of operations is valid. Signed-off-by: Tejun Heo Reported-by: Akinobu Mita Link: http://lkml.kernel.org/g/1443287365-4244-7-git-send-email-akinobu.mita@gmail.com Fixes: f47ad4578461 ("percpu_ref: decouple switching to percpu mode and reinit") --- lib/percpu-refcount.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c index f3ff793691ac2..c69938e4b0d5c 100644 --- a/lib/percpu-refcount.c +++ b/lib/percpu-refcount.c @@ -33,6 +33,7 @@ #define PERCPU_COUNT_BIAS (1LU << (BITS_PER_LONG - 1)) +static DEFINE_SPINLOCK(percpu_ref_switch_lock); static DECLARE_WAIT_QUEUE_HEAD(percpu_ref_switch_waitq); static unsigned long __percpu *percpu_count_ptr(struct percpu_ref *ref) @@ -208,15 +209,15 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref) static void __percpu_ref_switch_mode(struct percpu_ref *ref, percpu_ref_func_t *confirm_switch) { + lockdep_assert_held(&percpu_ref_switch_lock); + /* * If the previous ATOMIC switching hasn't finished yet, wait for * its completion. If the caller ensures that ATOMIC switching * isn't in progress, this function can be called from any context. - * Do an extra confirm_switch test to circumvent the unconditional - * might_sleep() in wait_event(). */ - if (ref->confirm_switch) - wait_event(percpu_ref_switch_waitq, !ref->confirm_switch); + wait_event_lock_irq(percpu_ref_switch_waitq, !ref->confirm_switch, + percpu_ref_switch_lock); if (ref->force_atomic || (ref->percpu_count_ptr & __PERCPU_REF_DEAD)) __percpu_ref_switch_to_atomic(ref, confirm_switch); @@ -247,8 +248,14 @@ static void __percpu_ref_switch_mode(struct percpu_ref *ref, void percpu_ref_switch_to_atomic(struct percpu_ref *ref, percpu_ref_func_t *confirm_switch) { + unsigned long flags; + + spin_lock_irqsave(&percpu_ref_switch_lock, flags); + ref->force_atomic = true; __percpu_ref_switch_mode(ref, confirm_switch); + + spin_unlock_irqrestore(&percpu_ref_switch_lock, flags); } /** @@ -271,8 +278,14 @@ void percpu_ref_switch_to_atomic(struct percpu_ref *ref, */ void percpu_ref_switch_to_percpu(struct percpu_ref *ref) { + unsigned long flags; + + spin_lock_irqsave(&percpu_ref_switch_lock, flags); + ref->force_atomic = false; __percpu_ref_switch_mode(ref, NULL); + + spin_unlock_irqrestore(&percpu_ref_switch_lock, flags); } /** @@ -293,12 +306,18 @@ void percpu_ref_switch_to_percpu(struct percpu_ref *ref) void percpu_ref_kill_and_confirm(struct percpu_ref *ref, percpu_ref_func_t *confirm_kill) { + unsigned long flags; + + spin_lock_irqsave(&percpu_ref_switch_lock, flags); + WARN_ONCE(ref->percpu_count_ptr & __PERCPU_REF_DEAD, "%s called more than once on %pf!", __func__, ref->release); ref->percpu_count_ptr |= __PERCPU_REF_DEAD; __percpu_ref_switch_mode(ref, confirm_kill); percpu_ref_put(ref); + + spin_unlock_irqrestore(&percpu_ref_switch_lock, flags); } EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm); @@ -315,10 +334,16 @@ EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm); */ void percpu_ref_reinit(struct percpu_ref *ref) { + unsigned long flags; + + spin_lock_irqsave(&percpu_ref_switch_lock, flags); + WARN_ON_ONCE(!percpu_ref_is_zero(ref)); ref->percpu_count_ptr &= ~__PERCPU_REF_DEAD; percpu_ref_get(ref); __percpu_ref_switch_mode(ref, NULL); + + spin_unlock_irqrestore(&percpu_ref_switch_lock, flags); } EXPORT_SYMBOL_GPL(percpu_ref_reinit); -- GitLab From cd27396e6103a43c3df76f70db1feafa16206471 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Aug 2016 07:26:02 -0700 Subject: [PATCH 0031/1167] ahci: also use a per-port lock for the multi-MSIX case Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- drivers/ata/libahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 7461a587b39b4..7c01192d3c48f 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2378,7 +2378,7 @@ static int ahci_port_start(struct ata_port *ap) /* * Switch to per-port locking in case each port has its own MSI vector. */ - if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) { + if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) { spin_lock_init(&pp->lock); ap->lock = &pp->lock; } -- GitLab From a67823c1ed1092160da94c31e6da5aeb35dca81c Mon Sep 17 00:00:00 2001 From: Roman Pen Date: Thu, 11 Aug 2016 19:27:09 +0200 Subject: [PATCH 0032/1167] percpu-refcount: init ->confirm_switch member properly This patch targets two things which are related to ->confirm_switch: 1. Init ->confirm_switch pointer with NULL on percpu_ref_init() or kernel frightfully complains with WARN_ON_ONCE(ref->confirm_switch) at __percpu_ref_switch_to_atomic if memory chunk was not properly zeroed. 2. Warn if RCU callback is still in progress on percpu_ref_exit(). The race still exists, because percpu_ref_call_confirm_rcu() drops ->confirm_switch to NULL early, but that is only a warning and still the caller is responsible that ref is no longer in active use. Hopefully that can help to catch incorrect usage of percpu-refcount. Signed-off-by: Roman Pen Cc: Tejun Heo Cc: linux-kernel@vger.kernel.org Signed-off-by: Tejun Heo --- lib/percpu-refcount.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c index c69938e4b0d5c..9ac959ef4cae9 100644 --- a/lib/percpu-refcount.c +++ b/lib/percpu-refcount.c @@ -83,6 +83,7 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release, atomic_long_set(&ref->count, start_count); ref->release = release; + ref->confirm_switch = NULL; return 0; } EXPORT_SYMBOL_GPL(percpu_ref_init); @@ -102,6 +103,8 @@ void percpu_ref_exit(struct percpu_ref *ref) unsigned long __percpu *percpu_count = percpu_count_ptr(ref); if (percpu_count) { + /* non-NULL confirm_switch indicates switching in progress */ + WARN_ON_ONCE(ref->confirm_switch); free_percpu(percpu_count); ref->percpu_count_ptr = __PERCPU_REF_ATOMIC_DEAD; } -- GitLab From dee81e9886748594babac67c14b0f720148e255d Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 24 Aug 2016 21:03:05 +0300 Subject: [PATCH 0033/1167] fixdep: faster CONFIG_ search Do you think kernel build is 100% dominated by gcc? You are wrong! One small utility called "fixdep" consistently manages to sneak into profile's first page (unless you have small monitor of course). The choke point is this clever code: for (; m < end; m++) { if (*m == INT_CONF) { p = (char *) m ; goto conf; } if (*m == INT_ONFI) { p = (char *) m-1; goto conf; } if (*m == INT_NFIG) { p = (char *) m-2; goto conf; } if (*m == INT_FIG_) { p = (char *) m-3; goto conf; } 4 branches per 4 characters is not fast. Use strstr(3), so that SSE2 etc can be used. With this patch, fixdep is so deep at the bottom, it is hard to find it. Signed-off-by: Alexey Dobriyan Signed-off-by: Michal Marek --- scripts/basic/fixdep.c | 86 ++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 58 deletions(-) diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 746ec1ece6143..fff818b92acb7 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -82,8 +82,7 @@ * to date before even starting the recursive build, so it's too late * at this point anyway. * - * The algorithm to grep for "CONFIG_..." is bit unusual, but should - * be fast ;-) We don't even try to really parse the header files, but + * We don't even try to really parse the header files, but * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will * be picked up as well. It's not a problem with respect to * correctness, since that can only give too many dependencies, thus @@ -115,11 +114,6 @@ #include #include -#define INT_CONF ntohl(0x434f4e46) -#define INT_ONFI ntohl(0x4f4e4649) -#define INT_NFIG ntohl(0x4e464947) -#define INT_FIG_ ntohl(0x4649475f) - int insert_extra_deps; char *target; char *depfile; @@ -241,37 +235,22 @@ static void use_config(const char *m, int slen) print_config(m, slen); } -static void parse_config_file(const char *map, size_t len) +static void parse_config_file(const char *p) { - const int *end = (const int *) (map + len); - /* start at +1, so that p can never be < map */ - const int *m = (const int *) map + 1; - const char *p, *q; - - for (; m < end; m++) { - if (*m == INT_CONF) { p = (char *) m ; goto conf; } - if (*m == INT_ONFI) { p = (char *) m-1; goto conf; } - if (*m == INT_NFIG) { p = (char *) m-2; goto conf; } - if (*m == INT_FIG_) { p = (char *) m-3; goto conf; } - continue; - conf: - if (p > map + len - 7) - continue; - if (memcmp(p, "CONFIG_", 7)) - continue; + const char *q, *r; + + while ((p = strstr(p, "CONFIG_"))) { p += 7; - for (q = p; q < map + len; q++) { - if (!(isalnum(*q) || *q == '_')) - goto found; - } - continue; - - found: - if (!memcmp(q - 7, "_MODULE", 7)) - q -= 7; - if (q - p < 0) - continue; - use_config(p, q - p); + q = p; + while (*q && (isalnum(*q) || *q == '_')) + q++; + if (memcmp(q - 7, "_MODULE", 7) == 0) + r = q - 7; + else + r = q; + if (r > p) + use_config(p, r - p); + p = q; } } @@ -291,7 +270,7 @@ static void do_config_file(const char *filename) { struct stat st; int fd; - void *map; + char *map; fd = open(filename, O_RDONLY); if (fd < 0) { @@ -308,18 +287,23 @@ static void do_config_file(const char *filename) close(fd); return; } - map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if ((long) map == -1) { - perror("fixdep: mmap"); + map = malloc(st.st_size + 1); + if (!map) { + perror("fixdep: malloc"); close(fd); return; } + if (read(fd, map, st.st_size) != st.st_size) { + perror("fixdep: read"); + close(fd); + return; + } + map[st.st_size] = '\0'; + close(fd); - parse_config_file(map, st.st_size); - - munmap(map, st.st_size); + parse_config_file(map); - close(fd); + free(map); } /* @@ -446,22 +430,8 @@ static void print_deps(void) close(fd); } -static void traps(void) -{ - static char test[] __attribute__((aligned(sizeof(int)))) = "CONF"; - int *p = (int *)test; - - if (*p != INT_CONF) { - fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianness? %#x\n", - *p); - exit(2); - } -} - int main(int argc, char *argv[]) { - traps(); - if (argc == 5 && !strcmp(argv[1], "-e")) { insert_extra_deps = 1; argv++; -- GitLab From 9379e6b8e0f995365dc6158a1463c8dab4f2c8da Mon Sep 17 00:00:00 2001 From: Shaun Tancheff Date: Sun, 21 Aug 2016 23:23:18 -0500 Subject: [PATCH 0034/1167] libata: Safely overwrite attached page in WRITE SAME xlat Safely overwriting the attached page to ATA format from the SCSI formatted variant. Signed-off-by: Shaun Tancheff Reviewed-by: Hannes Reinecke Acked-by: Tejun Heo --- drivers/ata/libata-scsi.c | 56 +++++++++++++++++++++++++++++++++++---- include/linux/ata.h | 26 ------------------ 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index be9c76c938b22..84e7f48ca83ed 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3282,6 +3282,54 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) return 1; } +/** + * ata_format_dsm_trim_descr() - SATL Write Same to DSM Trim + * @cmd: SCSI command being translated + * @num: Maximum number of entries (nominally 64). + * @sector: Starting sector + * @count: Total Range of request + * + * Rewrite the WRITE SAME descriptor to be a DSM TRIM little-endian formatted + * descriptor. + * + * Upto 64 entries of the format: + * 63:48 Range Length + * 47:0 LBA + * + * Range Length of 0 is ignored. + * LBA's should be sorted order and not overlap. + * + * NOTE: this is the same format as ADD LBA(S) TO NV CACHE PINNED SET + */ +static unsigned int ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 num, + u64 sector, u32 count) +{ + __le64 *buffer; + u32 i = 0, used_bytes; + unsigned long flags; + + BUILD_BUG_ON(512 > ATA_SCSI_RBUF_SIZE); + + spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); + buffer = ((void *)ata_scsi_rbuf); + while (i < num) { + u64 entry = sector | + ((u64)(count > 0xffff ? 0xffff : count) << 48); + buffer[i++] = __cpu_to_le64(entry); + if (count <= 0xffff) + break; + count -= 0xffff; + sector += 0xffff; + } + + used_bytes = ALIGN(i * 8, 512); + memset(buffer + i, 0, used_bytes - i * 8); + sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buffer, 512); + spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); + + return used_bytes; +} + static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) { struct ata_taskfile *tf = &qc->tf; @@ -3290,8 +3338,8 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) const u8 *cdb = scmd->cmnd; u64 block; u32 n_block; + const u32 trmax = ATA_MAX_TRIM_RNUM; u32 size; - void *buf; u16 fp; u8 bp = 0xff; @@ -3319,10 +3367,8 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) if (!scsi_sg_count(scmd)) goto invalid_param_len; - buf = page_address(sg_page(scsi_sglist(scmd))); - - if (n_block <= 65535 * ATA_MAX_TRIM_RNUM) { - size = ata_set_lba_range_entries(buf, ATA_MAX_TRIM_RNUM, block, n_block); + if (n_block <= 0xffff * trmax) { + size = ata_format_dsm_trim_descr(scmd, trmax, block, n_block); } else { fp = 2; goto invalid_fld; diff --git a/include/linux/ata.h b/include/linux/ata.h index adbc812c009b5..45a1d71c55f18 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -1071,32 +1071,6 @@ static inline void ata_id_to_hd_driveid(u16 *id) #endif } -/* - * Write LBA Range Entries to the buffer that will cover the extent from - * sector to sector + count. This is used for TRIM and for ADD LBA(S) - * TO NV CACHE PINNED SET. - */ -static inline unsigned ata_set_lba_range_entries(void *_buffer, - unsigned num, u64 sector, unsigned long count) -{ - __le64 *buffer = _buffer; - unsigned i = 0, used_bytes; - - while (i < num) { - u64 entry = sector | - ((u64)(count > 0xffff ? 0xffff : count) << 48); - buffer[i++] = __cpu_to_le64(entry); - if (count <= 0xffff) - break; - count -= 0xffff; - sector += 0xffff; - } - - used_bytes = ALIGN(i * 8, 512); - memset(buffer + i, 0, used_bytes - i * 8); - return used_bytes; -} - static inline bool ata_ok(u8 status) { return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) -- GitLab From 7b20309428598df00ffeb0b01f5948dea6aaf1f7 Mon Sep 17 00:00:00 2001 From: Shaun Tancheff Date: Sun, 21 Aug 2016 23:23:19 -0500 Subject: [PATCH 0035/1167] libata: Add support for SCT Write Same SATA drives may support write same via SCT. This is useful for setting the drive contents to a specific pattern (0's). Translate a SCSI WRITE SAME 16 command to be either a DSM TRIM command or an SCT Write Same command. Based on the UNMAP flag: - When set translate to DSM TRIM - When not set translate to SCT Write Same Signed-off-by: Shaun Tancheff Reviewed-by: Hannes Reinecke Acked-by: Tejun Heo --- drivers/ata/libata-scsi.c | 199 ++++++++++++++++++++++++++++++++------ include/linux/ata.h | 43 ++++++++ 2 files changed, 213 insertions(+), 29 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 84e7f48ca83ed..08d9c8e731b3f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1159,8 +1159,6 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) { sdev->use_10_for_rw = 1; sdev->use_10_for_ms = 1; - sdev->no_report_opcodes = 1; - sdev->no_write_same = 1; /* Schedule policy is determined by ->qc_defer() callback and * it needs to see every deferred qc. Set dev_blocked to 1 to @@ -3287,7 +3285,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) * @cmd: SCSI command being translated * @num: Maximum number of entries (nominally 64). * @sector: Starting sector - * @count: Total Range of request + * @count: Total Range of request in logical sectors * * Rewrite the WRITE SAME descriptor to be a DSM TRIM little-endian formatted * descriptor. @@ -3330,6 +3328,45 @@ static unsigned int ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 num, return used_bytes; } +/** + * ata_format_dsm_trim_descr() - SATL Write Same to ATA SCT Write Same + * @cmd: SCSI command being translated + * @lba: Starting sector + * @num: Number of logical sectors to be zero'd. + * + * Rewrite the WRITE SAME descriptor to be an SCT Write Same formatted + * descriptor. + * NOTE: Writes a pattern (0's) in the foreground. + * Large write-same requents can timeout. + */ +static void ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba, u64 num) +{ + u16 *sctpg; + unsigned long flags; + + spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); + sctpg = ((void *)ata_scsi_rbuf); + + put_unaligned_le16(0x0002, &sctpg[0]); /* SCT_ACT_WRITE_SAME */ + put_unaligned_le16(0x0101, &sctpg[1]); /* WRITE PTRN FG */ + put_unaligned_le64(lba, &sctpg[2]); + put_unaligned_le64(num, &sctpg[6]); + put_unaligned_le32(0u, &sctpg[10]); + + sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), sctpg, 512); + spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); +} + +/** + * ata_scsi_write_same_xlat() - SATL Write Same to ATA SCT Write Same + * @qc: Command to be translated + * + * Translate a SCSI WRITE SAME command to be either a DSM TRIM command or + * an SCT Write Same command. + * Based on WRITE SAME has the UNMAP flag + * When set translate to DSM TRIM + * When clear translate to SCT Write Same + */ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) { struct ata_taskfile *tf = &qc->tf; @@ -3342,6 +3379,7 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) u32 size; u16 fp; u8 bp = 0xff; + u8 unmap = cdb[1] & 0x8; /* we may not issue DMA commands if no DMA mode is set */ if (unlikely(!dev->dma_mode)) @@ -3353,11 +3391,26 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) } scsi_16_lba_len(cdb, &block, &n_block); - /* for now we only support WRITE SAME with the unmap bit set */ - if (unlikely(!(cdb[1] & 0x8))) { - fp = 1; - bp = 3; - goto invalid_fld; + if (unmap) { + /* If trim is not enabled the cmd is invalid. */ + if ((dev->horkage & ATA_HORKAGE_NOTRIM) || + !ata_id_has_trim(dev->id)) { + fp = 1; + bp = 3; + goto invalid_fld; + } + /* If the request is too large the cmd is invalid */ + if (n_block > 0xffff * trmax) { + fp = 2; + goto invalid_fld; + } + } else { + /* If write same is not available the cmd is invalid */ + if (!ata_id_sct_write_same(dev->id)) { + fp = 1; + bp = 3; + goto invalid_fld; + } } /* @@ -3367,30 +3420,42 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) if (!scsi_sg_count(scmd)) goto invalid_param_len; - if (n_block <= 0xffff * trmax) { + if (unmap) { size = ata_format_dsm_trim_descr(scmd, trmax, block, n_block); + if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) { + /* Newer devices support queued TRIM commands */ + tf->protocol = ATA_PROT_NCQ; + tf->command = ATA_CMD_FPDMA_SEND; + tf->hob_nsect = ATA_SUBCMD_FPDMA_SEND_DSM & 0x1f; + tf->nsect = qc->tag << 3; + tf->hob_feature = (size / 512) >> 8; + tf->feature = size / 512; + + tf->auxiliary = 1; + } else { + tf->protocol = ATA_PROT_DMA; + tf->hob_feature = 0; + tf->feature = ATA_DSM_TRIM; + tf->hob_nsect = (size / 512) >> 8; + tf->nsect = size / 512; + tf->command = ATA_CMD_DSM; + } } else { - fp = 2; - goto invalid_fld; - } - - if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) { - /* Newer devices support queued TRIM commands */ - tf->protocol = ATA_PROT_NCQ; - tf->command = ATA_CMD_FPDMA_SEND; - tf->hob_nsect = ATA_SUBCMD_FPDMA_SEND_DSM & 0x1f; - tf->nsect = qc->tag << 3; - tf->hob_feature = (size / 512) >> 8; - tf->feature = size / 512; + ata_format_sct_write_same(scmd, block, n_block); - tf->auxiliary = 1; - } else { - tf->protocol = ATA_PROT_DMA; tf->hob_feature = 0; - tf->feature = ATA_DSM_TRIM; - tf->hob_nsect = (size / 512) >> 8; - tf->nsect = size / 512; - tf->command = ATA_CMD_DSM; + tf->feature = 0; + tf->hob_nsect = 0; + tf->nsect = 1; + tf->lbah = 0; + tf->lbam = 0; + tf->lbal = ATA_CMD_STANDBYNOW1; + tf->hob_lbah = 0; + tf->hob_lbam = 0; + tf->hob_lbal = 0; + tf->device = ATA_CMD_STANDBYNOW1; + tf->protocol = ATA_PROT_DMA; + tf->command = ATA_CMD_WRITE_LOG_DMA_EXT; } tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | @@ -3413,6 +3478,76 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) return 1; } +/** + * ata_scsiop_maint_in - Simulate a subset of MAINTENANCE_IN + * @args: device MAINTENANCE_IN data / SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Yields a subset to satisfy scsi_report_opcode() + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) +{ + struct ata_device *dev = args->dev; + u8 *cdb = args->cmd->cmnd; + u8 supported = 0; + unsigned int err = 0; + + if (cdb[2] != 1) { + ata_dev_warn(dev, "invalid command format %d\n", cdb[2]); + err = 2; + goto out; + } + switch (cdb[3]) { + case INQUIRY: + case MODE_SENSE: + case MODE_SENSE_10: + case READ_CAPACITY: + case SERVICE_ACTION_IN_16: + case REPORT_LUNS: + case REQUEST_SENSE: + case SYNCHRONIZE_CACHE: + case REZERO_UNIT: + case SEEK_6: + case SEEK_10: + case TEST_UNIT_READY: + case SEND_DIAGNOSTIC: + case MAINTENANCE_IN: + case READ_6: + case READ_10: + case READ_16: + case WRITE_6: + case WRITE_10: + case WRITE_16: + case ATA_12: + case ATA_16: + case VERIFY: + case VERIFY_16: + case MODE_SELECT: + case MODE_SELECT_10: + case START_STOP: + supported = 3; + break; + case WRITE_SAME_16: + if (ata_id_sct_write_same(dev->id)) + supported = 3; + break; + case ZBC_IN: + case ZBC_OUT: + if (ata_id_zoned_cap(dev->id) || + dev->class == ATA_DEV_ZAC) + supported = 3; + break; + default: + break; + } +out: + rbuf[1] = supported; /* supported */ + return err; +} + /** * ata_scsi_report_zones_complete - convert ATA output * @qc: command structure returning the data @@ -4193,6 +4328,13 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) ata_scsi_invalid_field(dev, cmd, 1); break; + case MAINTENANCE_IN: + if (scsicmd[1] == MI_REPORT_SUPPORTED_OPERATION_CODES) + ata_scsi_rbuf_fill(&args, ata_scsiop_maint_in); + else + ata_scsi_invalid_field(dev, cmd, 1); + break; + /* all other commands */ default: ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0); @@ -4225,7 +4367,6 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) shost->max_lun = 1; shost->max_channel = 1; shost->max_cmd_len = 16; - shost->no_write_same = 1; /* Schedule policy is determined by ->qc_defer() * callback and it needs to see every deferred qc. diff --git a/include/linux/ata.h b/include/linux/ata.h index 45a1d71c55f18..fdb180367ba13 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -105,6 +105,7 @@ enum { ATA_ID_CFA_KEY_MGMT = 162, ATA_ID_CFA_MODES = 163, ATA_ID_DATA_SET_MGMT = 169, + ATA_ID_SCT_CMD_XPORT = 206, ATA_ID_ROT_SPEED = 217, ATA_ID_PIO4 = (1 << 1), @@ -788,6 +789,48 @@ static inline bool ata_id_sense_reporting_enabled(const u16 *id) return id[ATA_ID_COMMAND_SET_4] & (1 << 6); } +/** + * + * Word: 206 - SCT Command Transport + * 15:12 - Vendor Specific + * 11:6 - Reserved + * 5 - SCT Command Transport Data Tables supported + * 4 - SCT Command Transport Features Control supported + * 3 - SCT Command Transport Error Recovery Control supported + * 2 - SCT Command Transport Write Same supported + * 1 - SCT Command Transport Long Sector Access supported + * 0 - SCT Command Transport supported + */ +static inline bool ata_id_sct_data_tables(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 5) ? true : false; +} + +static inline bool ata_id_sct_features_ctrl(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 4) ? true : false; +} + +static inline bool ata_id_sct_error_recovery_ctrl(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 3) ? true : false; +} + +static inline bool ata_id_sct_write_same(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 2) ? true : false; +} + +static inline bool ata_id_sct_long_sector_access(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 1) ? true : false; +} + +static inline bool ata_id_sct_supported(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 0) ? true : false; +} + /** * ata_id_major_version - get ATA level of drive * @id: Identify data -- GitLab From ef2d7392c4ece5c3cd12a6c7ca9366cd8f189aff Mon Sep 17 00:00:00 2001 From: Shaun Tancheff Date: Wed, 24 Aug 2016 13:08:14 -0500 Subject: [PATCH 0036/1167] libata: SCT Write Same / DSM Trim Correct handling of devices with sector_size other that 512 bytes. In the case of a 4Kn device sector_size it is possible to describe a much larger DSM Trim than the current fixed default of 512 bytes. This patch assumes the minimum descriptor is sector_size and fills out the descriptor accordingly. The ACS-2 specification is quite clear that the DSM command payload is sized as number of 512 byte transfers so a 4Kn device will operate correctly without this patch. Signed-off-by: Shaun Tancheff Acked-by: Tejun Heo --- drivers/ata/libata-scsi.c | 85 ++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 08d9c8e731b3f..35b1f9e475cc4 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3283,7 +3283,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) /** * ata_format_dsm_trim_descr() - SATL Write Same to DSM Trim * @cmd: SCSI command being translated - * @num: Maximum number of entries (nominally 64). + * @trmax: Maximum number of entries that will fit in sector_size bytes. * @sector: Starting sector * @count: Total Range of request in logical sectors * @@ -3298,63 +3298,80 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) * LBA's should be sorted order and not overlap. * * NOTE: this is the same format as ADD LBA(S) TO NV CACHE PINNED SET + * + * Return: Number of bytes copied into sglist. */ -static unsigned int ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 num, - u64 sector, u32 count) +static size_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax, + u64 sector, u32 count) { - __le64 *buffer; - u32 i = 0, used_bytes; + struct scsi_device *sdp = cmd->device; + size_t len = sdp->sector_size; + size_t r; + __le64 *buf; + u32 i = 0; unsigned long flags; - BUILD_BUG_ON(512 > ATA_SCSI_RBUF_SIZE); + WARN_ON(len > ATA_SCSI_RBUF_SIZE); + + if (len > ATA_SCSI_RBUF_SIZE) + len = ATA_SCSI_RBUF_SIZE; spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); - buffer = ((void *)ata_scsi_rbuf); - while (i < num) { + buf = ((void *)ata_scsi_rbuf); + memset(buf, 0, len); + while (i < trmax) { u64 entry = sector | ((u64)(count > 0xffff ? 0xffff : count) << 48); - buffer[i++] = __cpu_to_le64(entry); + buf[i++] = __cpu_to_le64(entry); if (count <= 0xffff) break; count -= 0xffff; sector += 0xffff; } - - used_bytes = ALIGN(i * 8, 512); - memset(buffer + i, 0, used_bytes - i * 8); - sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buffer, 512); + r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, len); spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); - return used_bytes; + return r; } /** * ata_format_dsm_trim_descr() - SATL Write Same to ATA SCT Write Same * @cmd: SCSI command being translated * @lba: Starting sector - * @num: Number of logical sectors to be zero'd. + * @num: Number of sectors to be zero'd. * - * Rewrite the WRITE SAME descriptor to be an SCT Write Same formatted + * Rewrite the WRITE SAME payload to be an SCT Write Same formatted * descriptor. * NOTE: Writes a pattern (0's) in the foreground. - * Large write-same requents can timeout. + * + * Return: Number of bytes copied into sglist. */ -static void ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba, u64 num) +static size_t ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba, u64 num) { - u16 *sctpg; + struct scsi_device *sdp = cmd->device; + size_t len = sdp->sector_size; + size_t r; + u16 *buf; unsigned long flags; spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); - sctpg = ((void *)ata_scsi_rbuf); + buf = ((void *)ata_scsi_rbuf); + + put_unaligned_le16(0x0002, &buf[0]); /* SCT_ACT_WRITE_SAME */ + put_unaligned_le16(0x0101, &buf[1]); /* WRITE PTRN FG */ + put_unaligned_le64(lba, &buf[2]); + put_unaligned_le64(num, &buf[6]); + put_unaligned_le32(0u, &buf[10]); /* pattern */ + + WARN_ON(len > ATA_SCSI_RBUF_SIZE); - put_unaligned_le16(0x0002, &sctpg[0]); /* SCT_ACT_WRITE_SAME */ - put_unaligned_le16(0x0101, &sctpg[1]); /* WRITE PTRN FG */ - put_unaligned_le64(lba, &sctpg[2]); - put_unaligned_le64(num, &sctpg[6]); - put_unaligned_le32(0u, &sctpg[10]); + if (len > ATA_SCSI_RBUF_SIZE) + len = ATA_SCSI_RBUF_SIZE; - sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), sctpg, 512); + r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, len); spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); + + return r; } /** @@ -3371,11 +3388,13 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) { struct ata_taskfile *tf = &qc->tf; struct scsi_cmnd *scmd = qc->scsicmd; + struct scsi_device *sdp = scmd->device; + size_t len = sdp->sector_size; struct ata_device *dev = qc->dev; const u8 *cdb = scmd->cmnd; u64 block; u32 n_block; - const u32 trmax = ATA_MAX_TRIM_RNUM; + const u32 trmax = len >> 3; u32 size; u16 fp; u8 bp = 0xff; @@ -3420,8 +3439,16 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) if (!scsi_sg_count(scmd)) goto invalid_param_len; + /* + * size must match sector size in bytes + * For DATA SET MANAGEMENT TRIM in ACS-2 nsect (aka count) + * is defined as number of 512 byte blocks to be transferred. + */ if (unmap) { size = ata_format_dsm_trim_descr(scmd, trmax, block, n_block); + if (size != len) + goto invalid_param_len; + if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) { /* Newer devices support queued TRIM commands */ tf->protocol = ATA_PROT_NCQ; @@ -3441,7 +3468,9 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) tf->command = ATA_CMD_DSM; } } else { - ata_format_sct_write_same(scmd, block, n_block); + size = ata_format_sct_write_same(scmd, block, n_block); + if (size != len) + goto invalid_param_len; tf->hob_feature = 0; tf->feature = 0; -- GitLab From 7d36dd00ab8d57134cce86ad4febc2f5bbdf3e72 Mon Sep 17 00:00:00 2001 From: Shaun Tancheff Date: Sun, 21 Aug 2016 23:23:21 -0500 Subject: [PATCH 0037/1167] libata: SCT Write Same handle ATA_DFLAG_PIO Use non DMA write log when ATA_DFLAG_PIO is set. Signed-off-by: Shaun Tancheff Reviewed-by: Hannes Reinecke Acked-by: Tejun Heo --- drivers/ata/libata-scsi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 35b1f9e475cc4..2f5487f02de14 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3485,6 +3485,8 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) tf->device = ATA_CMD_STANDBYNOW1; tf->protocol = ATA_PROT_DMA; tf->command = ATA_CMD_WRITE_LOG_DMA_EXT; + if (unlikely(dev->flags & ATA_DFLAG_PIO)) + tf->command = ATA_CMD_WRITE_LOG_EXT; } tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | -- GitLab From 4fab91605a6bcd0c303bcbc292a8bffcf27b3a27 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 25 Aug 2016 19:53:08 +1000 Subject: [PATCH 0038/1167] kbuild: genksyms fix for typeof handling The tokenizer misses counting an open-parenthesis when parsing a non-trivial typeof beginning with an open-parenthesis. This function in include/linux/ceph/libceph.h static type *lookup_##name(struct rb_root *root, typeof(((type *)0)->keyfld) key) When instantiated in net/ceph/mon_client.c, causes subsequent symbols including an EXPORT_SYMBOL in that file to be lost. Signed-off-by: Nicholas Piggin Signed-off-by: Michal Marek --- scripts/genksyms/lex.l | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/scripts/genksyms/lex.l b/scripts/genksyms/lex.l index e583565f2011d..5235aa507ba53 100644 --- a/scripts/genksyms/lex.l +++ b/scripts/genksyms/lex.l @@ -289,6 +289,23 @@ repeat: } break; + case ST_TYPEOF_1: + if (token == IDENT) + { + if (is_reserved_word(yytext, yyleng) + || find_symbol(yytext, SYM_TYPEDEF, 1)) + { + yyless(0); + unput('('); + lexstate = ST_NORMAL; + token = TYPEOF_KEYW; + break; + } + _APP("(", 1); + } + lexstate = ST_TYPEOF; + /* FALLTHRU */ + case ST_TYPEOF: switch (token) { @@ -313,24 +330,6 @@ repeat: } break; - case ST_TYPEOF_1: - if (token == IDENT) - { - if (is_reserved_word(yytext, yyleng) - || find_symbol(yytext, SYM_TYPEDEF, 1)) - { - yyless(0); - unput('('); - lexstate = ST_NORMAL; - token = TYPEOF_KEYW; - break; - } - _APP("(", 1); - } - APP; - lexstate = ST_TYPEOF; - goto repeat; - case ST_BRACKET: APP; switch (token) -- GitLab From 5c6f3225d00d06b2ca91c74644a7bfcfe826a935 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Thu, 25 Aug 2016 20:03:51 +0200 Subject: [PATCH 0039/1167] kbuild: Regenerate genksyms lexer Update the lexer after 4fab91605a6b ("kbuild: genksyms fix for typeof handling"). Signed-off-by: Michal Marek --- scripts/genksyms/lex.lex.c_shipped | 35 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/scripts/genksyms/lex.lex.c_shipped b/scripts/genksyms/lex.lex.c_shipped index f82740a69b850..985c5541aae41 100644 --- a/scripts/genksyms/lex.lex.c_shipped +++ b/scripts/genksyms/lex.lex.c_shipped @@ -2098,6 +2098,23 @@ repeat: } break; + case ST_TYPEOF_1: + if (token == IDENT) + { + if (is_reserved_word(yytext, yyleng) + || find_symbol(yytext, SYM_TYPEDEF, 1)) + { + yyless(0); + unput('('); + lexstate = ST_NORMAL; + token = TYPEOF_KEYW; + break; + } + _APP("(", 1); + } + lexstate = ST_TYPEOF; + /* FALLTHRU */ + case ST_TYPEOF: switch (token) { @@ -2122,24 +2139,6 @@ repeat: } break; - case ST_TYPEOF_1: - if (token == IDENT) - { - if (is_reserved_word(yytext, yyleng) - || find_symbol(yytext, SYM_TYPEDEF, 1)) - { - yyless(0); - unput('('); - lexstate = ST_NORMAL; - token = TYPEOF_KEYW; - break; - } - _APP("(", 1); - } - APP; - lexstate = ST_TYPEOF; - goto repeat; - case ST_BRACKET: APP; switch (token) -- GitLab From 83ab7dad06b74e390c2ce0e7b5136daf286e1f5e Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 9 Aug 2016 13:58:27 +0200 Subject: [PATCH 0040/1167] rtc: pcf2123: Add missing error code assignment before test It is likely that checking the result of 'pcf2123_write_reg' is expected here. Also fix a small style issue. The '{' at the beginning of the function is misplaced. Fixes: 809b453b76e15 ("rtc: pcf2123: clean up writes to the rtc chip") Signed-off-by: Christophe JAILLET Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2123.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index b4478cc92b55d..8895f77726e8d 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -182,7 +182,8 @@ static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, } static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, - const char *buffer, size_t count) { + const char *buffer, size_t count) +{ struct pcf2123_sysfs_reg *r; unsigned long reg; unsigned long val; @@ -199,7 +200,7 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, if (ret) return ret; - pcf2123_write_reg(dev, reg, val); + ret = pcf2123_write_reg(dev, reg, val); if (ret < 0) return -EIO; return count; -- GitLab From 59e5e70c9516a0ba34dd5a1a44ed89518cd5eda9 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 3 Aug 2016 00:48:22 -0300 Subject: [PATCH 0041/1167] rtc: ds1390: Fix the SPI chip select number The number after the '@' symbol should be the SPI chip select number associated with the ds1390 and it should match the 'reg' field. So change it the address to zero, to make it consistent. Signed-off-by: Fabio Estevam Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/dallas,ds1390.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/rtc/dallas,ds1390.txt b/Documentation/devicetree/bindings/rtc/dallas,ds1390.txt index 8e76f26487966..9882b819f173f 100644 --- a/Documentation/devicetree/bindings/rtc/dallas,ds1390.txt +++ b/Documentation/devicetree/bindings/rtc/dallas,ds1390.txt @@ -11,7 +11,7 @@ Optional properties: - trickle-diode-disable : Do not use internal trickle charger diode Should be given if internal trickle charger diode should be disabled Example: - ds1390: rtc@68 { + ds1390: rtc@0 { compatible = "dallas,ds1390"; trickle-resistor-ohms = <250>; reg = <0>; -- GitLab From 50d6c0ea8111100a102c03b4410ba1e45fa8b771 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 13 Jul 2016 02:26:08 +0200 Subject: [PATCH 0042/1167] rtc: ds1307: fix century bit support Add an option to properly support the century bit of ds1337 and compatibles and ds1340. Because the driver had a bug until now, it is not possible to switch users to the fixed code directly as RTCs in the field will wrongly have the century bit set. Acked-by: Arnaud Ebalard Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 14 ++++++++++++ drivers/rtc/rtc-ds1307.c | 48 +++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 7fc11cdfd27ef..6ce3dad732533 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -234,6 +234,20 @@ config RTC_DRV_DS1307_HWMON Say Y here if you want to expose temperature sensor data on rtc-ds1307 (only DS3231) +config RTC_DRV_DS1307_CENTURY + bool "Century bit support for rtc-ds1307" + depends on RTC_DRV_DS1307 + default n + help + The DS1307 driver suffered from a bug where it was enabling the + century bit inconditionnally but never used it when reading the time. + It made the driver unable to support dates beyond 2099. + Setting this option will add proper support for the century bit but if + the time was previously set using a kernel predating this option, + reading the date will return a date in the next century. + To solve that, you could boot a kernel without this option set, set + the RTC date and then boot a kernel with this option set. + config RTC_DRV_DS1374 tristate "Dallas/Maxim DS1374" help diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 8e1c5cb6ece6f..712e221d2415f 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -382,10 +382,25 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) t->tm_mday = bcd2bin(ds1307->regs[DS1307_REG_MDAY] & 0x3f); tmp = ds1307->regs[DS1307_REG_MONTH] & 0x1f; t->tm_mon = bcd2bin(tmp) - 1; - - /* assume 20YY not 19YY, and ignore DS1337_BIT_CENTURY */ t->tm_year = bcd2bin(ds1307->regs[DS1307_REG_YEAR]) + 100; +#ifdef CONFIG_RTC_DRV_DS1307_CENTURY + switch (ds1307->type) { + case ds_1337: + case ds_1339: + case ds_3231: + if (ds1307->regs[DS1307_REG_MONTH] & DS1337_BIT_CENTURY) + t->tm_year += 100; + break; + case ds_1340: + if (ds1307->regs[DS1307_REG_HOUR] & DS1340_BIT_CENTURY) + t->tm_year += 100; + break; + default: + break; + } +#endif + dev_dbg(dev, "%s secs=%d, mins=%d, " "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", "read", t->tm_sec, t->tm_min, @@ -409,6 +424,27 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) t->tm_hour, t->tm_mday, t->tm_mon, t->tm_year, t->tm_wday); +#ifdef CONFIG_RTC_DRV_DS1307_CENTURY + if (t->tm_year < 100) + return -EINVAL; + + switch (ds1307->type) { + case ds_1337: + case ds_1339: + case ds_3231: + case ds_1340: + if (t->tm_year > 299) + return -EINVAL; + default: + if (t->tm_year > 199) + return -EINVAL; + break; + } +#else + if (t->tm_year < 100 || t->tm_year > 199) + return -EINVAL; +#endif + buf[DS1307_REG_SECS] = bin2bcd(t->tm_sec); buf[DS1307_REG_MIN] = bin2bcd(t->tm_min); buf[DS1307_REG_HOUR] = bin2bcd(t->tm_hour); @@ -424,11 +460,13 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) case ds_1337: case ds_1339: case ds_3231: - buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY; + if (t->tm_year > 199) + buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY; break; case ds_1340: - buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN - | DS1340_BIT_CENTURY; + buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN; + if (t->tm_year > 199) + buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY; break; case mcp794xx: /* -- GitLab From 78aaa06d7956dc4cd42fff5033f4bf6fafcbc79f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 13 Jul 2016 02:36:41 +0200 Subject: [PATCH 0043/1167] rtc: ds1307: add Intersil ISL12057 support Intersil ISL12057 is a drop-in replacement for DS1337. It can be supported by the ds1307 driver. Acked-by: Arnaud Ebalard Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 8 ++++---- drivers/rtc/rtc-ds1307.c | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6ce3dad732533..83a788416721a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -208,14 +208,14 @@ config RTC_DRV_AS3722 will be called rtc-as3722. config RTC_DRV_DS1307 - tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025" + tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025, ISL12057" help If you say yes here you get support for various compatible RTC chips (often with battery backup) connected with I2C. This driver should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00, - EPSON RX-8025 and probably other chips. In some cases the RTC - must already have been initialized (by manufacturing or a - bootloader). + EPSON RX-8025, Intersil ISL12057 and probably other chips. In some + cases the RTC must already have been initialized (by manufacturing or + a bootloader). The first seven registers on these chips hold an RTC, and other registers may add features such as NVRAM, a trickle charger for diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 712e221d2415f..4e31036ee2596 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -186,6 +186,7 @@ static const struct i2c_device_id ds1307_id[] = { { "mcp7941x", mcp794xx }, { "pt7c4338", ds_1307 }, { "rx8025", rx_8025 }, + { "isl12057", ds_1337 }, { } }; MODULE_DEVICE_TABLE(i2c, ds1307_id); @@ -1333,6 +1334,11 @@ static int ds1307_probe(struct i2c_client *client, if (of_property_read_bool(client->dev.of_node, "wakeup-source")) { ds1307_can_wakeup_device = true; } + /* Intersil ISL12057 DT backward compatibility */ + if (of_property_read_bool(client->dev.of_node, + "isil,irq2-can-wakeup-machine")) { + ds1307_can_wakeup_device = true; + } #endif switch (ds1307->type) { -- GitLab From e8aa7dcbf0b1fdd79127b125d2369bca7bdb5b03 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 13 Jul 2016 02:39:54 +0200 Subject: [PATCH 0044/1167] rtc: isl12057: remove driver The Intersil isl12057 is now supported by the ds1307 driver. Acked-by: Arnaud Ebalard Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 10 - drivers/rtc/Makefile | 1 - drivers/rtc/rtc-isl12057.c | 643 ------------------------------------- 3 files changed, 654 deletions(-) delete mode 100644 drivers/rtc/rtc-isl12057.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 83a788416721a..23acc3f536b35 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -388,16 +388,6 @@ config RTC_DRV_ISL12022 This driver can also be built as a module. If so, the module will be called rtc-isl12022. -config RTC_DRV_ISL12057 - select REGMAP_I2C - tristate "Intersil ISL12057" - help - If you say yes here you get support for the Intersil ISL12057 - I2C RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-isl12057. - config RTC_DRV_X1205 tristate "Xicor/Intersil X1205" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 8fb994bacdf7f..1ac694a330c8d 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -72,7 +72,6 @@ obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o -obj-$(CONFIG_RTC_DRV_ISL12057) += rtc-isl12057.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c deleted file mode 100644 index 0e7f0f52bfe4e..0000000000000 --- a/drivers/rtc/rtc-isl12057.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * rtc-isl12057 - Driver for Intersil ISL12057 I2C Real Time Clock - * - * Copyright (C) 2013, Arnaud EBALARD - * - * This work is largely based on Intersil ISL1208 driver developed by - * Hebert Valerio Riedel . - * - * Detailed datasheet on which this development is based is available here: - * - * http://natisbad.org/NAS2/refs/ISL12057.pdf - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "rtc-isl12057" - -/* RTC section */ -#define ISL12057_REG_RTC_SC 0x00 /* Seconds */ -#define ISL12057_REG_RTC_MN 0x01 /* Minutes */ -#define ISL12057_REG_RTC_HR 0x02 /* Hours */ -#define ISL12057_REG_RTC_HR_PM BIT(5) /* AM/PM bit in 12h format */ -#define ISL12057_REG_RTC_HR_MIL BIT(6) /* 24h/12h format */ -#define ISL12057_REG_RTC_DW 0x03 /* Day of the Week */ -#define ISL12057_REG_RTC_DT 0x04 /* Date */ -#define ISL12057_REG_RTC_MO 0x05 /* Month */ -#define ISL12057_REG_RTC_MO_CEN BIT(7) /* Century bit */ -#define ISL12057_REG_RTC_YR 0x06 /* Year */ -#define ISL12057_RTC_SEC_LEN 7 - -/* Alarm 1 section */ -#define ISL12057_REG_A1_SC 0x07 /* Alarm 1 Seconds */ -#define ISL12057_REG_A1_MN 0x08 /* Alarm 1 Minutes */ -#define ISL12057_REG_A1_HR 0x09 /* Alarm 1 Hours */ -#define ISL12057_REG_A1_HR_PM BIT(5) /* AM/PM bit in 12h format */ -#define ISL12057_REG_A1_HR_MIL BIT(6) /* 24h/12h format */ -#define ISL12057_REG_A1_DWDT 0x0A /* Alarm 1 Date / Day of the week */ -#define ISL12057_REG_A1_DWDT_B BIT(6) /* DW / DT selection bit */ -#define ISL12057_A1_SEC_LEN 4 - -/* Alarm 2 section */ -#define ISL12057_REG_A2_MN 0x0B /* Alarm 2 Minutes */ -#define ISL12057_REG_A2_HR 0x0C /* Alarm 2 Hours */ -#define ISL12057_REG_A2_DWDT 0x0D /* Alarm 2 Date / Day of the week */ -#define ISL12057_A2_SEC_LEN 3 - -/* Control/Status registers */ -#define ISL12057_REG_INT 0x0E -#define ISL12057_REG_INT_A1IE BIT(0) /* Alarm 1 interrupt enable bit */ -#define ISL12057_REG_INT_A2IE BIT(1) /* Alarm 2 interrupt enable bit */ -#define ISL12057_REG_INT_INTCN BIT(2) /* Interrupt control enable bit */ -#define ISL12057_REG_INT_RS1 BIT(3) /* Freq out control bit 1 */ -#define ISL12057_REG_INT_RS2 BIT(4) /* Freq out control bit 2 */ -#define ISL12057_REG_INT_EOSC BIT(7) /* Oscillator enable bit */ - -#define ISL12057_REG_SR 0x0F -#define ISL12057_REG_SR_A1F BIT(0) /* Alarm 1 interrupt bit */ -#define ISL12057_REG_SR_A2F BIT(1) /* Alarm 2 interrupt bit */ -#define ISL12057_REG_SR_OSF BIT(7) /* Oscillator failure bit */ - -/* Register memory map length */ -#define ISL12057_MEM_MAP_LEN 0x10 - -struct isl12057_rtc_data { - struct rtc_device *rtc; - struct regmap *regmap; - struct mutex lock; - int irq; -}; - -static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs) -{ - tm->tm_sec = bcd2bin(regs[ISL12057_REG_RTC_SC]); - tm->tm_min = bcd2bin(regs[ISL12057_REG_RTC_MN]); - - if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_MIL) { /* AM/PM */ - tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x1f); - if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_PM) - tm->tm_hour += 12; - } else { /* 24 hour mode */ - tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x3f); - } - - tm->tm_mday = bcd2bin(regs[ISL12057_REG_RTC_DT]); - tm->tm_wday = bcd2bin(regs[ISL12057_REG_RTC_DW]) - 1; /* starts at 1 */ - tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO] & 0x1f) - 1; /* ditto */ - tm->tm_year = bcd2bin(regs[ISL12057_REG_RTC_YR]) + 100; - - /* Check if years register has overflown from 99 to 00 */ - if (regs[ISL12057_REG_RTC_MO] & ISL12057_REG_RTC_MO_CEN) - tm->tm_year += 100; -} - -static int isl12057_rtc_tm_to_regs(u8 *regs, struct rtc_time *tm) -{ - u8 century_bit; - - /* - * The clock has an 8 bit wide bcd-coded register for the year. - * It also has a century bit encoded in MO flag which provides - * information about overflow of year register from 99 to 00. - * tm_year is an offset from 1900 and we are interested in the - * 2000-2199 range, so any value less than 100 or larger than - * 299 is invalid. - */ - if (tm->tm_year < 100 || tm->tm_year > 299) - return -EINVAL; - - century_bit = (tm->tm_year > 199) ? ISL12057_REG_RTC_MO_CEN : 0; - - regs[ISL12057_REG_RTC_SC] = bin2bcd(tm->tm_sec); - regs[ISL12057_REG_RTC_MN] = bin2bcd(tm->tm_min); - regs[ISL12057_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */ - regs[ISL12057_REG_RTC_DT] = bin2bcd(tm->tm_mday); - regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1) | century_bit; - regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year % 100); - regs[ISL12057_REG_RTC_DW] = bin2bcd(tm->tm_wday + 1); - - return 0; -} - -/* - * Try and match register bits w/ fixed null values to see whether we - * are dealing with an ISL12057. Note: this function is called early - * during init and hence does need mutex protection. - */ -static int isl12057_i2c_validate_chip(struct regmap *regmap) -{ - u8 regs[ISL12057_MEM_MAP_LEN]; - static const u8 mask[ISL12057_MEM_MAP_LEN] = { 0x80, 0x80, 0x80, 0xf8, - 0xc0, 0x60, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x60, 0x7c }; - int ret, i; - - ret = regmap_bulk_read(regmap, 0, regs, ISL12057_MEM_MAP_LEN); - if (ret) - return ret; - - for (i = 0; i < ISL12057_MEM_MAP_LEN; ++i) { - if (regs[i] & mask[i]) /* check if bits are cleared */ - return -ENODEV; - } - - return 0; -} - -static int _isl12057_rtc_clear_alarm(struct device *dev) -{ - struct isl12057_rtc_data *data = dev_get_drvdata(dev); - int ret; - - ret = regmap_update_bits(data->regmap, ISL12057_REG_SR, - ISL12057_REG_SR_A1F, 0); - if (ret) - dev_err(dev, "%s: clearing alarm failed (%d)\n", __func__, ret); - - return ret; -} - -static int _isl12057_rtc_update_alarm(struct device *dev, int enable) -{ - struct isl12057_rtc_data *data = dev_get_drvdata(dev); - int ret; - - ret = regmap_update_bits(data->regmap, ISL12057_REG_INT, - ISL12057_REG_INT_A1IE, - enable ? ISL12057_REG_INT_A1IE : 0); - if (ret) - dev_err(dev, "%s: changing alarm interrupt flag failed (%d)\n", - __func__, ret); - - return ret; -} - -/* - * Note: as we only read from device and do not perform any update, there is - * no need for an equivalent function which would try and get driver's main - * lock. Here, it is safe for everyone if we just use regmap internal lock - * on the device when reading. - */ -static int _isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - struct isl12057_rtc_data *data = dev_get_drvdata(dev); - u8 regs[ISL12057_RTC_SEC_LEN]; - unsigned int sr; - int ret; - - ret = regmap_read(data->regmap, ISL12057_REG_SR, &sr); - if (ret) { - dev_err(dev, "%s: unable to read oscillator status flag (%d)\n", - __func__, ret); - goto out; - } else { - if (sr & ISL12057_REG_SR_OSF) { - ret = -ENODATA; - goto out; - } - } - - ret = regmap_bulk_read(data->regmap, ISL12057_REG_RTC_SC, regs, - ISL12057_RTC_SEC_LEN); - if (ret) - dev_err(dev, "%s: unable to read RTC time section (%d)\n", - __func__, ret); - -out: - if (ret) - return ret; - - isl12057_rtc_regs_to_tm(tm, regs); - - return rtc_valid_tm(tm); -} - -static int isl12057_rtc_update_alarm(struct device *dev, int enable) -{ - struct isl12057_rtc_data *data = dev_get_drvdata(dev); - int ret; - - mutex_lock(&data->lock); - ret = _isl12057_rtc_update_alarm(dev, enable); - mutex_unlock(&data->lock); - - return ret; -} - -static int isl12057_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) -{ - struct isl12057_rtc_data *data = dev_get_drvdata(dev); - struct rtc_time *alarm_tm = &alarm->time; - u8 regs[ISL12057_A1_SEC_LEN]; - unsigned int ir; - int ret; - - mutex_lock(&data->lock); - ret = regmap_bulk_read(data->regmap, ISL12057_REG_A1_SC, regs, - ISL12057_A1_SEC_LEN); - if (ret) { - dev_err(dev, "%s: reading alarm section failed (%d)\n", - __func__, ret); - goto err_unlock; - } - - alarm_tm->tm_sec = bcd2bin(regs[0] & 0x7f); - alarm_tm->tm_min = bcd2bin(regs[1] & 0x7f); - alarm_tm->tm_hour = bcd2bin(regs[2] & 0x3f); - alarm_tm->tm_mday = bcd2bin(regs[3] & 0x3f); - - ret = regmap_read(data->regmap, ISL12057_REG_INT, &ir); - if (ret) { - dev_err(dev, "%s: reading alarm interrupt flag failed (%d)\n", - __func__, ret); - goto err_unlock; - } - - alarm->enabled = !!(ir & ISL12057_REG_INT_A1IE); - -err_unlock: - mutex_unlock(&data->lock); - - return ret; -} - -static int isl12057_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) -{ - struct isl12057_rtc_data *data = dev_get_drvdata(dev); - struct rtc_time *alarm_tm = &alarm->time; - unsigned long rtc_secs, alarm_secs; - u8 regs[ISL12057_A1_SEC_LEN]; - struct rtc_time rtc_tm; - int ret, enable = 1; - - mutex_lock(&data->lock); - ret = _isl12057_rtc_read_time(dev, &rtc_tm); - if (ret) - goto err_unlock; - - ret = rtc_tm_to_time(&rtc_tm, &rtc_secs); - if (ret) - goto err_unlock; - - ret = rtc_tm_to_time(alarm_tm, &alarm_secs); - if (ret) - goto err_unlock; - - /* If alarm time is before current time, disable the alarm */ - if (!alarm->enabled || alarm_secs <= rtc_secs) { - enable = 0; - } else { - /* - * Chip only support alarms up to one month in the future. Let's - * return an error if we get something after that limit. - * Comparison is done by incrementing rtc_tm month field by one - * and checking alarm value is still below. - */ - if (rtc_tm.tm_mon == 11) { /* handle year wrapping */ - rtc_tm.tm_mon = 0; - rtc_tm.tm_year += 1; - } else { - rtc_tm.tm_mon += 1; - } - - ret = rtc_tm_to_time(&rtc_tm, &rtc_secs); - if (ret) - goto err_unlock; - - if (alarm_secs > rtc_secs) { - dev_err(dev, "%s: max for alarm is one month (%d)\n", - __func__, ret); - ret = -EINVAL; - goto err_unlock; - } - } - - /* Disable the alarm before modifying it */ - ret = _isl12057_rtc_update_alarm(dev, 0); - if (ret < 0) { - dev_err(dev, "%s: unable to disable the alarm (%d)\n", - __func__, ret); - goto err_unlock; - } - - /* Program alarm registers */ - regs[0] = bin2bcd(alarm_tm->tm_sec) & 0x7f; - regs[1] = bin2bcd(alarm_tm->tm_min) & 0x7f; - regs[2] = bin2bcd(alarm_tm->tm_hour) & 0x3f; - regs[3] = bin2bcd(alarm_tm->tm_mday) & 0x3f; - - ret = regmap_bulk_write(data->regmap, ISL12057_REG_A1_SC, regs, - ISL12057_A1_SEC_LEN); - if (ret < 0) { - dev_err(dev, "%s: writing alarm section failed (%d)\n", - __func__, ret); - goto err_unlock; - } - - /* Enable or disable alarm */ - ret = _isl12057_rtc_update_alarm(dev, enable); - -err_unlock: - mutex_unlock(&data->lock); - - return ret; -} - -static int isl12057_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - struct isl12057_rtc_data *data = dev_get_drvdata(dev); - u8 regs[ISL12057_RTC_SEC_LEN]; - int ret; - - ret = isl12057_rtc_tm_to_regs(regs, tm); - if (ret) - return ret; - - mutex_lock(&data->lock); - ret = regmap_bulk_write(data->regmap, ISL12057_REG_RTC_SC, regs, - ISL12057_RTC_SEC_LEN); - if (ret) { - dev_err(dev, "%s: unable to write RTC time section (%d)\n", - __func__, ret); - goto out; - } - - /* - * Now that RTC time has been updated, let's clear oscillator - * failure flag, if needed. - */ - ret = regmap_update_bits(data->regmap, ISL12057_REG_SR, - ISL12057_REG_SR_OSF, 0); - if (ret < 0) - dev_err(dev, "%s: unable to clear osc. failure bit (%d)\n", - __func__, ret); - -out: - mutex_unlock(&data->lock); - - return ret; -} - -/* - * Check current RTC status and enable/disable what needs to be. Return 0 if - * everything went ok and a negative value upon error. Note: this function - * is called early during init and hence does need mutex protection. - */ -static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap) -{ - int ret; - - /* Enable oscillator if not already running */ - ret = regmap_update_bits(regmap, ISL12057_REG_INT, - ISL12057_REG_INT_EOSC, 0); - if (ret < 0) { - dev_err(dev, "%s: unable to enable oscillator (%d)\n", - __func__, ret); - return ret; - } - - /* Clear alarm bit if needed */ - ret = regmap_update_bits(regmap, ISL12057_REG_SR, - ISL12057_REG_SR_A1F, 0); - if (ret < 0) { - dev_err(dev, "%s: unable to clear alarm bit (%d)\n", - __func__, ret); - return ret; - } - - return 0; -} - -#ifdef CONFIG_OF -/* - * One would expect the device to be marked as a wakeup source only - * when an IRQ pin of the RTC is routed to an interrupt line of the - * CPU. In practice, such an IRQ pin can be connected to a PMIC and - * this allows the device to be powered up when RTC alarm rings. This - * is for instance the case on ReadyNAS 102, 104 and 2120. On those - * devices with no IRQ driectly connected to the SoC, the RTC chip - * can be forced as a wakeup source by stating that explicitly in - * the device's .dts file using the "wakeup-source" boolean property. - * This will guarantee 'wakealarm' sysfs entry is available on the device. - * - * The function below returns 1, i.e. the capability of the chip to - * wakeup the device, based on IRQ availability or if the boolean - * property has been set in the .dts file. Otherwise, it returns 0. - */ - -static bool isl12057_can_wakeup_machine(struct device *dev) -{ - struct isl12057_rtc_data *data = dev_get_drvdata(dev); - - return data->irq || of_property_read_bool(dev->of_node, "wakeup-source") - || of_property_read_bool(dev->of_node, /* legacy */ - "isil,irq2-can-wakeup-machine"); -} -#else -static bool isl12057_can_wakeup_machine(struct device *dev) -{ - struct isl12057_rtc_data *data = dev_get_drvdata(dev); - - return !!data->irq; -} -#endif - -static int isl12057_rtc_alarm_irq_enable(struct device *dev, - unsigned int enable) -{ - struct isl12057_rtc_data *rtc_data = dev_get_drvdata(dev); - int ret = -ENOTTY; - - if (rtc_data->irq) - ret = isl12057_rtc_update_alarm(dev, enable); - - return ret; -} - -static irqreturn_t isl12057_rtc_interrupt(int irq, void *data) -{ - struct i2c_client *client = data; - struct isl12057_rtc_data *rtc_data = dev_get_drvdata(&client->dev); - struct rtc_device *rtc = rtc_data->rtc; - int ret, handled = IRQ_NONE; - unsigned int sr; - - ret = regmap_read(rtc_data->regmap, ISL12057_REG_SR, &sr); - if (!ret && (sr & ISL12057_REG_SR_A1F)) { - dev_dbg(&client->dev, "RTC alarm!\n"); - - rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); - - /* Acknowledge and disable the alarm */ - _isl12057_rtc_clear_alarm(&client->dev); - _isl12057_rtc_update_alarm(&client->dev, 0); - - handled = IRQ_HANDLED; - } - - return handled; -} - -static const struct rtc_class_ops rtc_ops = { - .read_time = _isl12057_rtc_read_time, - .set_time = isl12057_rtc_set_time, - .read_alarm = isl12057_rtc_read_alarm, - .set_alarm = isl12057_rtc_set_alarm, - .alarm_irq_enable = isl12057_rtc_alarm_irq_enable, -}; - -static const struct regmap_config isl12057_rtc_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - -static int isl12057_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct device *dev = &client->dev; - struct isl12057_rtc_data *data; - struct regmap *regmap; - int ret; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) - return -ENODEV; - - regmap = devm_regmap_init_i2c(client, &isl12057_rtc_regmap_config); - if (IS_ERR(regmap)) { - ret = PTR_ERR(regmap); - dev_err(dev, "%s: regmap allocation failed (%d)\n", - __func__, ret); - return ret; - } - - ret = isl12057_i2c_validate_chip(regmap); - if (ret) - return ret; - - ret = isl12057_check_rtc_status(dev, regmap); - if (ret) - return ret; - - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - mutex_init(&data->lock); - data->regmap = regmap; - dev_set_drvdata(dev, data); - - if (client->irq > 0) { - ret = devm_request_threaded_irq(dev, client->irq, NULL, - isl12057_rtc_interrupt, - IRQF_SHARED|IRQF_ONESHOT, - DRV_NAME, client); - if (!ret) - data->irq = client->irq; - else - dev_err(dev, "%s: irq %d unavailable (%d)\n", __func__, - client->irq, ret); - } - - if (isl12057_can_wakeup_machine(dev)) - device_init_wakeup(dev, true); - - data->rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops, - THIS_MODULE); - ret = PTR_ERR_OR_ZERO(data->rtc); - if (ret) { - dev_err(dev, "%s: unable to register RTC device (%d)\n", - __func__, ret); - goto err; - } - - /* We cannot support UIE mode if we do not have an IRQ line */ - if (!data->irq) - data->rtc->uie_unsupported = 1; - -err: - return ret; -} - -static int isl12057_remove(struct i2c_client *client) -{ - if (isl12057_can_wakeup_machine(&client->dev)) - device_init_wakeup(&client->dev, false); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int isl12057_rtc_suspend(struct device *dev) -{ - struct isl12057_rtc_data *rtc_data = dev_get_drvdata(dev); - - if (rtc_data->irq && device_may_wakeup(dev)) - return enable_irq_wake(rtc_data->irq); - - return 0; -} - -static int isl12057_rtc_resume(struct device *dev) -{ - struct isl12057_rtc_data *rtc_data = dev_get_drvdata(dev); - - if (rtc_data->irq && device_may_wakeup(dev)) - return disable_irq_wake(rtc_data->irq); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(isl12057_rtc_pm_ops, isl12057_rtc_suspend, - isl12057_rtc_resume); - -#ifdef CONFIG_OF -static const struct of_device_id isl12057_dt_match[] = { - { .compatible = "isl,isl12057" }, /* for backward compat., don't use */ - { .compatible = "isil,isl12057" }, - { }, -}; -MODULE_DEVICE_TABLE(of, isl12057_dt_match); -#endif - -static const struct i2c_device_id isl12057_id[] = { - { "isl12057", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, isl12057_id); - -static struct i2c_driver isl12057_driver = { - .driver = { - .name = DRV_NAME, - .pm = &isl12057_rtc_pm_ops, - .of_match_table = of_match_ptr(isl12057_dt_match), - }, - .probe = isl12057_probe, - .remove = isl12057_remove, - .id_table = isl12057_id, -}; -module_i2c_driver(isl12057_driver); - -MODULE_AUTHOR("Arnaud EBALARD "); -MODULE_DESCRIPTION("Intersil ISL12057 RTC driver"); -MODULE_LICENSE("GPL"); -- GitLab From bbeb9787d9a258bc55dfd40bb37e2a87962bbe8b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 13 Jul 2016 02:48:59 +0200 Subject: [PATCH 0045/1167] Documentation: dt: Intersil isl12057 is not a trivial device The ISL12057 has a documentation file, remove it from trivial-devices.txt Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/i2c/trivial-devices.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 5c70ce9c19544..43af4765d5fed 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -50,7 +50,6 @@ fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz) infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz) -isil,isl12057 Intersil ISL12057 I2C RTC Chip isil,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs -- GitLab From 84281c2d72a70456a3ba8d1e49548dd469f2e9d8 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Fri, 12 Aug 2016 14:46:14 +0200 Subject: [PATCH 0046/1167] rtc: sysfs: fix a cast removing the const attribute The char pointer buf_ptr is assigned an address from a const char pointer buf (parameter of wakealarm_store). The data pointer by buf_ptr is never modified. So casting it to a (char *) is useless. This patch remove this cast, and transform buf_ptr to a const char pointer. Signed-off-by: LABBE Corentin Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 63b9fb1318c2a..1218d5d4224dd 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -160,7 +160,7 @@ wakealarm_store(struct device *dev, struct device_attribute *attr, unsigned long push = 0; struct rtc_wkalrm alm; struct rtc_device *rtc = to_rtc_device(dev); - char *buf_ptr; + const char *buf_ptr; int adjust = 0; /* Only request alarms that trigger in the future. Disable them @@ -171,7 +171,7 @@ wakealarm_store(struct device *dev, struct device_attribute *attr, return retval; rtc_tm_to_time(&alm.time, &now); - buf_ptr = (char *)buf; + buf_ptr = buf; if (*buf_ptr == '+') { buf_ptr++; if (*buf_ptr == '=') { -- GitLab From 6ed1a51e0b8a981ab0540117f0c47c1f11fca5fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C3=96stlund?= Date: Thu, 11 Aug 2016 13:31:43 +0200 Subject: [PATCH 0047/1167] rtc: bq32k: Use correct mask name for 'minutes' register. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BQ32K_SECONDS_MASK and BQ32K_MINUTES_MASK both has the same value. This is no functional change. Signed-off-by: Jan Östlund Signed-off-by: Daniel Romell Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-bq32k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index 0299988b4f136..5a0c13761023d 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c @@ -94,7 +94,7 @@ static int bq32k_rtc_read_time(struct device *dev, struct rtc_time *tm) return error; tm->tm_sec = bcd2bin(regs.seconds & BQ32K_SECONDS_MASK); - tm->tm_min = bcd2bin(regs.minutes & BQ32K_SECONDS_MASK); + tm->tm_min = bcd2bin(regs.minutes & BQ32K_MINUTES_MASK); tm->tm_hour = bcd2bin(regs.cent_hours & BQ32K_HOURS_MASK); tm->tm_mday = bcd2bin(regs.date); tm->tm_wday = bcd2bin(regs.day) - 1; -- GitLab From 421a5ba24b3ef23b8972a6c238bd300abef532da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C3=96stlund?= Date: Thu, 11 Aug 2016 13:31:44 +0200 Subject: [PATCH 0048/1167] rtc: bq32k: Fix handling of oscillator failure flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the oscillator failure flag is set, the RTC registers should be considered invalid. bq32k_rtc_read_time() now returns an error instead of an invalid time. The failure flag is cleared the next time the clock is set. Signed-off-by: Jan Östlund Signed-off-by: Daniel Romell Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-bq32k.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index 5a0c13761023d..397742446007a 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c @@ -93,6 +93,13 @@ static int bq32k_rtc_read_time(struct device *dev, struct rtc_time *tm) if (error) return error; + /* + * In case of oscillator failure, the register contents should be + * considered invalid. The flag is cleared the next time the RTC is set. + */ + if (regs.minutes & BQ32K_OF) + return -EINVAL; + tm->tm_sec = bcd2bin(regs.seconds & BQ32K_SECONDS_MASK); tm->tm_min = bcd2bin(regs.minutes & BQ32K_MINUTES_MASK); tm->tm_hour = bcd2bin(regs.cent_hours & BQ32K_HOURS_MASK); @@ -204,13 +211,10 @@ static int bq32k_probe(struct i2c_client *client, /* Check Oscillator Failure flag */ error = bq32k_read(dev, ®, BQ32K_MINUTES, 1); - if (!error && (reg & BQ32K_OF)) { - dev_warn(dev, "Oscillator Failure. Check RTC battery.\n"); - reg &= ~BQ32K_OF; - error = bq32k_write(dev, ®, BQ32K_MINUTES, 1); - } if (error) return error; + if (reg & BQ32K_OF) + dev_warn(dev, "Oscillator Failure. Check RTC battery.\n"); if (client->dev.of_node) trickle_charger_of_init(dev, client->dev.of_node); -- GitLab From e545b984f0225244505b5e0605070bfc6099f475 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 15 Aug 2016 10:52:47 +0200 Subject: [PATCH 0049/1167] rtc: pic32: Delete owner assignment The field "owner" is set by core. Thus delete an extra initialisation. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Markus Elfring Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pic32.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c index 64e1e4578492a..5cfb6df5c4303 100644 --- a/drivers/rtc/rtc-pic32.c +++ b/drivers/rtc/rtc-pic32.c @@ -400,7 +400,6 @@ static struct platform_driver pic32_rtc_driver = { .remove = pic32_rtc_remove, .driver = { .name = "pic32-rtc", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pic32_rtc_dt_ids), }, }; -- GitLab From 1bc40cb1ccbc7e33622a1fd2a8a37f311e64d4fc Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 15 Aug 2016 17:04:42 +0200 Subject: [PATCH 0050/1167] rtc: rx6110: remove owner assignment .owner is already set by the spi core. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx6110.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index bbad00b233bce..591793e2b4acf 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -388,7 +388,6 @@ MODULE_DEVICE_TABLE(spi, rx6110_id); static struct spi_driver rx6110_driver = { .driver = { .name = RX6110_DRIVER_NAME, - .owner = THIS_MODULE, }, .probe = rx6110_probe, .remove = rx6110_remove, -- GitLab From 637cac7c139f6433506f38aca85c2bf37ff64787 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 19 Aug 2016 15:42:23 +0800 Subject: [PATCH 0051/1167] rtc: ac100: support clock-output-names in device tree binding The ac100 device tree binding specifies the usage of clock-output-names to specify the names of its 3 clock outputs. This is needed for orphan clock resolution, when the ac100 is probed much later than any clocks that consume any of its outputs. This wasn't supported by the driver. Add support for this. Signed-off-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ac100.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c index 70b4fd0f61225..2d0bb02a25d95 100644 --- a/drivers/rtc/rtc-ac100.c +++ b/drivers/rtc/rtc-ac100.c @@ -327,6 +327,8 @@ static int ac100_rtc_register_clks(struct ac100_rtc_dev *chip) .flags = 0, }; + of_property_read_string_index(np, "clock-output-names", + i, &init.name); clk->regmap = chip->regmap; clk->offset = AC100_CLKOUT_CTRL1 + i; clk->hw.init = &init; -- GitLab From 34c7b3ac4ccb6a972f81a4102c8ef216ca1fb155 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 31 Aug 2016 10:05:25 +0200 Subject: [PATCH 0052/1167] rtc: constify rtc_class_ops structures Check for rtc_class_ops structures that are only passed to devm_rtc_device_register, rtc_device_register, platform_device_register_data, all of which declare the corresponding parameter as const. Declare rtc_class_ops structures that have these properties as const. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r disable optional_qualifier@ identifier i; position p; @@ static struct rtc_class_ops i@p = { ... }; @ok@ identifier r.i; expression e1,e2,e3,e4; position p; @@ ( devm_rtc_device_register(e1,e2,&i@p,e3) | rtc_device_register(e1,e2,&i@p,e3) | platform_device_register_data(e1,e2,e3,&i@p,e4) ) @bad@ position p != {r.p,ok.p}; identifier r.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ static +const struct rtc_class_ops i = { ... }; // Signed-off-by: Julia Lawall Acked-by: Baruch Siach Acked-by: Hans Ulli Kroll Acked-by: Linus Walleij Acked-by: Thierry Reding Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-at32ap700x.c | 2 +- drivers/rtc/rtc-coh901331.c | 2 +- drivers/rtc/rtc-davinci.c | 2 +- drivers/rtc/rtc-digicolor.c | 2 +- drivers/rtc/rtc-ds1302.c | 2 +- drivers/rtc/rtc-gemini.c | 2 +- drivers/rtc/rtc-jz4740.c | 2 +- drivers/rtc/rtc-mcp795.c | 2 +- drivers/rtc/rtc-mt6397.c | 2 +- drivers/rtc/rtc-nuc900.c | 2 +- drivers/rtc/rtc-omap.c | 2 +- drivers/rtc/rtc-palmas.c | 2 +- drivers/rtc/rtc-pcf50633.c | 2 +- drivers/rtc/rtc-rx6110.c | 2 +- drivers/rtc/rtc-rx8025.c | 2 +- drivers/rtc/rtc-spear.c | 2 +- drivers/rtc/rtc-stmp3xxx.c | 2 +- drivers/rtc/rtc-tegra.c | 2 +- drivers/rtc/rtc-twl.c | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index 83ac2337c0f73..de8bf56a41e76 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -187,7 +187,7 @@ static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id) return ret; } -static struct rtc_class_ops at32_rtc_ops = { +static const struct rtc_class_ops at32_rtc_ops = { .read_time = at32_rtc_readtime, .set_time = at32_rtc_settime, .read_alarm = at32_rtc_readalarm, diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 101b7a240e0fa..cfc4141d99cde 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -140,7 +140,7 @@ static int coh901331_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static struct rtc_class_ops coh901331_ops = { +static const struct rtc_class_ops coh901331_ops = { .read_time = coh901331_read_time, .set_mmss = coh901331_set_mmss, .read_alarm = coh901331_read_alarm, diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index dba60c1dfce2e..caf35567e14cb 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -469,7 +469,7 @@ static int davinci_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) return 0; } -static struct rtc_class_ops davinci_rtc_ops = { +static const struct rtc_class_ops davinci_rtc_ops = { .ioctl = davinci_rtc_ioctl, .read_time = davinci_rtc_read_time, .set_time = davinci_rtc_set_time, diff --git a/drivers/rtc/rtc-digicolor.c b/drivers/rtc/rtc-digicolor.c index 8d05596a67659..b253bf1b35314 100644 --- a/drivers/rtc/rtc-digicolor.c +++ b/drivers/rtc/rtc-digicolor.c @@ -159,7 +159,7 @@ static int dc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static struct rtc_class_ops dc_rtc_ops = { +static const struct rtc_class_ops dc_rtc_ops = { .read_time = dc_rtc_read_time, .set_mmss = dc_rtc_set_mmss, .read_alarm = dc_rtc_read_alarm, diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index f5dd09fe5add5..0ec4be62322bf 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -102,7 +102,7 @@ static int ds1302_rtc_get_time(struct device *dev, struct rtc_time *time) return rtc_valid_tm(time); } -static struct rtc_class_ops ds1302_rtc_ops = { +static const struct rtc_class_ops ds1302_rtc_ops = { .read_time = ds1302_rtc_get_time, .set_time = ds1302_rtc_set_time, }; diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-gemini.c index b57505efadbc8..688debc143483 100644 --- a/drivers/rtc/rtc-gemini.c +++ b/drivers/rtc/rtc-gemini.c @@ -110,7 +110,7 @@ static int gemini_rtc_set_time(struct device *dev, struct rtc_time *tm) return 0; } -static struct rtc_class_ops gemini_rtc_ops = { +static const struct rtc_class_ops gemini_rtc_ops = { .read_time = gemini_rtc_read_time, .set_time = gemini_rtc_set_time, }; diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index b2bcfc0bf2e51..5e14651b71a89 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -174,7 +174,7 @@ static int jz4740_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) return jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_AF_IRQ, enable); } -static struct rtc_class_ops jz4740_rtc_ops = { +static const struct rtc_class_ops jz4740_rtc_ops = { .read_time = jz4740_rtc_read_time, .set_mmss = jz4740_rtc_set_mmss, .read_alarm = jz4740_rtc_read_alarm, diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index 025bb33b9cd2d..4021fd04cb0ac 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -151,7 +151,7 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim) return rtc_valid_tm(tim); } -static struct rtc_class_ops mcp795_rtc_ops = { +static const struct rtc_class_ops mcp795_rtc_ops = { .read_time = mcp795_read_time, .set_time = mcp795_set_time }; diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 44f622c3e0488..1a61fa56f3ad7 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -301,7 +301,7 @@ static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) return ret; } -static struct rtc_class_ops mtk_rtc_ops = { +static const struct rtc_class_ops mtk_rtc_ops = { .read_time = mtk_rtc_read_time, .set_time = mtk_rtc_set_time, .read_alarm = mtk_rtc_read_alarm, diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c index 09fc1c19f0dfd..b1b6b3041bfbc 100644 --- a/drivers/rtc/rtc-nuc900.c +++ b/drivers/rtc/rtc-nuc900.c @@ -214,7 +214,7 @@ static int nuc900_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return 0; } -static struct rtc_class_ops nuc900_rtc_ops = { +static const struct rtc_class_ops nuc900_rtc_ops = { .read_time = nuc900_rtc_read_time, .set_time = nuc900_rtc_set_time, .read_alarm = nuc900_rtc_read_alarm, diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index ec2e9c5fb993c..cadac8e2aa6b7 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -469,7 +469,7 @@ static void omap_rtc_power_off(void) mdelay(2500); } -static struct rtc_class_ops omap_rtc_ops = { +static const struct rtc_class_ops omap_rtc_ops = { .read_time = omap_rtc_read_time, .set_time = omap_rtc_set_time, .read_alarm = omap_rtc_read_alarm, diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c index 6080e0edef632..4bcfb88674d38 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -225,7 +225,7 @@ static irqreturn_t palmas_rtc_interrupt(int irq, void *context) return IRQ_HANDLED; } -static struct rtc_class_ops palmas_rtc_ops = { +static const struct rtc_class_ops palmas_rtc_ops = { .read_time = palmas_rtc_read_time, .set_time = palmas_rtc_set_time, .read_alarm = palmas_rtc_read_alarm, diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index e6b6911c8e052..00c31c91b245f 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c @@ -232,7 +232,7 @@ static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } -static struct rtc_class_ops pcf50633_rtc_ops = { +static const struct rtc_class_ops pcf50633_rtc_ops = { .read_time = pcf50633_rtc_read_time, .set_time = pcf50633_rtc_set_time, .read_alarm = pcf50633_rtc_read_alarm, diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index 591793e2b4acf..7c9c08eab5e5b 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -317,7 +317,7 @@ static int rx6110_init(struct rx6110_data *rx6110) return ret; } -static struct rtc_class_ops rx6110_rtc_ops = { +static const struct rtc_class_ops rx6110_rtc_ops = { .read_time = rx6110_get_time, .set_time = rx6110_set_time, }; diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 2b85cc7a24e75..91857d8d2df87 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -403,7 +403,7 @@ static int rx8025_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static struct rtc_class_ops rx8025_rtc_ops = { +static const struct rtc_class_ops rx8025_rtc_ops = { .read_time = rx8025_get_time, .set_time = rx8025_set_time, .read_alarm = rx8025_read_alarm, diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index f05ef85684804..e377f42abae7a 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -343,7 +343,7 @@ static int spear_alarm_irq_enable(struct device *dev, unsigned int enabled) return ret; } -static struct rtc_class_ops spear_rtc_ops = { +static const struct rtc_class_ops spear_rtc_ops = { .read_time = spear_rtc_read_time, .set_time = spear_rtc_set_time, .read_alarm = spear_rtc_read_alarm, diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index e6aaaa52e7fe1..d578e40d5a506 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -231,7 +231,7 @@ static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) return 0; } -static struct rtc_class_ops stmp3xxx_rtc_ops = { +static const struct rtc_class_ops stmp3xxx_rtc_ops = { .alarm_irq_enable = stmp3xxx_alarm_irq_enable, .read_time = stmp3xxx_rtc_gettime, diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index 15ac597d54da2..3853ba963bb5d 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -291,7 +291,7 @@ static irqreturn_t tegra_rtc_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static struct rtc_class_ops tegra_rtc_ops = { +static const struct rtc_class_ops tegra_rtc_ops = { .read_time = tegra_rtc_read_time, .set_time = tegra_rtc_set_time, .read_alarm = tegra_rtc_read_alarm, diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 2dc787dc06c17..176720b7b9e50 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -462,7 +462,7 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) return ret; } -static struct rtc_class_ops twl_rtc_ops = { +static const struct rtc_class_ops twl_rtc_ops = { .read_time = twl_rtc_read_time, .set_time = twl_rtc_set_time, .read_alarm = twl_rtc_read_alarm, -- GitLab From 7f742e8e8ad4c54ae66820c91bbbb6526a461117 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 31 Aug 2016 18:15:27 +0200 Subject: [PATCH 0053/1167] rtc: asm9260: allow COMPILE_TEST The rtc-asm9260 driver compiles correctly on other architectures, add COMPILE_TEST to improve code coverage. Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 23acc3f536b35..896302a0d4b9d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1205,7 +1205,7 @@ comment "on-CPU RTC drivers" config RTC_DRV_ASM9260 tristate "Alphascale asm9260 RTC" - depends on MACH_ASM9260 + depends on MACH_ASM9260 || COMPILE_TEST help If you say yes here you get support for the RTC on the Alphascale asm9260 SoC. -- GitLab From de75ccdd4118ca41ac473c1ab96365280c631cdd Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 31 Aug 2016 18:15:28 +0200 Subject: [PATCH 0054/1167] rtc: asm9260: rework locking The rtc-asm9260 driver uses a discrete spinlock (wrongly uninitialized). Use the rtc mutex to lock mmio accesses instead. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-asm9260.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/rtc/rtc-asm9260.c b/drivers/rtc/rtc-asm9260.c index 5219916ce11d2..18a93d3e3f931 100644 --- a/drivers/rtc/rtc-asm9260.c +++ b/drivers/rtc/rtc-asm9260.c @@ -112,8 +112,6 @@ struct asm9260_rtc_priv { void __iomem *iobase; struct rtc_device *rtc; struct clk *clk; - /* io lock */ - spinlock_t lock; }; static irqreturn_t asm9260_rtc_irq(int irq, void *dev_id) @@ -122,11 +120,15 @@ static irqreturn_t asm9260_rtc_irq(int irq, void *dev_id) u32 isr; unsigned long events = 0; + mutex_lock(&priv->rtc->ops_lock); isr = ioread32(priv->iobase + HW_CIIR); - if (!isr) + if (!isr) { + mutex_unlock(&priv->rtc->ops_lock); return IRQ_NONE; + } iowrite32(0, priv->iobase + HW_CIIR); + mutex_unlock(&priv->rtc->ops_lock); events |= RTC_AF | RTC_IRQF; @@ -139,9 +141,7 @@ static int asm9260_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); u32 ctime0, ctime1, ctime2; - unsigned long irq_flags; - spin_lock_irqsave(&priv->lock, irq_flags); ctime0 = ioread32(priv->iobase + HW_CTIME0); ctime1 = ioread32(priv->iobase + HW_CTIME1); ctime2 = ioread32(priv->iobase + HW_CTIME2); @@ -155,7 +155,6 @@ static int asm9260_rtc_read_time(struct device *dev, struct rtc_time *tm) ctime1 = ioread32(priv->iobase + HW_CTIME1); ctime2 = ioread32(priv->iobase + HW_CTIME2); } - spin_unlock_irqrestore(&priv->lock, irq_flags); tm->tm_sec = (ctime0 >> BM_CTIME0_SEC_S) & BM_CTIME0_SEC_M; tm->tm_min = (ctime0 >> BM_CTIME0_MIN_S) & BM_CTIME0_MIN_M; @@ -174,9 +173,7 @@ static int asm9260_rtc_read_time(struct device *dev, struct rtc_time *tm) static int asm9260_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); - unsigned long irq_flags; - spin_lock_irqsave(&priv->lock, irq_flags); /* * make sure SEC counter will not flip other counter on write time, * real value will be written at the enf of sequence. @@ -191,7 +188,6 @@ static int asm9260_rtc_set_time(struct device *dev, struct rtc_time *tm) iowrite32(tm->tm_hour, priv->iobase + HW_HOUR); iowrite32(tm->tm_min, priv->iobase + HW_MIN); iowrite32(tm->tm_sec, priv->iobase + HW_SEC); - spin_unlock_irqrestore(&priv->lock, irq_flags); return 0; } @@ -199,9 +195,7 @@ static int asm9260_rtc_set_time(struct device *dev, struct rtc_time *tm) static int asm9260_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); - unsigned long irq_flags; - spin_lock_irqsave(&priv->lock, irq_flags); alrm->time.tm_year = ioread32(priv->iobase + HW_ALYEAR); alrm->time.tm_mon = ioread32(priv->iobase + HW_ALMON); alrm->time.tm_mday = ioread32(priv->iobase + HW_ALDOM); @@ -213,7 +207,6 @@ static int asm9260_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = ioread32(priv->iobase + HW_AMR) ? 1 : 0; alrm->pending = ioread32(priv->iobase + HW_CIIR) ? 1 : 0; - spin_unlock_irqrestore(&priv->lock, irq_flags); return rtc_valid_tm(&alrm->time); } @@ -221,9 +214,7 @@ static int asm9260_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int asm9260_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); - unsigned long irq_flags; - spin_lock_irqsave(&priv->lock, irq_flags); iowrite32(alrm->time.tm_year, priv->iobase + HW_ALYEAR); iowrite32(alrm->time.tm_mon, priv->iobase + HW_ALMON); iowrite32(alrm->time.tm_mday, priv->iobase + HW_ALDOM); @@ -234,7 +225,6 @@ static int asm9260_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) iowrite32(alrm->time.tm_sec, priv->iobase + HW_ALSEC); iowrite32(alrm->enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR); - spin_unlock_irqrestore(&priv->lock, irq_flags); return 0; } -- GitLab From 0b9e2988ab2261fd6d4a0039edf81ed1e3662be8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 5 Sep 2016 17:21:45 +0200 Subject: [PATCH 0055/1167] ahci: use pci_alloc_irq_vectors Use the new pci_alloc_irq_vectors API to allocate MSI-X and MSI vectors. The big advantage over the old code is that we can use the same API for MSI and MSI-X, and that we don't need to store the MSI-X vector mapping in driver-private data structures. This first conversion keeps the probe order as-is: MSI-X multi vector, MSI multi vector, MSI single vector, MSI-X single vector and last a single least legacy interrupt line. There is one small change of behavior: we now check the "MSI Revert to Single Message" flag for MSI-X in addition to MSI. Because the API to find the Linux IRQ number for a MSI/MSI-X vector is PCI specific, but libahaci is bus-agnostic I had to a get_irq_vector function pointer to struct ahci_host_priv. The alternative would be to move the multi-vector case of ahci_host_activate to ahci.c and just call ata_host_activate directly from the others users of ahci_host_activate. Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 149 +++++++++--------------------------------- drivers/ata/ahci.h | 24 ++----- drivers/ata/libahci.c | 11 +++- 3 files changed, 45 insertions(+), 139 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 90eabaf812150..ba5f11cebee2a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1400,142 +1400,56 @@ static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance) } #endif -/* - * ahci_init_msix() - optionally enable per-port MSI-X otherwise defer - * to single msi. - */ -static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports, - struct ahci_host_priv *hpriv, unsigned long flags) +static int ahci_get_irq_vector(struct ata_host *host, int port) { - int nvec, i, rc; - - /* Do not init MSI-X if MSI is disabled for the device */ - if (hpriv->flags & AHCI_HFLAG_NO_MSI) - return -ENODEV; - - nvec = pci_msix_vec_count(pdev); - if (nvec < 0) - return nvec; - - /* - * Proper MSI-X implementations will have a vector per-port. - * Barring that, we prefer single-MSI over single-MSIX. If this - * check fails (not enough MSI-X vectors for all ports) we will - * be called again with the flag clear iff ahci_init_msi() - * fails. - */ - if (flags & AHCI_HFLAG_MULTI_MSIX) { - if (nvec < n_ports) - return -ENODEV; - nvec = n_ports; - } else if (nvec) { - nvec = 1; - } else { - /* - * Emit dev_err() since this was the non-legacy irq - * method of last resort. - */ - rc = -ENODEV; - goto fail; - } - - for (i = 0; i < nvec; i++) - hpriv->msix[i].entry = i; - rc = pci_enable_msix_exact(pdev, hpriv->msix, nvec); - if (rc < 0) - goto fail; - - if (nvec > 1) - hpriv->flags |= AHCI_HFLAG_MULTI_MSIX; - hpriv->irq = hpriv->msix[0].vector; /* for single msi-x */ - - return nvec; -fail: - dev_err(&pdev->dev, - "failed to enable MSI-X with error %d, # of vectors: %d\n", - rc, nvec); - - return rc; + return pci_irq_vector(to_pci_dev(host->dev), port); } static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, struct ahci_host_priv *hpriv) { - int rc, nvec; + int nvec; if (hpriv->flags & AHCI_HFLAG_NO_MSI) return -ENODEV; - nvec = pci_msi_vec_count(pdev); - if (nvec < 0) - return nvec; - /* * If number of MSIs is less than number of ports then Sharing Last * Message mode could be enforced. In this case assume that advantage * of multipe MSIs is negated and use single MSI mode instead. */ - if (nvec < n_ports) - goto single_msi; - - rc = pci_enable_msi_exact(pdev, nvec); - if (rc == -ENOSPC) - goto single_msi; - if (rc < 0) - return rc; + nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX, + PCI_IRQ_MSIX | PCI_IRQ_MSI); + if (nvec > 0) { + if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) { + hpriv->get_irq_vector = ahci_get_irq_vector; + hpriv->flags |= AHCI_HFLAG_MULTI_MSI; + return nvec; + } - /* fallback to single MSI mode if the controller enforced MRSM mode */ - if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) { - pci_disable_msi(pdev); + /* + * Fallback to single MSI mode if the controller enforced MRSM + * mode. + */ printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n"); - goto single_msi; + pci_free_irq_vectors(pdev); } - if (nvec > 1) - hpriv->flags |= AHCI_HFLAG_MULTI_MSI; - - goto out; - -single_msi: - nvec = 1; - - rc = pci_enable_msi(pdev); - if (rc < 0) - return rc; -out: - hpriv->irq = pdev->irq; - - return nvec; -} - -static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, - struct ahci_host_priv *hpriv) -{ - int nvec; - /* - * Try to enable per-port MSI-X. If the host is not capable - * fall back to single MSI before finally attempting single - * MSI-X. + * -ENOSPC indicated we don't have enough vectors. Don't bother trying + * a single vectors for any other error: */ - nvec = ahci_init_msix(pdev, n_ports, hpriv, AHCI_HFLAG_MULTI_MSIX); - if (nvec >= 0) + if (nvec < 0 && nvec != -ENOSPC) return nvec; - nvec = ahci_init_msi(pdev, n_ports, hpriv); - if (nvec >= 0) - return nvec; - - /* try single-msix */ - nvec = ahci_init_msix(pdev, n_ports, hpriv, 0); - if (nvec >= 0) + /* + * If the host is not capable of supporting per-port vectors, fall + * back to single MSI before finally attempting single MSI-X. + */ + nvec = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); + if (nvec == 1) return nvec; - - /* legacy intx interrupts */ - pci_intx(pdev, 1); - hpriv->irq = pdev->irq; - - return 0; + return pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX); } static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1698,11 +1612,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!host) return -ENOMEM; host->private_data = hpriv; - hpriv->msix = devm_kzalloc(&pdev->dev, - sizeof(struct msix_entry) * n_ports, GFP_KERNEL); - if (!hpriv->msix) - return -ENOMEM; - ahci_init_interrupts(pdev, n_ports, hpriv); + + if (ahci_init_msi(pdev, n_ports, hpriv) < 0) { + /* legacy intx interrupts */ + pci_intx(pdev, 1); + } + hpriv->irq = pdev->irq; if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) host->flags |= ATA_HOST_PARALLEL_SCAN; diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 70b06bcfb7e35..0cc08f892feae 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -242,12 +242,10 @@ enum { AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */ #ifdef CONFIG_PCI_MSI - AHCI_HFLAG_MULTI_MSI = (1 << 20), /* multiple PCI MSIs */ - AHCI_HFLAG_MULTI_MSIX = (1 << 21), /* per-port MSI-X */ + AHCI_HFLAG_MULTI_MSI = (1 << 20), /* per-port MSI(-X) */ #else /* compile out MSI infrastructure */ AHCI_HFLAG_MULTI_MSI = 0, - AHCI_HFLAG_MULTI_MSIX = 0, #endif AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */ @@ -351,7 +349,6 @@ struct ahci_host_priv { * the PHY position in this array. */ struct phy **phys; - struct msix_entry *msix; /* Optional MSI-X support */ unsigned nports; /* Number of ports */ void *plat_data; /* Other platform data */ unsigned int irq; /* interrupt line */ @@ -362,22 +359,11 @@ struct ahci_host_priv { */ void (*start_engine)(struct ata_port *ap); irqreturn_t (*irq_handler)(int irq, void *dev_instance); -}; -#ifdef CONFIG_PCI_MSI -static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port) -{ - if (hpriv->flags & AHCI_HFLAG_MULTI_MSIX) - return hpriv->msix[port].vector; - else - return hpriv->irq + port; -} -#else -static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port) -{ - return hpriv->irq; -} -#endif + /* only required for per-port MSI(-X) support */ + int (*get_irq_vector)(struct ata_host *host, + int port); +}; extern int ahci_ignore_sss; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 5a1329e31609f..0d028ead99e85 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2378,7 +2378,7 @@ static int ahci_port_start(struct ata_port *ap) /* * Switch to per-port locking in case each port has its own MSI vector. */ - if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) { + if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) { spin_lock_init(&pp->lock); ap->lock = &pp->lock; } @@ -2520,7 +2520,7 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, */ for (i = 0; i < host->n_ports; i++) { struct ahci_port_priv *pp = host->ports[i]->private_data; - int irq = ahci_irq_vector(hpriv, i); + int irq = hpriv->get_irq_vector(host, i); /* Do not receive interrupts sent by dummy ports */ if (!pp) { @@ -2556,10 +2556,15 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht) int irq = hpriv->irq; int rc; - if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) { + if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) { if (hpriv->irq_handler) dev_warn(host->dev, "both AHCI_HFLAG_MULTI_MSI flag set and custom irq handler implemented\n"); + if (!hpriv->get_irq_vector) { + dev_err(host->dev, + "AHCI_HFLAG_MULTI_MSI requires ->get_irq_vector!\n"); + return -EIO; + } rc = ahci_host_activate_multi_irqs(host, sht); } else { -- GitLab From a5967db9af51a84f5e181600954714a9e4c69f1f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 24 Aug 2016 22:29:19 +1000 Subject: [PATCH 0056/1167] kbuild: allow architectures to use thin archives instead of ld -r ld -r is an incremental link used to create built-in.o files in build subdirectories. It produces relocatable object files containing all its input files, and these are are then pulled together and relocated in the final link. Aside from the bloat, this constrains the final link relocations, which has bitten large powerpc builds with unresolvable relocations in the final link. Alan Modra has recommended the kernel use thin archives for linking. This is an alternative and means that the linker has more information available to it when it links the kernel. This patch enables a config option architectures can select, which causes all built-in.o files to be built as thin archives. built-in.o files in subdirectories do not get symbol table or index attached, which improves speed and size. The final link pass creates a built-in.o archive in the root output directory which includes the symbol table and index. The linker then uses takes this file to link. The --whole-archive linker option is required, because the linker now has visibility to every individual object file, and it will otherwise just completely avoid including those without external references (consider a file with EXPORT_SYMBOL or initcall or hardware exceptions as its only entry points). The traditional built works "by luck" as built-in.o files are large enough that they're going to get external references. However this optimisation is unpredictable for the kernel (due to above external references), ineffective at culling unused, and costly because the .o files have to be searched for references. Superior alternatives for link-time culling should be used instead. Build characteristics for inclink vs thinarc, on a small powerpc64le pseries VM with a modest .config: inclink thinarc sizes vmlinux 15 618 680 15 625 028 sum of all built-in.o 56 091 808 1 054 334 sum excluding root built-in.o 151 430 find -name built-in.o | xargs rm ; time make vmlinux real 22.772s 21.143s user 13.280s 13.430s sys 4.310s 2.750s - Final kernel pulled in only about 6K more, which shows how ineffective the object file culling is. - Build performance looks improved due to less pagecache activity. On IO constrained systems it could be a bigger win. - Build size saving is significant. Side note, the toochain understands archives, so there's some tricks, $ ar t built-in.o # list all files you linked with $ size built-in.o # and their sizes $ objdump -d built-in.o # disassembly (unrelocated) with filenames Implementation by sfr, minor tweaks by npiggin. Signed-off-by: Stephen Rothwell Signed-off-by: Nicholas Piggin Signed-off-by: Michal Marek --- arch/Kconfig | 6 ++++ scripts/Makefile.build | 23 ++++++++++--- scripts/link-vmlinux.sh | 71 ++++++++++++++++++++++++++++++++++------- 3 files changed, 85 insertions(+), 15 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index bd8056b5b2460..6842154813e50 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -461,6 +461,12 @@ config CC_STACKPROTECTOR_STRONG endchoice +config THIN_ARCHIVES + bool + help + Select this if the architecture wants to use thin archives + instead of ld -r to create the built-in.o files. + config HAVE_CONTEXT_TRACKING bool help diff --git a/scripts/Makefile.build b/scripts/Makefile.build index cd9bf22bb0279..de46ab03f063b 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -359,12 +359,22 @@ $(sort $(subdir-obj-y)): $(subdir-ym) ; # Rule to compile a set of .o files into one .o file # ifdef builtin-target -quiet_cmd_link_o_target = LD $@ + +ifdef CONFIG_THIN_ARCHIVES + cmd_make_builtin = rm -f $@; $(AR) rcST$(KBUILD_ARFLAGS) + cmd_make_empty_builtin = rm -f $@; $(AR) rcST$(KBUILD_ARFLAGS) + quiet_cmd_link_o_target = AR $@ +else + cmd_make_builtin = $(LD) $(ld_flags) -r -o + cmd_make_empty_builtin = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) + quiet_cmd_link_o_target = LD $@ +endif + # If the list of objects to link is empty, just create an empty built-in.o cmd_link_o_target = $(if $(strip $(obj-y)),\ - $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \ + $(cmd_make_builtin) $@ $(filter $(obj-y), $^) \ $(cmd_secanalysis),\ - rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@) + $(cmd_make_empty_builtin) $@) $(builtin-target): $(obj-y) FORCE $(call if_changed,link_o_target) @@ -390,7 +400,12 @@ $(modorder-target): $(subdir-ym) FORCE # ifdef lib-target quiet_cmd_link_l_target = AR $@ -cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y) + +ifdef CONFIG_THIN_ARCHIVES + cmd_link_l_target = rm -f $@; $(AR) rcsT$(KBUILD_ARFLAGS) $@ $(lib-y) +else + cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y) +endif $(lib-target): $(lib-y) FORCE $(call if_changed,link_l_target) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 4f727eb5ec43f..f742c65108b9d 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -37,12 +37,40 @@ info() fi } +# Thin archive build here makes a final archive with +# symbol table and indexes from vmlinux objects, which can be +# used as input to linker. +# +# Traditional incremental style of link does not require this step +# +# built-in.o output file +# +archive_builtin() +{ + if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + info AR built-in.o + rm -f built-in.o; + ${AR} rcsT${KBUILD_ARFLAGS} built-in.o \ + ${KBUILD_VMLINUX_INIT} \ + ${KBUILD_VMLINUX_MAIN} + fi +} + # Link of vmlinux.o used for section mismatch analysis # ${1} output file modpost_link() { - ${LD} ${LDFLAGS} -r -o ${1} ${KBUILD_VMLINUX_INIT} \ - --start-group ${KBUILD_VMLINUX_MAIN} --end-group + local objects + + if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + objects="--whole-archive built-in.o" + else + objects="${KBUILD_VMLINUX_INIT} \ + --start-group \ + ${KBUILD_VMLINUX_MAIN} \ + --end-group" + fi + ${LD} ${LDFLAGS} -r -o ${1} ${objects} } # Link of vmlinux @@ -51,18 +79,36 @@ modpost_link() vmlinux_link() { local lds="${objtree}/${KBUILD_LDS}" + local objects if [ "${SRCARCH}" != "um" ]; then - ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ - -T ${lds} ${KBUILD_VMLINUX_INIT} \ - --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1} + if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + objects="--whole-archive built-in.o ${1}" + else + objects="${KBUILD_VMLINUX_INIT} \ + --start-group \ + ${KBUILD_VMLINUX_MAIN} \ + --end-group \ + ${1}" + fi + + ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ + -T ${lds} ${objects} else - ${CC} ${CFLAGS_vmlinux} -o ${2} \ - -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT} \ - -Wl,--start-group \ - ${KBUILD_VMLINUX_MAIN} \ - -Wl,--end-group \ - -lutil -lrt -lpthread ${1} + if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + objects="-Wl,--whole-archive built-in.o ${1}" + else + objects="${KBUILD_VMLINUX_INIT} \ + -Wl,--start-group \ + ${KBUILD_VMLINUX_MAIN} \ + -Wl,--end-group \ + ${1}" + fi + + ${CC} ${CFLAGS_vmlinux} -o ${2} \ + -Wl,-T,${lds} \ + ${objects} \ + -lutil -lrt -lpthread rm -f linux fi } @@ -119,6 +165,7 @@ cleanup() rm -f .tmp_kallsyms* rm -f .tmp_version rm -f .tmp_vmlinux* + rm -f built-in.o rm -f System.map rm -f vmlinux rm -f vmlinux.o @@ -162,6 +209,8 @@ case "${KCONFIG_CONFIG}" in . "./${KCONFIG_CONFIG}" esac +archive_builtin + #link vmlinux.o info LD vmlinux.o modpost_link vmlinux.o -- GitLab From b67067f1176df6ee727450546b58704e4b588563 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 24 Aug 2016 22:29:20 +1000 Subject: [PATCH 0057/1167] kbuild: allow archs to select link dead code/data elimination Introduce LD_DEAD_CODE_DATA_ELIMINATION option for architectures to select to build with -ffunction-sections, -fdata-sections, and link with --gc-sections. It requires some work (documented) to ensure all unreferenced entrypoints are live, and requires toolchain and build verification, so it is made a per-arch option for now. On a random powerpc64le build, this yelds a significant size saving, it boots and runs fine, but there is a lot I haven't tested as yet, so these savings may be reduced if there are bugs in the link. text data bss dec filename 11169741 1180744 1923176 14273661 vmlinux 10445269 1004127 1919707 13369103 vmlinux.dce ~700K text, ~170K data, 6% removed from kernel image size. Signed-off-by: Nicholas Piggin Signed-off-by: Michal Marek --- Makefile | 9 ++++++ arch/Kconfig | 13 ++++++++ include/asm-generic/vmlinux.lds.h | 52 +++++++++++++++++-------------- include/linux/compiler.h | 23 ++++++++++++++ include/linux/export.h | 30 +++++++++--------- include/linux/init.h | 38 ++++++++-------------- init/Makefile | 2 ++ 7 files changed, 104 insertions(+), 63 deletions(-) diff --git a/Makefile b/Makefile index 70de1448c5717..6d40f3a3a8cce 100644 --- a/Makefile +++ b/Makefile @@ -622,6 +622,11 @@ include arch/$(SRCARCH)/Makefile KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,) +ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION +KBUILD_CFLAGS += $(call cc-option,-ffunction-sections,) +KBUILD_CFLAGS += $(call cc-option,-fdata-sections,) +endif + ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE KBUILD_CFLAGS += -Os else @@ -809,6 +814,10 @@ LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\ KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID) LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID) +ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION +LDFLAGS_vmlinux += $(call ld-option, --gc-sections,) +endif + ifeq ($(CONFIG_STRIP_ASM_SYMS),y) LDFLAGS_vmlinux += $(call ld-option, -X,) endif diff --git a/arch/Kconfig b/arch/Kconfig index 6842154813e50..3f948c422d9d1 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -467,6 +467,19 @@ config THIN_ARCHIVES Select this if the architecture wants to use thin archives instead of ld -r to create the built-in.o files. +config LD_DEAD_CODE_DATA_ELIMINATION + bool + help + Select this if the architecture wants to do dead code and + data elimination with the linker by compiling with + -ffunction-sections -fdata-sections and linking with + --gc-sections. + + This requires that the arch annotates or otherwise protects + its external entry points from being discarded. Linker scripts + must also merge .text.*, .data.*, and .bss.* correctly into + output sections. + config HAVE_CONTEXT_TRACKING bool help diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 24563970ff7bd..ad9d8f94dc7a9 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -196,9 +196,14 @@ *(.dtb.init.rodata) \ VMLINUX_SYMBOL(__dtb_end) = .; -/* .data section */ +/* + * .data section + * -fdata-sections generates .data.identifier which needs to be pulled in + * with .data, but don't want to pull in .data..stuff which has its own + * requirements. Same for bss. + */ #define DATA_DATA \ - *(.data) \ + *(.data .data.[0-9a-zA-Z_]*) \ *(.ref.data) \ *(.data..shared_aligned) /* percpu related */ \ MEM_KEEP(init.data) \ @@ -320,76 +325,76 @@ /* Kernel symbol table: Normal symbols */ \ __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab) = .; \ - *(SORT(___ksymtab+*)) \ + KEEP(*(SORT(___ksymtab+*))) \ VMLINUX_SYMBOL(__stop___ksymtab) = .; \ } \ \ /* Kernel symbol table: GPL-only symbols */ \ __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ - *(SORT(___ksymtab_gpl+*)) \ + KEEP(*(SORT(___ksymtab_gpl+*))) \ VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ } \ \ /* Kernel symbol table: Normal unused symbols */ \ __ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \ - *(SORT(___ksymtab_unused+*)) \ + KEEP(*(SORT(___ksymtab_unused+*))) \ VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \ } \ \ /* Kernel symbol table: GPL-only unused symbols */ \ __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \ - *(SORT(___ksymtab_unused_gpl+*)) \ + KEEP(*(SORT(___ksymtab_unused_gpl+*))) \ VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \ } \ \ /* Kernel symbol table: GPL-future-only symbols */ \ __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \ - *(SORT(___ksymtab_gpl_future+*)) \ + KEEP(*(SORT(___ksymtab_gpl_future+*))) \ VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \ } \ \ /* Kernel symbol table: Normal symbols */ \ __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab) = .; \ - *(SORT(___kcrctab+*)) \ + KEEP(*(SORT(___kcrctab+*))) \ VMLINUX_SYMBOL(__stop___kcrctab) = .; \ } \ \ /* Kernel symbol table: GPL-only symbols */ \ __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ - *(SORT(___kcrctab_gpl+*)) \ + KEEP(*(SORT(___kcrctab_gpl+*))) \ VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ } \ \ /* Kernel symbol table: Normal unused symbols */ \ __kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \ - *(SORT(___kcrctab_unused+*)) \ + KEEP(*(SORT(___kcrctab_unused+*))) \ VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \ } \ \ /* Kernel symbol table: GPL-only unused symbols */ \ __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \ - *(SORT(___kcrctab_unused_gpl+*)) \ + KEEP(*(SORT(___kcrctab_unused_gpl+*))) \ VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \ } \ \ /* Kernel symbol table: GPL-future-only symbols */ \ __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \ - *(SORT(___kcrctab_gpl_future+*)) \ + KEEP(*(SORT(___kcrctab_gpl_future+*))) \ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ } \ \ /* Kernel symbol table: strings */ \ __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ - *(__ksymtab_strings) \ + KEEP(*(__ksymtab_strings)) \ } \ \ /* __*init sections */ \ @@ -424,7 +429,7 @@ #define SECURITY_INIT \ .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__security_initcall_start) = .; \ - *(.security_initcall.init) \ + KEEP(*(.security_initcall.init)) \ VMLINUX_SYMBOL(__security_initcall_end) = .; \ } @@ -432,7 +437,7 @@ * during second ld run in second ld pass when generating System.map */ #define TEXT_TEXT \ ALIGN_FUNCTION(); \ - *(.text.hot .text .text.fixup .text.unlikely) \ + *(.text.hot .text .text.fixup .text.unlikely .text.*) \ *(.ref.text) \ MEM_KEEP(init.text) \ MEM_KEEP(exit.text) \ @@ -527,6 +532,7 @@ /* init and exit section handling */ #define INIT_DATA \ + KEEP(*(SORT(___kentry+*))) \ *(.init.data) \ MEM_DISCARD(init.data) \ KERNEL_CTORS() \ @@ -593,7 +599,7 @@ BSS_FIRST_SECTIONS \ *(.bss..page_aligned) \ *(.dynbss) \ - *(.bss) \ + *(.bss .bss.[0-9a-zA-Z_]*) \ *(COMMON) \ } @@ -676,12 +682,12 @@ #define INIT_CALLS_LEVEL(level) \ VMLINUX_SYMBOL(__initcall##level##_start) = .; \ - *(.initcall##level##.init) \ - *(.initcall##level##s.init) \ + KEEP(*(.initcall##level##.init)) \ + KEEP(*(.initcall##level##s.init)) \ #define INIT_CALLS \ VMLINUX_SYMBOL(__initcall_start) = .; \ - *(.initcallearly.init) \ + KEEP(*(.initcallearly.init)) \ INIT_CALLS_LEVEL(0) \ INIT_CALLS_LEVEL(1) \ INIT_CALLS_LEVEL(2) \ @@ -695,21 +701,21 @@ #define CON_INITCALL \ VMLINUX_SYMBOL(__con_initcall_start) = .; \ - *(.con_initcall.init) \ + KEEP(*(.con_initcall.init)) \ VMLINUX_SYMBOL(__con_initcall_end) = .; #define SECURITY_INITCALL \ VMLINUX_SYMBOL(__security_initcall_start) = .; \ - *(.security_initcall.init) \ + KEEP(*(.security_initcall.init)) \ VMLINUX_SYMBOL(__security_initcall_end) = .; #ifdef CONFIG_BLK_DEV_INITRD #define INIT_RAM_FS \ . = ALIGN(4); \ VMLINUX_SYMBOL(__initramfs_start) = .; \ - *(.init.ramfs) \ + KEEP(*(.init.ramfs)) \ . = ALIGN(8); \ - *(.init.ramfs.info) + KEEP(*(.init.ramfs.info)) #else #define INIT_RAM_FS #endif diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 1bb9548427250..86130cded1104 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -182,6 +182,29 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); # define unreachable() do { } while (1) #endif +/* + * KENTRY - kernel entry point + * This can be used to annotate symbols (functions or data) that are used + * without their linker symbol being referenced explicitly. For example, + * interrupt vector handlers, or functions in the kernel image that are found + * programatically. + * + * Not required for symbols exported with EXPORT_SYMBOL, or initcalls. Those + * are handled in their own way (with KEEP() in linker scripts). + * + * KENTRY can be avoided if the symbols in question are marked as KEEP() in the + * linker script. For example an architecture could KEEP() its entire + * boot/exception vector code rather than annotate each function and data. + */ +#ifndef KENTRY +# define KENTRY(sym) \ + extern typeof(sym) sym; \ + static const unsigned long __kentry_##sym \ + __used \ + __attribute__((section("___kentry" "+" #sym ), used)) \ + = (unsigned long)&sym; +#endif + #ifndef RELOC_HIDE # define RELOC_HIDE(ptr, off) \ ({ unsigned long __ptr; \ diff --git a/include/linux/export.h b/include/linux/export.h index c565f87f005e9..337cb90f36687 100644 --- a/include/linux/export.h +++ b/include/linux/export.h @@ -1,5 +1,6 @@ #ifndef _LINUX_EXPORT_H #define _LINUX_EXPORT_H + /* * Export symbols from the kernel to modules. Forked from module.h * to reduce the amount of pointless cruft we feed to gcc when only @@ -42,27 +43,26 @@ extern struct module __this_module; #ifdef CONFIG_MODVERSIONS /* Mark the CRC weak since genksyms apparently decides not to * generate a checksums for some symbols */ -#define __CRC_SYMBOL(sym, sec) \ - extern __visible void *__crc_##sym __attribute__((weak)); \ - static const unsigned long __kcrctab_##sym \ - __used \ - __attribute__((section("___kcrctab" sec "+" #sym), unused)) \ +#define __CRC_SYMBOL(sym, sec) \ + extern __visible void *__crc_##sym __attribute__((weak)); \ + static const unsigned long __kcrctab_##sym \ + __used \ + __attribute__((section("___kcrctab" sec "+" #sym), used)) \ = (unsigned long) &__crc_##sym; #else #define __CRC_SYMBOL(sym, sec) #endif /* For every exported symbol, place a struct in the __ksymtab section */ -#define ___EXPORT_SYMBOL(sym, sec) \ - extern typeof(sym) sym; \ - __CRC_SYMBOL(sym, sec) \ - static const char __kstrtab_##sym[] \ - __attribute__((section("__ksymtab_strings"), aligned(1))) \ - = VMLINUX_SYMBOL_STR(sym); \ - extern const struct kernel_symbol __ksymtab_##sym; \ - __visible const struct kernel_symbol __ksymtab_##sym \ - __used \ - __attribute__((section("___ksymtab" sec "+" #sym), unused)) \ +#define ___EXPORT_SYMBOL(sym, sec) \ + extern typeof(sym) sym; \ + __CRC_SYMBOL(sym, sec) \ + static const char __kstrtab_##sym[] \ + __attribute__((section("__ksymtab_strings"), aligned(1))) \ + = VMLINUX_SYMBOL_STR(sym); \ + static const struct kernel_symbol __ksymtab_##sym \ + __used \ + __attribute__((section("___ksymtab" sec "+" #sym), used)) \ = { (unsigned long)&sym, __kstrtab_##sym } #if defined(__KSYM_DEPS__) diff --git a/include/linux/init.h b/include/linux/init.h index 6935d02474aae..e571fec4bb284 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -150,24 +150,8 @@ extern bool initcall_debug; #ifndef __ASSEMBLY__ -#ifdef CONFIG_LTO -/* Work around a LTO gcc problem: when there is no reference to a variable - * in a module it will be moved to the end of the program. This causes - * reordering of initcalls which the kernel does not like. - * Add a dummy reference function to avoid this. The function is - * deleted by the linker. - */ -#define LTO_REFERENCE_INITCALL(x) \ - ; /* yes this is needed */ \ - static __used __exit void *reference_##x(void) \ - { \ - return &x; \ - } -#else -#define LTO_REFERENCE_INITCALL(x) -#endif - -/* initcalls are now grouped by functionality into separate +/* + * initcalls are now grouped by functionality into separate * subsections. Ordering inside the subsections is determined * by link order. * For backwards compatibility, initcall() puts the call in @@ -175,12 +159,16 @@ extern bool initcall_debug; * * The `id' arg to __define_initcall() is needed so that multiple initcalls * can point at the same handler without causing duplicate-symbol build errors. + * + * Initcalls are run by placing pointers in initcall sections that the + * kernel iterates at runtime. The linker can do dead code / data elimination + * and remove that completely, so the initcall sections have to be marked + * as KEEP() in the linker script. */ #define __define_initcall(fn, id) \ static initcall_t __initcall_##fn##id __used \ - __attribute__((__section__(".initcall" #id ".init"))) = fn; \ - LTO_REFERENCE_INITCALL(__initcall_##fn##id) + __attribute__((__section__(".initcall" #id ".init"))) = fn; /* * Early initcalls run before initializing SMP. @@ -216,15 +204,15 @@ extern bool initcall_debug; #define __initcall(fn) device_initcall(fn) -#define __exitcall(fn) \ +#define __exitcall(fn) \ static exitcall_t __exitcall_##fn __exit_call = fn -#define console_initcall(fn) \ - static initcall_t __initcall_##fn \ +#define console_initcall(fn) \ + static initcall_t __initcall_##fn \ __used __section(.con_initcall.init) = fn -#define security_initcall(fn) \ - static initcall_t __initcall_##fn \ +#define security_initcall(fn) \ + static initcall_t __initcall_##fn \ __used __section(.security_initcall.init) = fn struct obs_kernel_param { diff --git a/init/Makefile b/init/Makefile index 7bc47ee31c369..c4fb45525d088 100644 --- a/init/Makefile +++ b/init/Makefile @@ -2,6 +2,8 @@ # Makefile for the linux kernel. # +ccflags-y := -fno-function-sections -fno-data-sections + obj-y := main.o version.o mounts.o ifneq ($(CONFIG_BLK_DEV_INITRD),y) obj-y += noinitramfs.o -- GitLab From fbe6e37dab974dd0fc3660c001895f7bfd771c9a Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 24 Aug 2016 22:29:21 +1000 Subject: [PATCH 0058/1167] kbuild: add arch specific post-link Makefile Allow architectures to create arch/xxx/Makefile.postlink with targets for vmlinux, modules.ko, and clean, which will be invoked after final linking of vmlinux and modules. powerpc will use this to check vmlinux linker relocations for sanity, and may use it to fix up alternate instruction patch branch addresses. Signed-off-by: Nicholas Piggin Signed-off-by: Michal Marek --- Documentation/kbuild/makefiles.txt | 16 ++++++++++++++++ Makefile | 10 +++++++--- scripts/Makefile.modpost | 14 +++++++++----- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 385a5ef41c17b..9b9c4797fc556 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -41,6 +41,7 @@ This document describes the Linux kernel Makefiles. --- 6.8 Custom kbuild commands --- 6.9 Preprocessing linker scripts --- 6.10 Generic header files + --- 6.11 Post-link pass === 7 Kbuild syntax for exported headers --- 7.1 header-y @@ -1237,6 +1238,21 @@ When kbuild executes, the following steps are followed (roughly): to list the file in the Kbuild file. See "7.4 generic-y" for further info on syntax etc. +--- 6.11 Post-link pass + + If the file arch/xxx/Makefile.postlink exists, this makefile + will be invoked for post-link objects (vmlinux and modules.ko) + for architectures to run post-link passes on. Must also handle + the clean target. + + This pass runs after kallsyms generation. If the architecture + needs to modify symbol locations, rather than manipulate the + kallsyms, it may be easier to add another postlink target for + .tmp_vmlinux? targets to be called from link-vmlinux.sh. + + For example, powerpc uses this to check relocation sanity of + the linked vmlinux file. + === 7 Kbuild syntax for exported headers The kernel includes a set of headers that is exported to userspace. diff --git a/Makefile b/Makefile index 6d40f3a3a8cce..83dae63df91a5 100644 --- a/Makefile +++ b/Makefile @@ -957,9 +957,12 @@ endif include/generated/autoksyms.h: FORCE $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh true -# Final link of vmlinux - cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -quiet_cmd_link-vmlinux = LINK $@ +ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) + +# Final link of vmlinux with optional arch pass after final link + cmd_link-vmlinux = \ + $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) ; \ + $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) vmlinux: scripts/link-vmlinux.sh vmlinux_prereq $(vmlinux-deps) FORCE +$(call if_changed,link-vmlinux) @@ -1286,6 +1289,7 @@ $(clean-dirs): vmlinuxclean: $(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-vmlinux.sh clean + $(Q)$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) clean) clean: archclean vmlinuxclean diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 1366a94b6c395..16923ba4b5b10 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -115,14 +115,18 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE targets += $(modules:.ko=.mod.o) -# Step 6), final link of the modules +ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) + +# Step 6), final link of the modules with optional arch pass after final link quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ - $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ - -o $@ $(filter-out FORCE,$^) + cmd_ld_ko_o = \ + $(LD) -r $(LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ + -o $@ $(filter-out FORCE,$^) ; \ + $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) $(modules): %.ko :%.o %.mod.o FORCE - $(call if_changed,ld_ko_o) + +$(call if_changed,ld_ko_o) targets += $(modules) -- GitLab From 0ce1b18c42a5b1613ad84d3bf93ee4f5bb3f8b33 Mon Sep 17 00:00:00 2001 From: Shaun Tancheff Date: Fri, 9 Sep 2016 11:44:19 -0500 Subject: [PATCH 0059/1167] libata: Some drives failing on SCT Write Same Restrict support SCT Write Same to devices which also support ZAC where support is required. Reported-by: Mike Krinkin Signed-off-by: Shaun Tancheff Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 2f5487f02de14..9cceb4a875a58 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3562,9 +3562,9 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) supported = 3; break; case WRITE_SAME_16: - if (ata_id_sct_write_same(dev->id)) - supported = 3; - break; + if (!ata_id_sct_write_same(dev->id)) + break; + /* fallthrough: if SCT ... only enable for ZBC */ case ZBC_IN: case ZBC_OUT: if (ata_id_zoned_cap(dev->id) || -- GitLab From 085354f907969fb3ee33f236368f6e1dd4c74d62 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 10 Sep 2016 16:21:34 -0400 Subject: [PATCH 0060/1167] alpha: get rid of tail-zeroing in __copy_user() ... and adjust copy_from_user() accordingly Signed-off-by: Al Viro --- arch/alpha/include/asm/uaccess.h | 9 +++++---- arch/alpha/lib/copy_user.S | 16 +--------------- arch/alpha/lib/ev6-copy_user.S | 23 +---------------------- 3 files changed, 7 insertions(+), 41 deletions(-) diff --git a/arch/alpha/include/asm/uaccess.h b/arch/alpha/include/asm/uaccess.h index 466e42e96bfaf..94f587535deed 100644 --- a/arch/alpha/include/asm/uaccess.h +++ b/arch/alpha/include/asm/uaccess.h @@ -396,11 +396,12 @@ copy_to_user(void __user *to, const void *from, long n) extern inline long copy_from_user(void *to, const void __user *from, long n) { + long res = n; if (likely(__access_ok((unsigned long)from, n, get_fs()))) - n = __copy_tofrom_user_nocheck(to, (__force void *)from, n); - else - memset(to, 0, n); - return n; + res = __copy_from_user_inatomic(to, from, n); + if (unlikely(res)) + memset(to + (n - res), 0, res); + return res; } extern void __do_clear_user(void); diff --git a/arch/alpha/lib/copy_user.S b/arch/alpha/lib/copy_user.S index 6f3fab9eb4344..ac9c3766ba8cb 100644 --- a/arch/alpha/lib/copy_user.S +++ b/arch/alpha/lib/copy_user.S @@ -124,22 +124,8 @@ $65: bis $31,$31,$0 $41: $35: -$exitout: - ret $31,($28),1 - $exitin: - /* A stupid byte-by-byte zeroing of the rest of the output - buffer. This cures security holes by never leaving - random kernel data around to be copied elsewhere. */ - - mov $0,$1 -$101: - EXO ( ldq_u $2,0($6) ) - subq $1,1,$1 - mskbl $2,$6,$2 - EXO ( stq_u $2,0($6) ) - addq $6,1,$6 - bgt $1,$101 +$exitout: ret $31,($28),1 .end __copy_user diff --git a/arch/alpha/lib/ev6-copy_user.S b/arch/alpha/lib/ev6-copy_user.S index db42ffe9c350b..c4d0689c3d26e 100644 --- a/arch/alpha/lib/ev6-copy_user.S +++ b/arch/alpha/lib/ev6-copy_user.S @@ -227,33 +227,12 @@ $dirtyentry: bgt $0,$onebyteloop # U .. .. .. : U L U L $zerolength: +$exitin: $exitout: # Destination for exception recovery(?) nop # .. .. .. E nop # .. .. E .. nop # .. E .. .. ret $31,($28),1 # L0 .. .. .. : L U L U -$exitin: - - /* A stupid byte-by-byte zeroing of the rest of the output - buffer. This cures security holes by never leaving - random kernel data around to be copied elsewhere. */ - - nop - nop - nop - mov $0,$1 - -$101: - EXO ( stb $31,0($6) ) # L - subq $1,1,$1 # E - addq $6,1,$6 # E - bgt $1,$101 # U - - nop - nop - nop - ret $31,($28),1 # L0 - .end __copy_user -- GitLab From 7798bf2140ebcc36eafec6a4194fffd8d585d471 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 10 Sep 2016 16:31:04 -0400 Subject: [PATCH 0061/1167] arc: don't leak bits of kernel stack into coredump On faulting sigreturn we do get SIGSEGV, all right, but anything we'd put into pt_regs could end up in the coredump. And since __copy_from_user() never zeroed on arc, we'd better bugger off on its failure without copying random uninitialized bits of kernel stack into pt_regs... Cc: stable@vger.kernel.org Signed-off-by: Al Viro --- arch/arc/kernel/signal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c index 6cb3736b6b836..d347bbc086fed 100644 --- a/arch/arc/kernel/signal.c +++ b/arch/arc/kernel/signal.c @@ -107,13 +107,13 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf) struct user_regs_struct uregs; err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); - if (!err) - set_current_blocked(&set); - err |= __copy_from_user(&uregs.scratch, &(sf->uc.uc_mcontext.regs.scratch), sizeof(sf->uc.uc_mcontext.regs.scratch)); + if (err) + return err; + set_current_blocked(&set); regs->bta = uregs.scratch.bta; regs->lp_start = uregs.scratch.lp_start; regs->lp_end = uregs.scratch.lp_end; @@ -138,7 +138,7 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf) regs->r0 = uregs.scratch.r0; regs->sp = uregs.scratch.sp; - return err; + return 0; } static inline int is_do_ss_needed(unsigned int magic) -- GitLab From 91344493b7da9487a8dbc1109d7486e51c8e5235 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 10 Sep 2016 16:44:03 -0400 Subject: [PATCH 0062/1167] arm: don't zero in __copy_from_user_inatomic()/__copy_from_user() adjust copy_from_user(), obviously Signed-off-by: Al Viro --- arch/arm/include/asm/uaccess.h | 11 ++++++----- arch/arm/lib/copy_from_user.S | 9 +++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index a93c0f99acf77..1f59ea051bab8 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -533,11 +533,12 @@ __clear_user(void __user *addr, unsigned long n) static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { - if (access_ok(VERIFY_READ, from, n)) - n = __copy_from_user(to, from, n); - else /* security hole - plug it */ - memset(to, 0, n); - return n; + unsigned long res = n; + if (likely(access_ok(VERIFY_READ, from, n))) + res = __copy_from_user(to, from, n); + if (unlikely(res)) + memset(to + (n - res), 0, res); + return res; } static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index 1512bebfbf1b1..7a4b060490012 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S @@ -98,12 +98,9 @@ ENDPROC(arm_copy_from_user) .pushsection .fixup,"ax" .align 0 copy_abort_preamble - ldmfd sp!, {r1, r2} - sub r3, r0, r1 - rsb r1, r3, r2 - str r1, [sp] - bl __memzero - ldr r0, [sp], #4 + ldmfd sp!, {r1, r2, r3} + sub r0, r0, r1 + rsb r0, r0, r2 copy_abort_end .popsection -- GitLab From 4855bd255f9fb429d296dc3c620f1b563d20353e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 10 Sep 2016 16:50:00 -0400 Subject: [PATCH 0063/1167] arm64: don't zero in __copy_from_user{,_inatomic} Signed-off-by: Al Viro --- arch/arm64/include/asm/uaccess.h | 10 ++++++---- arch/arm64/lib/copy_from_user.S | 7 +------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index c47257c91b77e..bcaf6fba1b65b 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -278,14 +278,16 @@ static inline unsigned long __must_check __copy_to_user(void __user *to, const v static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { + unsigned long res = n; kasan_check_write(to, n); if (access_ok(VERIFY_READ, from, n)) { check_object_size(to, n, false); - n = __arch_copy_from_user(to, from, n); - } else /* security hole - plug it */ - memset(to, 0, n); - return n; + res = __arch_copy_from_user(to, from, n); + } + if (unlikely(res)) + memset(to + (n - res), 0, res); + return res; } static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index 0b90497d4424c..4fd67ea03bb05 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S @@ -79,11 +79,6 @@ ENDPROC(__arch_copy_from_user) .section .fixup,"ax" .align 2 -9998: - sub x0, end, dst -9999: - strb wzr, [dst], #1 // zero remaining buffer space - cmp dst, end - b.lo 9999b +9998: sub x0, end, dst // bytes not copied ret .previous -- GitLab From b065444286bed7ec49ee81c593a46f3031fbfc83 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 10 Sep 2016 18:53:30 -0400 Subject: [PATCH 0064/1167] blackfin: no access_ok() for __copy_{to,from}_user() callers have checked that already Signed-off-by: Al Viro --- arch/blackfin/include/asm/uaccess.h | 32 ++++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h index 0a2a70096d8b2..0eff88aa6d6ae 100644 --- a/arch/blackfin/include/asm/uaccess.h +++ b/arch/blackfin/include/asm/uaccess.h @@ -163,18 +163,29 @@ static inline int bad_user_access_length(void) : "a" (__ptr(ptr))); \ }) -#define __copy_from_user(to, from, n) copy_from_user(to, from, n) -#define __copy_to_user(to, from, n) copy_to_user(to, from, n) #define __copy_to_user_inatomic __copy_to_user #define __copy_from_user_inatomic __copy_from_user +static inline unsigned long __must_check +__copy_from_user(void *to, const void __user *from, unsigned long n) +{ + memcpy(to, (const void __force *)from, n); + return 0; +} + +static inline unsigned long __must_check +__copy_to_user(void __user *to, const void *from, unsigned long n) +{ + memcpy((void __force *)to, from, n); + SSYNC(); + return 0; +} + static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { - if (likely(access_ok(VERIFY_READ, from, n))) { - memcpy(to, (const void __force *)from, n); - return 0; - } + if (likely(access_ok(VERIFY_READ, from, n))) + return __copy_from_user(to, from, n); memset(to, 0, n); return n; } @@ -182,12 +193,9 @@ copy_from_user(void *to, const void __user *from, unsigned long n) static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) { - if (access_ok(VERIFY_WRITE, to, n)) - memcpy((void __force *)to, from, n); - else - return n; - SSYNC(); - return 0; + if (likely(access_ok(VERIFY_WRITE, to, n))) + return __copy_to_user(to, from, n); + return n; } /* -- GitLab From 8b326c61de08f5ca4bc454a168f19e7e43c4cc2a Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 16 Sep 2016 14:12:11 +0200 Subject: [PATCH 0065/1167] ovl: copy_up_xattr(): use strnlen Be defensive about what underlying fs provides us in the returned xattr list buffer. strlen() may overrun the buffer, so use strnlen() and WARN if the contents are not properly null terminated. Signed-off-by: Miklos Szeredi Cc: --- fs/overlayfs/copy_up.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 43fdc2765aea6..abadbc30e013a 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -57,6 +57,7 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new) ssize_t list_size, size, value_size = 0; char *buf, *name, *value = NULL; int uninitialized_var(error); + size_t slen; if (!old->d_inode->i_op->getxattr || !new->d_inode->i_op->getxattr) @@ -79,7 +80,16 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new) goto out; } - for (name = buf; name < (buf + list_size); name += strlen(name) + 1) { + for (name = buf; list_size; name += slen) { + slen = strnlen(name, list_size) + 1; + + /* underlying fs providing us with an broken xattr list? */ + if (WARN_ON(slen > list_size)) { + error = -EIO; + break; + } + list_size -= slen; + if (ovl_is_private_xattr(name)) continue; retry: -- GitLab From 2b6bc7f48d34a6043915beddbf53b981603737c8 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 16 Sep 2016 14:12:11 +0200 Subject: [PATCH 0066/1167] ovl: lookup: do getxattr with mounter's permission The getxattr() in ovl_is_opaquedir() was missed when converting all operations on underlying fs to be done under mounter's permission. This patch fixes this by moving the ovl_override_creds()/revert_creds() out from ovl_lookup_real() to ovl_lookup(). Also convert to using vfs_getxattr() instead of directly calling i_op->getxattr(). Signed-off-by: Miklos Szeredi --- fs/overlayfs/super.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index e2a94a26767ba..8ccebaf64c5b3 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -273,12 +273,11 @@ static bool ovl_is_opaquedir(struct dentry *dentry) { int res; char val; - struct inode *inode = dentry->d_inode; - if (!S_ISDIR(inode->i_mode) || !inode->i_op->getxattr) + if (!d_is_dir(dentry)) return false; - res = inode->i_op->getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1); + res = vfs_getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1); if (res == 1 && val == 'y') return true; @@ -419,16 +418,12 @@ static bool ovl_dentry_weird(struct dentry *dentry) DCACHE_OP_COMPARE); } -static inline struct dentry *ovl_lookup_real(struct super_block *ovl_sb, - struct dentry *dir, +static inline struct dentry *ovl_lookup_real(struct dentry *dir, const struct qstr *name) { - const struct cred *old_cred; struct dentry *dentry; - old_cred = ovl_override_creds(ovl_sb); dentry = lookup_one_len_unlocked(name->name, dir, name->len); - revert_creds(old_cred); if (IS_ERR(dentry)) { if (PTR_ERR(dentry) == -ENOENT) @@ -469,6 +464,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct ovl_entry *oe; + const struct cred *old_cred; struct ovl_entry *poe = dentry->d_parent->d_fsdata; struct path *stack = NULL; struct dentry *upperdir, *upperdentry = NULL; @@ -479,9 +475,10 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int i; int err; + old_cred = ovl_override_creds(dentry->d_sb); upperdir = ovl_upperdentry_dereference(poe); if (upperdir) { - this = ovl_lookup_real(dentry->d_sb, upperdir, &dentry->d_name); + this = ovl_lookup_real(upperdir, &dentry->d_name); err = PTR_ERR(this); if (IS_ERR(this)) goto out; @@ -514,8 +511,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, bool opaque = false; struct path lowerpath = poe->lowerstack[i]; - this = ovl_lookup_real(dentry->d_sb, - lowerpath.dentry, &dentry->d_name); + this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name); err = PTR_ERR(this); if (IS_ERR(this)) { /* @@ -588,6 +584,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ovl_copyattr(realdentry->d_inode, inode); } + revert_creds(old_cred); oe->opaque = upperopaque; oe->__upperdentry = upperdentry; memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr); @@ -606,6 +603,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, out_put_upper: dput(upperdentry); out: + revert_creds(old_cred); return ERR_PTR(err); } -- GitLab From 8eac98b8beb4711c4ab61822cac077fd6660e820 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Tue, 6 Sep 2016 13:40:32 -0400 Subject: [PATCH 0067/1167] ovl: during copy up, switch to mounter's creds early Now, we have the notion that copy up of a file is done with the creds of mounter of overlay filesystem (as opposed to task). Right now before we switch creds, we do some vfs_getattr() operations in the context of task and that itself can fail. We should do that getattr() using the creds of mounter instead. So this patch switches to mounter's creds early during copy up process so that even vfs_getattr() is done with mounter's creds. Do not call revert_creds() unless we have already called ovl_override_creds(). [Reported by Arnd Bergmann] Signed-off-by: Vivek Goyal Signed-off-by: Miklos Szeredi --- fs/overlayfs/copy_up.c | 9 +++------ fs/overlayfs/inode.c | 13 ++++++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index abadbc30e013a..796d06fafd091 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -348,7 +348,6 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, struct path parentpath; struct dentry *upperdir; struct dentry *upperdentry; - const struct cred *old_cred; char *link = NULL; if (WARN_ON(!workdir)) @@ -369,8 +368,6 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, return PTR_ERR(link); } - old_cred = ovl_override_creds(dentry->d_sb); - err = -EIO; if (lock_rename(workdir, upperdir) != NULL) { pr_err("overlayfs: failed to lock workdir+upperdir\n"); @@ -391,7 +388,6 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, } out_unlock: unlock_rename(workdir, upperdir); - revert_creds(old_cred); if (link) free_page((unsigned long) link); @@ -401,9 +397,9 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, int ovl_copy_up(struct dentry *dentry) { - int err; + int err = 0; + const struct cred *old_cred = ovl_override_creds(dentry->d_sb); - err = 0; while (!err) { struct dentry *next; struct dentry *parent; @@ -435,6 +431,7 @@ int ovl_copy_up(struct dentry *dentry) dput(parent); dput(next); } + revert_creds(old_cred); return err; } diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index c75625c1efa36..ce5d7dfaf7693 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -19,6 +19,7 @@ static int ovl_copy_up_truncate(struct dentry *dentry) struct dentry *parent; struct kstat stat; struct path lowerpath; + const struct cred *old_cred; parent = dget_parent(dentry); err = ovl_copy_up(parent); @@ -26,12 +27,14 @@ static int ovl_copy_up_truncate(struct dentry *dentry) goto out_dput_parent; ovl_path_lower(dentry, &lowerpath); - err = vfs_getattr(&lowerpath, &stat); - if (err) - goto out_dput_parent; - stat.size = 0; - err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat); + old_cred = ovl_override_creds(dentry->d_sb); + err = vfs_getattr(&lowerpath, &stat); + if (!err) { + stat.size = 0; + err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat); + } + revert_creds(old_cred); out_dput_parent: dput(parent); -- GitLab From 33c45ef8adc8a7cf781b2566d50e6ea8e97b3596 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Mon, 19 Sep 2016 12:02:50 +0200 Subject: [PATCH 0068/1167] ARM: mvebu: Select corediv clk for all mvebu v7 SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the commit bd3677ff31a3 ("clk: mvebu: Remove corediv clock from Armada XP"), the corediv clk is no more selected for Armada XP, however this clock is used for Armada XP using the compatible armada-370-corediv-clock. While since commit 1594d568c6e3 ("clk: mvebu: Move corediv config to mvebu config") Armada 38x and Armada 375 got corediv support again, not only Armada XP was missed but also Armada 39x. Actually all the SoC selecting MVEBU_V7 config need this clock: git grep "\-corediv-clock" arch/arm/boot/dts arch/arm/boot/dts/armada-370-xp.dtsi: compatible = "marvell,armada-370-corediv-clock"; arch/arm/boot/dts/armada-375.dtsi: compatible = "marvell,armada-375-corediv-clock"; arch/arm/boot/dts/armada-38x.dtsi: compatible = "marvell,armada-380-corediv-clock"; arch/arm/boot/dts/armada-39x.dtsi: compatible = "marvell,armada-390-corediv-clock" This commit now fixes this behavior by letting MVEBU_V7 select MVEBU_CLK_COREDIV. Fixes: bd3677ff31a3 ("clk: mvebu: Remove corediv clock from Armada XP") Cc: stable@vger.kernel.org Reported-by: Uwe Kleine-König Acked-by: Uwe Kleine-König Signed-off-by: Gregory CLEMENT --- arch/arm/mach-mvebu/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index f9b6bd306cfea..541647f571925 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -23,6 +23,7 @@ config MACH_MVEBU_V7 select CACHE_L2X0 select ARM_CPU_SUSPEND select MACH_MVEBU_ANY + select MVEBU_CLK_COREDIV config MACH_ARMADA_370 bool "Marvell Armada 370 boards" @@ -32,7 +33,6 @@ config MACH_ARMADA_370 select CPU_PJ4B select MACH_MVEBU_V7 select PINCTRL_ARMADA_370 - select MVEBU_CLK_COREDIV help Say 'Y' here if you want your kernel to support boards based on the Marvell Armada 370 SoC with device tree. @@ -50,7 +50,6 @@ config MACH_ARMADA_375 select HAVE_SMP select MACH_MVEBU_V7 select PINCTRL_ARMADA_375 - select MVEBU_CLK_COREDIV help Say 'Y' here if you want your kernel to support boards based on the Marvell Armada 375 SoC with device tree. @@ -68,7 +67,6 @@ config MACH_ARMADA_38X select HAVE_SMP select MACH_MVEBU_V7 select PINCTRL_ARMADA_38X - select MVEBU_CLK_COREDIV help Say 'Y' here if you want your kernel to support boards based on the Marvell Armada 380/385 SoC with device tree. -- GitLab From 970fc7f4afd52d638d88aeda985ea03ccd33acee Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Thu, 15 Sep 2016 09:38:16 +0530 Subject: [PATCH 0069/1167] rtc: cmos: Initialize hpet timer before irq is registered We have observed on few x86 machines with rtc-cmos device that hpet_rtc_interrupt() is called just after irq registration and before cmos_do_probe() could call hpet_rtc_timer_init(). So, neither hpet_default_delta nor hpet_t1_cmp is initialized by the time interrupt is raised in the given situation, and this results in NMI watchdog LOCKUP. It has only been observed sporadically on kdump secondary kernels. See the call trace: ---<-snip->--- [ 27.913194] Kernel panic - not syncing: Watchdog detected hard LOCKUP on cpu 0 [ 27.915371] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.10.0-342.el7.x86_64 #1 [ 27.917503] Hardware name: HP ProLiant DL160 Gen8, BIOS J03 02/10/2014 [ 27.919455] ffffffff8186a728 0000000059c82488 ffff880034e05af0 ffffffff81637bd4 [ 27.921870] ffff880034e05b70 ffffffff8163144a 0000000000000010 ffff880034e05b80 [ 27.924257] ffff880034e05b20 0000000059c82488 0000000000000000 0000000000000000 [ 27.926599] Call Trace: [ 27.927352] [] dump_stack+0x19/0x1b [ 27.929080] [] panic+0xd8/0x1e7 [ 27.930588] [] ? restart_watchdog_hrtimer+0x50/0x50 [ 27.932502] [] watchdog_overflow_callback+0xc2/0xd0 [ 27.934427] [] __perf_event_overflow+0xa1/0x250 [ 27.936232] [] perf_event_overflow+0x14/0x20 [ 27.937957] [] intel_pmu_handle_irq+0x1e8/0x470 [ 27.939799] [] perf_event_nmi_handler+0x2b/0x50 [ 27.941649] [] nmi_handle.isra.0+0x69/0xb0 [ 27.943348] [] do_nmi+0x169/0x340 [ 27.944802] [] end_repeat_nmi+0x1e/0x2e [ 27.946424] [] ? hpet_rtc_interrupt+0x85/0x380 [ 27.948197] [] ? hpet_rtc_interrupt+0x85/0x380 [ 27.949992] [] ? hpet_rtc_interrupt+0x85/0x380 [ 27.951816] <> [] ? run_timer_softirq+0x43/0x340 [ 27.954114] [] handle_irq_event_percpu+0x3e/0x1e0 [ 27.955962] [] handle_irq_event+0x3d/0x60 [ 27.957635] [] handle_edge_irq+0x77/0x130 [ 27.959332] [] handle_irq+0xbf/0x150 [ 27.960949] [] do_IRQ+0x4f/0xf0 [ 27.962434] [] common_interrupt+0x6d/0x6d [ 27.964101] [] ? _raw_spin_unlock_irqrestore+0x1b/0x40 [ 27.966308] [] __setup_irq+0x2a7/0x570 [ 28.067859] [] ? hpet_cpuhp_notify+0x140/0x140 [ 28.069709] [] request_threaded_irq+0xcc/0x170 [ 28.071585] [] cmos_do_probe+0x1e6/0x450 [ 28.073240] [] ? cmos_do_probe+0x450/0x450 [ 28.074911] [] cmos_pnp_probe+0xbb/0xc0 [ 28.076533] [] pnp_device_probe+0x65/0xd0 [ 28.078198] [] driver_probe_device+0x87/0x390 [ 28.079971] [] __driver_attach+0x93/0xa0 [ 28.081660] [] ? __device_attach+0x40/0x40 [ 28.083662] [] bus_for_each_dev+0x73/0xc0 [ 28.085370] [] driver_attach+0x1e/0x20 [ 28.086974] [] bus_add_driver+0x200/0x2d0 [ 28.088634] [] ? rtc_sysfs_init+0xe/0xe [ 28.090349] [] driver_register+0x64/0xf0 [ 28.091989] [] pnp_register_driver+0x20/0x30 [ 28.093707] [] cmos_init+0x11/0x71 ---<-snip->--- This patch moves hpet_rtc_timer_init() before IRQ registration, so that we can gracefully handle such spurious interrupts. It also masks HPET RTC interrupts, in case IRQ registration fails. We were able to reproduce the problem in maximum 15 trials of kdump secondary kernel boot on an hp-dl160gen8 FCoE host machine without this patch. However, more than 35 trials went fine after applying this patch. Suggested-by: Thomas Gleixner Signed-off-by: Pratyush Anand Acked-by: Thomas Gleixner Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 43745cac0141a..fddde655cbd4f 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -707,6 +707,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) goto cleanup1; } + hpet_rtc_timer_init(); + if (is_valid_irq(rtc_irq)) { irq_handler_t rtc_cmos_int_handler; @@ -714,6 +716,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) rtc_cmos_int_handler = hpet_rtc_interrupt; retval = hpet_register_irq_handler(cmos_interrupt); if (retval) { + hpet_mask_rtc_irq_bit(RTC_IRQMASK); dev_warn(dev, "hpet_register_irq_handler " " failed in rtc_init()."); goto cleanup1; @@ -729,7 +732,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) goto cleanup1; } } - hpet_rtc_timer_init(); /* export at least the first block of NVRAM */ nvram.size = address_space - NVRAM_OFFSET; -- GitLab From 51227bf52008bd4c4c50da4b749bbc6e7bbbca52 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Tue, 6 Sep 2016 19:41:11 +0200 Subject: [PATCH 0070/1167] arm64: dts: marvell: fix clocksource for CP110 master SPI0 I2C and SPI interfaces share common clock trees within the CP110 HW block. It occurred that SPI0 interface has wrong clock assignment in the device tree, which is fixed in this commit to a proper value. Fixes: 728dacc7f4dd ("arm64: dts: marvell: initial DT description of ...") Signed-off-by: Marcin Wojtas CC: v4.7+ Signed-off-by: Gregory CLEMENT --- arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi index da31bbbbb59ee..399271853aad9 100644 --- a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi @@ -131,7 +131,7 @@ #address-cells = <0x1>; #size-cells = <0x0>; cell-index = <1>; - clocks = <&cpm_syscon0 0 3>; + clocks = <&cpm_syscon0 1 21>; status = "disabled"; }; -- GitLab From 3409f9ab71d7db96eed849f49a6c8116c62dc251 Mon Sep 17 00:00:00 2001 From: Aleksander Alekseev Date: Thu, 18 Aug 2016 12:36:53 +0300 Subject: [PATCH 0071/1167] kselftest: kselftest documentation improvement Suggested patch solves two issues: 1) Currently documentation is unclear whether `make kselftest` should be run before or after kernel was installed and booted. `make help` gives a clear answer on that: "kselftest - Build and run kernel selftest (run as root). Build, install, and boot kernel before running kselftest on it." 2) Documentation states that `make kselftest` executes "unit" tests. Technically it's not a _unit_ test if it requires to install an application first. It's either integration or system test. To not to confuse a user I suggest not to use a word "unit". Signed-off-by: Aleksander Alekseev Acked-by: Michael Ellerman Signed-off-by: Shuah Khan --- Documentation/kselftest.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/kselftest.txt b/Documentation/kselftest.txt index 979eacae243d1..54bee77fa7285 100644 --- a/Documentation/kselftest.txt +++ b/Documentation/kselftest.txt @@ -1,8 +1,9 @@ Linux Kernel Selftests The kernel contains a set of "self tests" under the tools/testing/selftests/ -directory. These are intended to be small unit tests to exercise individual -code paths in the kernel. +directory. These are intended to be small tests to exercise individual code +paths in the kernel. Tests are intended to be run after building, installing +and booting a kernel. On some systems, hot-plug tests could hang forever waiting for cpu and memory to be ready to be offlined. A special hot-plug target is created -- GitLab From 0ad46becb5c03e7d2464f00b2a1cd460a9c2b3c0 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 12 Aug 2016 22:49:59 +0200 Subject: [PATCH 0072/1167] selftests/zram: replace ZRAM_LZ4_COMPRESS Since commit ce1ed9f98e88 ("zram: delete custom lzo/lz4") we need CONFIG_CRYPTO_LZ4=y instead of CONFIG_ZRAM_LZ4_COMPRESS Signed-off-by: Fabian Frederick Signed-off-by: Shuah Khan --- tools/testing/selftests/zram/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/zram/README b/tools/testing/selftests/zram/README index eb17917c8a3a5..7972cc5124080 100644 --- a/tools/testing/selftests/zram/README +++ b/tools/testing/selftests/zram/README @@ -13,7 +13,7 @@ Statistics for individual zram devices are exported through sysfs nodes at Kconfig required: CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_CRYPTO_LZ4=y CONFIG_ZPOOL=y CONFIG_ZSMALLOC=y -- GitLab From c3cb83560daae4c619d1034eb98c1a40ee896387 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 9 Aug 2016 12:11:26 +0200 Subject: [PATCH 0073/1167] selftests/timers: Add missing error code assignment before test In order to work, the 'err' return value has to be updated otherwise the test can never be true. Signed-off-by: Christophe JAILLET Acked-by: John Stultz Signed-off-by: Shuah Khan --- tools/testing/selftests/timers/posix_timers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/timers/posix_timers.c b/tools/testing/selftests/timers/posix_timers.c index 5a246a02dff3c..15cf56d321553 100644 --- a/tools/testing/selftests/timers/posix_timers.c +++ b/tools/testing/selftests/timers/posix_timers.c @@ -122,7 +122,7 @@ static int check_itimer(int which) else if (which == ITIMER_REAL) idle_loop(); - gettimeofday(&end, NULL); + err = gettimeofday(&end, NULL); if (err < 0) { perror("Can't call gettimeofday()\n"); return -1; @@ -175,7 +175,7 @@ static int check_timer_create(int which) user_loop(); - gettimeofday(&end, NULL); + err = gettimeofday(&end, NULL); if (err < 0) { perror("Can't call gettimeofday()\n"); return -1; -- GitLab From 10924bc6448760b355492f05ea414a65d924a72c Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 13 Sep 2016 10:08:36 -0600 Subject: [PATCH 0074/1167] selftests: move dnotify_test from Documentation/filesystems Move dnotify_test.c, Makefile, and .gitignore from Documentation/filesystems to selftests/filesystems. Remove filesystems build target from Documentation/Makefile and update selftests/filesystems/Makefile to work under selftests. dnotify_test will not be run as part of selftests suite and will not be included in install targets. It can be built separately for now. Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/filesystems/Makefile | 5 ----- .../testing/selftests}/filesystems/.gitignore | 0 tools/testing/selftests/filesystems/Makefile | 7 +++++++ .../testing/selftests}/filesystems/dnotify_test.c | 0 5 files changed, 8 insertions(+), 6 deletions(-) delete mode 100644 Documentation/filesystems/Makefile rename {Documentation => tools/testing/selftests}/filesystems/.gitignore (100%) create mode 100644 tools/testing/selftests/filesystems/Makefile rename {Documentation => tools/testing/selftests}/filesystems/dnotify_test.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index de955e151af8e..0473710c09d04 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,3 +1,3 @@ subdir-y := accounting auxdisplay blackfin \ - filesystems filesystems ia64 laptops mic misc-devices \ + ia64 laptops mic misc-devices \ networking pcmcia prctl ptp timers vDSO watchdog diff --git a/Documentation/filesystems/Makefile b/Documentation/filesystems/Makefile deleted file mode 100644 index 883010ce5e35b..0000000000000 --- a/Documentation/filesystems/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# List of programs to build -hostprogs-y := dnotify_test - -# Tell kbuild to always build the programs -always := $(hostprogs-y) diff --git a/Documentation/filesystems/.gitignore b/tools/testing/selftests/filesystems/.gitignore similarity index 100% rename from Documentation/filesystems/.gitignore rename to tools/testing/selftests/filesystems/.gitignore diff --git a/tools/testing/selftests/filesystems/Makefile b/tools/testing/selftests/filesystems/Makefile new file mode 100644 index 0000000000000..0ab11307b4142 --- /dev/null +++ b/tools/testing/selftests/filesystems/Makefile @@ -0,0 +1,7 @@ +TEST_PROGS := dnotify_test +all: $(TEST_PROGS) + +include ../lib.mk + +clean: + rm -fr $(TEST_PROGS) diff --git a/Documentation/filesystems/dnotify_test.c b/tools/testing/selftests/filesystems/dnotify_test.c similarity index 100% rename from Documentation/filesystems/dnotify_test.c rename to tools/testing/selftests/filesystems/dnotify_test.c -- GitLab From 92dd8dd4d07f170db0638a20a8db691262da4e5e Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 13 Sep 2016 11:13:46 -0600 Subject: [PATCH 0075/1167] selftests: move prctl tests from Documentation/prctl Move prctl tests from Documentation/prctl to selftests/prctl. Remove prctl from Makefile to move the test. Update prctl Makefile to work under selftests. prctl will not be run as part of selftests suite and will not be included in install targets. They can be built separately for now. Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/prctl/Makefile | 10 ---------- .../testing/selftests}/prctl/.gitignore | 0 tools/testing/selftests/prctl/Makefile | 15 +++++++++++++++ .../prctl/disable-tsc-ctxt-sw-stress-test.c | 0 .../prctl/disable-tsc-on-off-stress-test.c | 0 .../testing/selftests}/prctl/disable-tsc-test.c | 0 7 files changed, 16 insertions(+), 11 deletions(-) delete mode 100644 Documentation/prctl/Makefile rename {Documentation => tools/testing/selftests}/prctl/.gitignore (100%) create mode 100644 tools/testing/selftests/prctl/Makefile rename {Documentation => tools/testing/selftests}/prctl/disable-tsc-ctxt-sw-stress-test.c (100%) rename {Documentation => tools/testing/selftests}/prctl/disable-tsc-on-off-stress-test.c (100%) rename {Documentation => tools/testing/selftests}/prctl/disable-tsc-test.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index 0473710c09d04..7a28f6c267554 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,3 +1,3 @@ subdir-y := accounting auxdisplay blackfin \ ia64 laptops mic misc-devices \ - networking pcmcia prctl ptp timers vDSO watchdog + networking pcmcia ptp timers vDSO watchdog diff --git a/Documentation/prctl/Makefile b/Documentation/prctl/Makefile deleted file mode 100644 index 44de3080c7f2e..0000000000000 --- a/Documentation/prctl/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -ifndef CROSS_COMPILE -# List of programs to build -hostprogs-$(CONFIG_X86) := disable-tsc-ctxt-sw-stress-test disable-tsc-on-off-stress-test disable-tsc-test -# Tell kbuild to always build the programs -always := $(hostprogs-y) - -HOSTCFLAGS_disable-tsc-ctxt-sw-stress-test.o += -I$(objtree)/usr/include -HOSTCFLAGS_disable-tsc-on-off-stress-test.o += -I$(objtree)/usr/include -HOSTCFLAGS_disable-tsc-test.o += -I$(objtree)/usr/include -endif diff --git a/Documentation/prctl/.gitignore b/tools/testing/selftests/prctl/.gitignore similarity index 100% rename from Documentation/prctl/.gitignore rename to tools/testing/selftests/prctl/.gitignore diff --git a/tools/testing/selftests/prctl/Makefile b/tools/testing/selftests/prctl/Makefile new file mode 100644 index 0000000000000..35aa1c8f2df21 --- /dev/null +++ b/tools/testing/selftests/prctl/Makefile @@ -0,0 +1,15 @@ +ifndef CROSS_COMPILE +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) + +ifeq ($(ARCH),x86) +TEST_PROGS := disable-tsc-ctxt-sw-stress-test disable-tsc-on-off-stress-test \ + disable-tsc-test +all: $(TEST_PROGS) + +include ../lib.mk + +clean: + rm -fr $(TEST_PROGS) +endif +endif diff --git a/Documentation/prctl/disable-tsc-ctxt-sw-stress-test.c b/tools/testing/selftests/prctl/disable-tsc-ctxt-sw-stress-test.c similarity index 100% rename from Documentation/prctl/disable-tsc-ctxt-sw-stress-test.c rename to tools/testing/selftests/prctl/disable-tsc-ctxt-sw-stress-test.c diff --git a/Documentation/prctl/disable-tsc-on-off-stress-test.c b/tools/testing/selftests/prctl/disable-tsc-on-off-stress-test.c similarity index 100% rename from Documentation/prctl/disable-tsc-on-off-stress-test.c rename to tools/testing/selftests/prctl/disable-tsc-on-off-stress-test.c diff --git a/Documentation/prctl/disable-tsc-test.c b/tools/testing/selftests/prctl/disable-tsc-test.c similarity index 100% rename from Documentation/prctl/disable-tsc-test.c rename to tools/testing/selftests/prctl/disable-tsc-test.c -- GitLab From 8dbbf854202610a033a0788c33d8feb1548d3eeb Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 13 Sep 2016 11:30:03 -0600 Subject: [PATCH 0076/1167] selftests: move ptp tests from Documentation/ptp Remove ptp from Makefile to move the test to selftests. Update ptp Makefile to work under selftests. ptp will not be run as part of selftests suite and will not be included in install targets. They can be built separately for now. Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/ptp/Makefile | 8 -------- {Documentation => tools/testing/selftests}/ptp/.gitignore | 0 tools/testing/selftests/ptp/Makefile | 8 ++++++++ {Documentation => tools/testing/selftests}/ptp/testptp.c | 0 {Documentation => tools/testing/selftests}/ptp/testptp.mk | 0 6 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 Documentation/ptp/Makefile rename {Documentation => tools/testing/selftests}/ptp/.gitignore (100%) create mode 100644 tools/testing/selftests/ptp/Makefile rename {Documentation => tools/testing/selftests}/ptp/testptp.c (100%) rename {Documentation => tools/testing/selftests}/ptp/testptp.mk (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index 7a28f6c267554..8cd6d1aaabfaa 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,3 +1,3 @@ subdir-y := accounting auxdisplay blackfin \ ia64 laptops mic misc-devices \ - networking pcmcia ptp timers vDSO watchdog + networking pcmcia timers vDSO watchdog diff --git a/Documentation/ptp/Makefile b/Documentation/ptp/Makefile deleted file mode 100644 index 293d6c09a11ff..0000000000000 --- a/Documentation/ptp/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# List of programs to build -hostprogs-y := testptp - -# Tell kbuild to always build the programs -always := $(hostprogs-y) - -HOSTCFLAGS_testptp.o += -I$(objtree)/usr/include -HOSTLOADLIBES_testptp := -lrt diff --git a/Documentation/ptp/.gitignore b/tools/testing/selftests/ptp/.gitignore similarity index 100% rename from Documentation/ptp/.gitignore rename to tools/testing/selftests/ptp/.gitignore diff --git a/tools/testing/selftests/ptp/Makefile b/tools/testing/selftests/ptp/Makefile new file mode 100644 index 0000000000000..83dd42b2129e9 --- /dev/null +++ b/tools/testing/selftests/ptp/Makefile @@ -0,0 +1,8 @@ +TEST_PROGS := testptp +LDLIBS += -lrt +all: $(TEST_PROGS) + +include ../lib.mk + +clean: + rm -fr $(TEST_PROGS) diff --git a/Documentation/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c similarity index 100% rename from Documentation/ptp/testptp.c rename to tools/testing/selftests/ptp/testptp.c diff --git a/Documentation/ptp/testptp.mk b/tools/testing/selftests/ptp/testptp.mk similarity index 100% rename from Documentation/ptp/testptp.mk rename to tools/testing/selftests/ptp/testptp.mk -- GitLab From f9b6b0ef60349cf1747d8f366f23900671f888c5 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 13 Sep 2016 12:06:20 -0600 Subject: [PATCH 0077/1167] selftests: move vDSO tests from Documentation/vDSO Remove vDSO from Makefile to move the to selftests. Update vDSO Makefile to work under selftests. vDSO will not be run as part of selftests suite and will not be included in install targets. They can be built separately for now. Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/vDSO/Makefile | 17 ---------------- .../testing/selftests}/vDSO/.gitignore | 0 tools/testing/selftests/vDSO/Makefile | 20 +++++++++++++++++++ .../testing/selftests}/vDSO/parse_vdso.c | 0 .../vDSO/vdso_standalone_test_x86.c | 0 .../testing/selftests}/vDSO/vdso_test.c | 0 7 files changed, 21 insertions(+), 18 deletions(-) delete mode 100644 Documentation/vDSO/Makefile rename {Documentation => tools/testing/selftests}/vDSO/.gitignore (100%) create mode 100644 tools/testing/selftests/vDSO/Makefile rename {Documentation => tools/testing/selftests}/vDSO/parse_vdso.c (100%) rename {Documentation => tools/testing/selftests}/vDSO/vdso_standalone_test_x86.c (100%) rename {Documentation => tools/testing/selftests}/vDSO/vdso_test.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index 8cd6d1aaabfaa..085b917b46953 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,3 +1,3 @@ subdir-y := accounting auxdisplay blackfin \ ia64 laptops mic misc-devices \ - networking pcmcia timers vDSO watchdog + networking pcmcia timers watchdog diff --git a/Documentation/vDSO/Makefile b/Documentation/vDSO/Makefile deleted file mode 100644 index b12e98770e1f5..0000000000000 --- a/Documentation/vDSO/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -ifndef CROSS_COMPILE -# vdso_test won't build for glibc < 2.16, so disable it -# hostprogs-y := vdso_test -hostprogs-$(CONFIG_X86) := vdso_standalone_test_x86 -vdso_standalone_test_x86-objs := vdso_standalone_test_x86.o parse_vdso.o -vdso_test-objs := parse_vdso.o vdso_test.o - -# Tell kbuild to always build the programs -always := $(hostprogs-y) - -HOSTCFLAGS := -I$(objtree)/usr/include -std=gnu99 -HOSTCFLAGS_vdso_standalone_test_x86.o := -fno-asynchronous-unwind-tables -fno-stack-protector -HOSTLOADLIBES_vdso_standalone_test_x86 := -nostdlib -ifeq ($(CONFIG_X86_32),y) -HOSTLOADLIBES_vdso_standalone_test_x86 += -lgcc_s -endif -endif diff --git a/Documentation/vDSO/.gitignore b/tools/testing/selftests/vDSO/.gitignore similarity index 100% rename from Documentation/vDSO/.gitignore rename to tools/testing/selftests/vDSO/.gitignore diff --git a/tools/testing/selftests/vDSO/Makefile b/tools/testing/selftests/vDSO/Makefile new file mode 100644 index 0000000000000..706b68b1c3722 --- /dev/null +++ b/tools/testing/selftests/vDSO/Makefile @@ -0,0 +1,20 @@ +ifndef CROSS_COMPILE +CFLAGS := -std=gnu99 +CFLAGS_vdso_standalone_test_x86 := -nostdlib -fno-asynchronous-unwind-tables -fno-stack-protector +ifeq ($(CONFIG_X86_32),y) +LDLIBS += -lgcc_s +endif + +TEST_PROGS := vdso_test vdso_standalone_test_x86 + +all: $(TEST_PROGS) +vdso_test: parse_vdso.c vdso_test.c +vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c + $(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \ + vdso_standalone_test_x86.c parse_vdso.c \ + -o vdso_standalone_test_x86 + +include ../lib.mk +clean: + rm -fr $(TEST_PROGS) +endif diff --git a/Documentation/vDSO/parse_vdso.c b/tools/testing/selftests/vDSO/parse_vdso.c similarity index 100% rename from Documentation/vDSO/parse_vdso.c rename to tools/testing/selftests/vDSO/parse_vdso.c diff --git a/Documentation/vDSO/vdso_standalone_test_x86.c b/tools/testing/selftests/vDSO/vdso_standalone_test_x86.c similarity index 100% rename from Documentation/vDSO/vdso_standalone_test_x86.c rename to tools/testing/selftests/vDSO/vdso_standalone_test_x86.c diff --git a/Documentation/vDSO/vdso_test.c b/tools/testing/selftests/vDSO/vdso_test.c similarity index 100% rename from Documentation/vDSO/vdso_test.c rename to tools/testing/selftests/vDSO/vdso_test.c -- GitLab From b6ebbac51bedf9e98e837688bc838f400196da5e Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 13 Sep 2016 12:52:24 -0600 Subject: [PATCH 0078/1167] selftests: move ia64 tests from Documentation/ia64 Remove ia64 from Makefile to move the test to selftests. Update ia64 Makefile to work under selftests. ia64 will not be run as part of selftests suite and will not be included in install targets. They can be built separately for now. The original Makefile built this test on all archirectures and this update doesn't change that. Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/ia64/Makefile | 5 ----- .../testing/selftests}/ia64/.gitignore | 0 tools/testing/selftests/ia64/Makefile | 8 ++++++++ .../testing/selftests}/ia64/aliasing-test.c | 0 5 files changed, 9 insertions(+), 6 deletions(-) delete mode 100644 Documentation/ia64/Makefile rename {Documentation => tools/testing/selftests}/ia64/.gitignore (100%) create mode 100644 tools/testing/selftests/ia64/Makefile rename {Documentation => tools/testing/selftests}/ia64/aliasing-test.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index 085b917b46953..572e9b7f37584 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,3 +1,3 @@ subdir-y := accounting auxdisplay blackfin \ - ia64 laptops mic misc-devices \ + laptops mic misc-devices \ networking pcmcia timers watchdog diff --git a/Documentation/ia64/Makefile b/Documentation/ia64/Makefile deleted file mode 100644 index d493163affe70..0000000000000 --- a/Documentation/ia64/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# List of programs to build -hostprogs-y := aliasing-test - -# Tell kbuild to always build the programs -always := $(hostprogs-y) diff --git a/Documentation/ia64/.gitignore b/tools/testing/selftests/ia64/.gitignore similarity index 100% rename from Documentation/ia64/.gitignore rename to tools/testing/selftests/ia64/.gitignore diff --git a/tools/testing/selftests/ia64/Makefile b/tools/testing/selftests/ia64/Makefile new file mode 100644 index 0000000000000..2b3de2d3e9459 --- /dev/null +++ b/tools/testing/selftests/ia64/Makefile @@ -0,0 +1,8 @@ +TEST_PROGS := aliasing-test + +all: $(TEST_PROGS) + +include ../lib.mk + +clean: + rm -fr $(TEST_PROGS) diff --git a/Documentation/ia64/aliasing-test.c b/tools/testing/selftests/ia64/aliasing-test.c similarity index 100% rename from Documentation/ia64/aliasing-test.c rename to tools/testing/selftests/ia64/aliasing-test.c -- GitLab From 02a35aad8a3e0b2bde1986053cefc2fcd63aee5d Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 13 Sep 2016 13:03:35 -0600 Subject: [PATCH 0079/1167] selftests: move watchdog tests from Documentation/watchdog Remove watchdog-test from Makefile to move the test to selftests. Add Makefile and .gitignore for watchdog-test. watchdog-test will not be run as part of selftests suite and will not be included in install targets. It can be built separately for now. Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/watchdog/src/.gitignore | 1 - Documentation/watchdog/src/Makefile | 2 +- tools/testing/selftests/watchdog/.gitignore | 1 + tools/testing/selftests/watchdog/Makefile | 8 ++++++++ .../testing/selftests/watchdog}/watchdog-test.c | 0 5 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/watchdog/.gitignore create mode 100644 tools/testing/selftests/watchdog/Makefile rename {Documentation/watchdog/src => tools/testing/selftests/watchdog}/watchdog-test.c (100%) diff --git a/Documentation/watchdog/src/.gitignore b/Documentation/watchdog/src/.gitignore index ac90997dba937..ff0ebb5403334 100644 --- a/Documentation/watchdog/src/.gitignore +++ b/Documentation/watchdog/src/.gitignore @@ -1,2 +1 @@ watchdog-simple -watchdog-test diff --git a/Documentation/watchdog/src/Makefile b/Documentation/watchdog/src/Makefile index 4a892c304983c..47be791827d48 100644 --- a/Documentation/watchdog/src/Makefile +++ b/Documentation/watchdog/src/Makefile @@ -1,5 +1,5 @@ # List of programs to build -hostprogs-y := watchdog-simple watchdog-test +hostprogs-y := watchdog-simple # Tell kbuild to always build the programs always := $(hostprogs-y) diff --git a/tools/testing/selftests/watchdog/.gitignore b/tools/testing/selftests/watchdog/.gitignore new file mode 100644 index 0000000000000..5aac51575c7ef --- /dev/null +++ b/tools/testing/selftests/watchdog/.gitignore @@ -0,0 +1 @@ +watchdog-test diff --git a/tools/testing/selftests/watchdog/Makefile b/tools/testing/selftests/watchdog/Makefile new file mode 100644 index 0000000000000..f863c664e3d14 --- /dev/null +++ b/tools/testing/selftests/watchdog/Makefile @@ -0,0 +1,8 @@ +TEST_PROGS := watchdog-test + +all: $(TEST_PROGS) + +include ../lib.mk + +clean: + rm -fr $(TEST_PROGS) diff --git a/Documentation/watchdog/src/watchdog-test.c b/tools/testing/selftests/watchdog/watchdog-test.c similarity index 100% rename from Documentation/watchdog/src/watchdog-test.c rename to tools/testing/selftests/watchdog/watchdog-test.c -- GitLab From 3d2c86e3057995270e08693231039d9d942871f0 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 15 Sep 2016 08:36:07 -0600 Subject: [PATCH 0080/1167] selftests: Move networking/timestamping from Documentation Remove networking from Documentation Makefile to move the test to selftests. Update networking/timestamping Makefile to work under selftests. These tests will not be run as part of selftests suite and will not be included in install targets. They can be built and run separately for now. This is part of the effort to move runnable code from Documentation. Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 3 +-- Documentation/networking/Makefile | 1 - Documentation/networking/timestamping/Makefile | 14 -------------- .../selftests}/networking/timestamping/.gitignore | 0 .../selftests/networking/timestamping/Makefile | 8 ++++++++ .../networking/timestamping/hwtstamp_config.c | 0 .../networking/timestamping/timestamping.c | 0 .../networking/timestamping/txtimestamp.c | 0 8 files changed, 9 insertions(+), 17 deletions(-) delete mode 100644 Documentation/networking/Makefile delete mode 100644 Documentation/networking/timestamping/Makefile rename {Documentation => tools/testing/selftests}/networking/timestamping/.gitignore (100%) create mode 100644 tools/testing/selftests/networking/timestamping/Makefile rename {Documentation => tools/testing/selftests}/networking/timestamping/hwtstamp_config.c (100%) rename {Documentation => tools/testing/selftests}/networking/timestamping/timestamping.c (100%) rename {Documentation => tools/testing/selftests}/networking/timestamping/txtimestamp.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index 572e9b7f37584..f530c29806189 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,3 +1,2 @@ subdir-y := accounting auxdisplay blackfin \ - laptops mic misc-devices \ - networking pcmcia timers watchdog + laptops mic misc-devices pcmcia timers watchdog diff --git a/Documentation/networking/Makefile b/Documentation/networking/Makefile deleted file mode 100644 index 4c5d7c4854395..0000000000000 --- a/Documentation/networking/Makefile +++ /dev/null @@ -1 +0,0 @@ -subdir-y := timestamping diff --git a/Documentation/networking/timestamping/Makefile b/Documentation/networking/timestamping/Makefile deleted file mode 100644 index 8c20dfaa4d6ee..0000000000000 --- a/Documentation/networking/timestamping/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# To compile, from the source root -# -# make headers_install -# make M=documentation - -# List of programs to build -hostprogs-y := hwtstamp_config timestamping txtimestamp - -# Tell kbuild to always build the programs -always := $(hostprogs-y) - -HOSTCFLAGS_timestamping.o += -I$(objtree)/usr/include -HOSTCFLAGS_txtimestamp.o += -I$(objtree)/usr/include -HOSTCFLAGS_hwtstamp_config.o += -I$(objtree)/usr/include diff --git a/Documentation/networking/timestamping/.gitignore b/tools/testing/selftests/networking/timestamping/.gitignore similarity index 100% rename from Documentation/networking/timestamping/.gitignore rename to tools/testing/selftests/networking/timestamping/.gitignore diff --git a/tools/testing/selftests/networking/timestamping/Makefile b/tools/testing/selftests/networking/timestamping/Makefile new file mode 100644 index 0000000000000..ccbb9edbbbb9a --- /dev/null +++ b/tools/testing/selftests/networking/timestamping/Makefile @@ -0,0 +1,8 @@ +TEST_PROGS := hwtstamp_config timestamping txtimestamp + +all: $(TEST_PROGS) + +include ../../lib.mk + +clean: + rm -fr $(TEST_PROGS) diff --git a/Documentation/networking/timestamping/hwtstamp_config.c b/tools/testing/selftests/networking/timestamping/hwtstamp_config.c similarity index 100% rename from Documentation/networking/timestamping/hwtstamp_config.c rename to tools/testing/selftests/networking/timestamping/hwtstamp_config.c diff --git a/Documentation/networking/timestamping/timestamping.c b/tools/testing/selftests/networking/timestamping/timestamping.c similarity index 100% rename from Documentation/networking/timestamping/timestamping.c rename to tools/testing/selftests/networking/timestamping/timestamping.c diff --git a/Documentation/networking/timestamping/txtimestamp.c b/tools/testing/selftests/networking/timestamping/txtimestamp.c similarity index 100% rename from Documentation/networking/timestamping/txtimestamp.c rename to tools/testing/selftests/networking/timestamping/txtimestamp.c -- GitLab From 6bee835dd54e279f3d3ae2eca92a9c394b4fd028 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 16 Sep 2016 15:53:52 -0600 Subject: [PATCH 0081/1167] samples: move mic/mpssd example code from Documentation Move mic/mpssd examples to samples and remove it from Documentation Makefile. Create a new Makefile to build mic/mpssd. It can be built from top level directory or from mic/mpssd directory: Run make -C samples/mic/mpssd or cd samples/mic/mpssd; make Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/mic/Makefile | 1 - Documentation/mic/mpssd/Makefile | 21 --------------- .../mic/mpssd/.gitignore | 0 samples/mic/mpssd/Makefile | 27 +++++++++++++++++++ {Documentation => samples}/mic/mpssd/micctrl | 0 {Documentation => samples}/mic/mpssd/mpss | 0 {Documentation => samples}/mic/mpssd/mpssd.c | 0 {Documentation => samples}/mic/mpssd/mpssd.h | 0 {Documentation => samples}/mic/mpssd/sysfs.c | 0 10 files changed, 28 insertions(+), 23 deletions(-) delete mode 100644 Documentation/mic/Makefile delete mode 100644 Documentation/mic/mpssd/Makefile rename {Documentation => samples}/mic/mpssd/.gitignore (100%) create mode 100644 samples/mic/mpssd/Makefile rename {Documentation => samples}/mic/mpssd/micctrl (100%) rename {Documentation => samples}/mic/mpssd/mpss (100%) rename {Documentation => samples}/mic/mpssd/mpssd.c (100%) rename {Documentation => samples}/mic/mpssd/mpssd.h (100%) rename {Documentation => samples}/mic/mpssd/sysfs.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index f530c29806189..80b5bdc65055f 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ subdir-y := accounting auxdisplay blackfin \ - laptops mic misc-devices pcmcia timers watchdog + laptops misc-devices pcmcia timers watchdog diff --git a/Documentation/mic/Makefile b/Documentation/mic/Makefile deleted file mode 100644 index a191d453badf1..0000000000000 --- a/Documentation/mic/Makefile +++ /dev/null @@ -1 +0,0 @@ -subdir-y := mpssd diff --git a/Documentation/mic/mpssd/Makefile b/Documentation/mic/mpssd/Makefile deleted file mode 100644 index 06871b0c08a6e..0000000000000 --- a/Documentation/mic/mpssd/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -ifndef CROSS_COMPILE -# List of programs to build -hostprogs-$(CONFIG_X86_64) := mpssd - -mpssd-objs := mpssd.o sysfs.o - -# Tell kbuild to always build the programs -always := $(hostprogs-y) - -HOSTCFLAGS += -I$(objtree)/usr/include -I$(srctree)/tools/include - -ifdef DEBUG -HOSTCFLAGS += -DDEBUG=$(DEBUG) -endif - -HOSTLOADLIBES_mpssd := -lpthread - -install: - install mpssd /usr/sbin/mpssd - install micctrl /usr/sbin/micctrl -endif diff --git a/Documentation/mic/mpssd/.gitignore b/samples/mic/mpssd/.gitignore similarity index 100% rename from Documentation/mic/mpssd/.gitignore rename to samples/mic/mpssd/.gitignore diff --git a/samples/mic/mpssd/Makefile b/samples/mic/mpssd/Makefile new file mode 100644 index 0000000000000..3e3ef91fed6b3 --- /dev/null +++ b/samples/mic/mpssd/Makefile @@ -0,0 +1,27 @@ +ifndef CROSS_COMPILE +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) + +ifeq ($(ARCH),x86) + +PROGS := mpssd +CC = $(CROSS_COMPILE)gcc +CFLAGS := -I../../../usr/include -I../../../tools/include + +ifdef DEBUG +CFLAGS += -DDEBUG=$(DEBUG) +endif + +all: $(PROGS) +mpssd: mpssd.c sysfs.c + $(CC) $(CFLAGS) mpssd.c sysfs.c -o mpssd -lpthread + +install: + install mpssd /usr/sbin/mpssd + install micctrl /usr/sbin/micctrl + +clean: + rm -fr $(PROGS) + +endif +endif diff --git a/Documentation/mic/mpssd/micctrl b/samples/mic/mpssd/micctrl similarity index 100% rename from Documentation/mic/mpssd/micctrl rename to samples/mic/mpssd/micctrl diff --git a/Documentation/mic/mpssd/mpss b/samples/mic/mpssd/mpss similarity index 100% rename from Documentation/mic/mpssd/mpss rename to samples/mic/mpssd/mpss diff --git a/Documentation/mic/mpssd/mpssd.c b/samples/mic/mpssd/mpssd.c similarity index 100% rename from Documentation/mic/mpssd/mpssd.c rename to samples/mic/mpssd/mpssd.c diff --git a/Documentation/mic/mpssd/mpssd.h b/samples/mic/mpssd/mpssd.h similarity index 100% rename from Documentation/mic/mpssd/mpssd.h rename to samples/mic/mpssd/mpssd.h diff --git a/Documentation/mic/mpssd/sysfs.c b/samples/mic/mpssd/sysfs.c similarity index 100% rename from Documentation/mic/mpssd/sysfs.c rename to samples/mic/mpssd/sysfs.c -- GitLab From 6ec76070f17993aa9ac0344330b971783d10c9c2 Mon Sep 17 00:00:00 2001 From: Harman Kalra Date: Wed, 21 Sep 2016 01:14:40 +0530 Subject: [PATCH 0082/1167] ata: sata_mv: Replacing dma_pool_alloc and memset with a single call dma_pool_zalloc. Replacing dma_pool_alloc and memset with a single call to dma_pool_zalloc Signed-off-by: Harman Kalra Signed-off-by: Tejun Heo --- drivers/ata/sata_mv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 745489a1c86ab..efc48bf89d518 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1727,15 +1727,13 @@ static int mv_port_start(struct ata_port *ap) return -ENOMEM; ap->private_data = pp; - pp->crqb = dma_pool_alloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma); + pp->crqb = dma_pool_zalloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma); if (!pp->crqb) return -ENOMEM; - memset(pp->crqb, 0, MV_CRQB_Q_SZ); - pp->crpb = dma_pool_alloc(hpriv->crpb_pool, GFP_KERNEL, &pp->crpb_dma); + pp->crpb = dma_pool_zalloc(hpriv->crpb_pool, GFP_KERNEL, &pp->crpb_dma); if (!pp->crpb) goto out_port_free_dma_mem; - memset(pp->crpb, 0, MV_CRPB_Q_SZ); /* 6041/6081 Rev. "C0" (and newer) are okay with async notify */ if (hpriv->hp_flags & MV_HP_ERRATA_60X1C0) -- GitLab From 6a45b3628ce4dcf7498b39c87d475bab6e2a9b24 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Fri, 16 Sep 2016 11:45:24 +0200 Subject: [PATCH 0083/1167] ovl: Fix info leak in ovl_lookup_temp() The function uses the memory address of a struct dentry as unique id. While the address-based directory entry is only visible to root it is IMHO still worth fixing since the temporary name does not have to be a kernel address. It can be any unique number. Replace it by an atomic integer which is allowed to wrap around. Signed-off-by: Richard Weinberger Reviewed-by: Kees Cook Signed-off-by: Miklos Szeredi Cc: # v3.18+ Fixes: e9be9d5e76e3 ("overlay filesystem") --- fs/overlayfs/dir.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 1560fdc09a5fa..74e696426aaef 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "overlayfs.h" void ovl_cleanup(struct inode *wdir, struct dentry *wdentry) @@ -37,8 +38,10 @@ struct dentry *ovl_lookup_temp(struct dentry *workdir, struct dentry *dentry) { struct dentry *temp; char name[20]; + static atomic_t temp_id = ATOMIC_INIT(0); - snprintf(name, sizeof(name), "#%lx", (unsigned long) dentry); + /* counter is allowed to wrap, since temp dentries are ephemeral */ + snprintf(name, sizeof(name), "#%x", atomic_inc_return(&temp_id)); temp = lookup_one_len(name, workdir, strlen(name)); if (!IS_ERR(temp) && temp->d_inode) { -- GitLab From 97ea1906b3c2201273ea6bb40c43c611c056ddb3 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Fri, 16 Sep 2016 11:26:28 +0200 Subject: [PATCH 0084/1167] rtc: omap: Support ext_wakeup configuration Support configuration of ext_wakeup sources. This patch makes it possible to enable ext_wakeup and set it's polarity, depending on board configuration. AM335x's dedicated PMIC (tps65217) uses ext_wakeup to notify about power-button presses. Handling power-button presses enables to recover from RTC-only power states correctly. Signed-off-by: Marcin Niestroj Acked-by: Tony Lindgren Acked-by: Rob Herring Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/rtc-omap.txt | 21 +++ drivers/rtc/Kconfig | 3 + drivers/rtc/rtc-omap.c | 168 +++++++++++++++++- 3 files changed, 184 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/rtc/rtc-omap.txt b/Documentation/devicetree/bindings/rtc/rtc-omap.txt index bf7d11ae9bea6..bee41f97044e1 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-omap.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-omap.txt @@ -18,6 +18,18 @@ Optional properties: through pmic_power_en - clocks: Any internal or external clocks feeding in to rtc - clock-names: Corresponding names of the clocks +- pinctrl-0: a phandle pointing to the pin settings for the device +- pinctrl-names: should be "default" + +Optional subnodes: +- generic pinctrl node + +Required pinctrl subnodes properties: +- pins - Names of ext_wakeup pins to configure + +Optional pinctrl subnodes properties: +- input-enable - Enables ext_wakeup +- ti,active-high - Set input active high (by default active low) Example: @@ -30,4 +42,13 @@ rtc@1c23000 { system-power-controller; clocks = <&clk_32k_rtc>, <&clk_32768_ck>; clock-names = "ext-clk", "int-clk"; + + pinctrl-0 = <&ext_wakeup>; + pinctrl-names = "default"; + + ext_wakeup: ext-wakeup { + pins = "ext_wakeup0"; + input-enable; + ti,active-high; + }; }; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 896302a0d4b9d..531343a260f85 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1245,6 +1245,9 @@ config RTC_DRV_IMXDI config RTC_DRV_OMAP tristate "TI OMAP Real Time Clock" depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST + depends on OF + depends on PINCTRL + select GENERIC_PINCONF help Say "yes" here to support the on chip real time clock present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx. diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index cadac8e2aa6b7..b04ea9b5ae673 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -13,19 +13,23 @@ * 2 of the License, or (at your option) any later version. */ -#include +#include +#include +#include +#include #include -#include +#include #include -#include -#include -#include -#include +#include +#include #include #include +#include +#include +#include +#include #include -#include -#include +#include /* * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock @@ -115,6 +119,8 @@ /* OMAP_RTC_PMIC bit fields: */ #define OMAP_RTC_PMIC_POWER_EN_EN BIT(16) +#define OMAP_RTC_PMIC_EXT_WKUP_EN(x) BIT(x) +#define OMAP_RTC_PMIC_EXT_WKUP_POL(x) BIT(4 + x) /* OMAP_RTC_KICKER values */ #define KICK0_VALUE 0x83e70b13 @@ -141,6 +147,7 @@ struct omap_rtc { bool is_pmic_controller; bool has_ext_clk; const struct omap_rtc_device_type *type; + struct pinctrl_dev *pctldev; }; static inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg) @@ -525,6 +532,139 @@ static const struct of_device_id omap_rtc_of_match[] = { }; MODULE_DEVICE_TABLE(of, omap_rtc_of_match); +static const struct pinctrl_pin_desc rtc_pins_desc[] = { + PINCTRL_PIN(0, "ext_wakeup0"), + PINCTRL_PIN(1, "ext_wakeup1"), + PINCTRL_PIN(2, "ext_wakeup2"), + PINCTRL_PIN(3, "ext_wakeup3"), +}; + +static int rtc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + return 0; +} + +static const char *rtc_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + return NULL; +} + +static const struct pinctrl_ops rtc_pinctrl_ops = { + .get_groups_count = rtc_pinctrl_get_groups_count, + .get_group_name = rtc_pinctrl_get_group_name, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +enum rtc_pin_config_param { + PIN_CONFIG_ACTIVE_HIGH = PIN_CONFIG_END + 1, +}; + +static const struct pinconf_generic_params rtc_params[] = { + {"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0}, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item rtc_conf_items[ARRAY_SIZE(rtc_params)] = { + PCONFDUMP(PIN_CONFIG_ACTIVE_HIGH, "input active high", NULL, false), +}; +#endif + +static int rtc_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev); + unsigned int param = pinconf_to_config_param(*config); + u32 val; + u16 arg = 0; + + rtc->type->unlock(rtc); + val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); + rtc->type->lock(rtc); + + switch (param) { + case PIN_CONFIG_INPUT_ENABLE: + if (!(val & OMAP_RTC_PMIC_EXT_WKUP_EN(pin))) + return -EINVAL; + break; + case PIN_CONFIG_ACTIVE_HIGH: + if (val & OMAP_RTC_PMIC_EXT_WKUP_POL(pin)) + return -EINVAL; + break; + default: + return -ENOTSUPP; + }; + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int rtc_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *configs, + unsigned int num_configs) +{ + struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev); + u32 val; + unsigned int param; + u16 param_val; + int i; + + rtc->type->unlock(rtc); + val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); + rtc->type->lock(rtc); + + /* active low by default */ + val |= OMAP_RTC_PMIC_EXT_WKUP_POL(pin); + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + param_val = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_INPUT_ENABLE: + if (param_val) + val |= OMAP_RTC_PMIC_EXT_WKUP_EN(pin); + else + val &= ~OMAP_RTC_PMIC_EXT_WKUP_EN(pin); + break; + case PIN_CONFIG_ACTIVE_HIGH: + val &= ~OMAP_RTC_PMIC_EXT_WKUP_POL(pin); + break; + default: + dev_err(&rtc->rtc->dev, "Property %u not supported\n", + param); + return -ENOTSUPP; + } + } + + rtc->type->unlock(rtc); + rtc_writel(rtc, OMAP_RTC_PMIC_REG, val); + rtc->type->lock(rtc); + + return 0; +} + +static const struct pinconf_ops rtc_pinconf_ops = { + .is_generic = true, + .pin_config_get = rtc_pinconf_get, + .pin_config_set = rtc_pinconf_set, +}; + +static struct pinctrl_desc rtc_pinctrl_desc = { + .pins = rtc_pins_desc, + .npins = ARRAY_SIZE(rtc_pins_desc), + .pctlops = &rtc_pinctrl_ops, + .confops = &rtc_pinconf_ops, + .custom_params = rtc_params, + .num_custom_params = ARRAY_SIZE(rtc_params), +#ifdef CONFIG_DEBUG_FS + .custom_conf_items = rtc_conf_items, +#endif + .owner = THIS_MODULE, +}; + static int omap_rtc_probe(struct platform_device *pdev) { struct omap_rtc *rtc; @@ -681,6 +821,15 @@ static int omap_rtc_probe(struct platform_device *pdev) } } + /* Support ext_wakeup pinconf */ + rtc_pinctrl_desc.name = dev_name(&pdev->dev); + + rtc->pctldev = pinctrl_register(&rtc_pinctrl_desc, &pdev->dev, rtc); + if (IS_ERR(rtc->pctldev)) { + dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); + return PTR_ERR(rtc->pctldev); + } + return 0; err: @@ -724,6 +873,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + /* Remove ext_wakeup pinconf */ + pinctrl_unregister(rtc->pctldev); + return 0; } -- GitLab From 983bf1256edb477a376b6ce95adf36e13bc88f9a Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Tue, 20 Sep 2016 01:12:43 +0200 Subject: [PATCH 0085/1167] rtc: cmos: Clear ACPI-driven alarms upon resume Currently ACPI-driven alarms are not cleared when they wake the system. As consequence, expired alarms must be manually cleared to program a new alarm. Fix this by correctly handling ACPI-driven alarms. More specifically, the ACPI specification [1] provides for two alternative implementations of the RTC. Depending on the implementation, the driver either clear the alarm from the resume callback or from ACPI interrupt handler: - The platform has the RTC wakeup status fixed in hardware (ACPI_FADT_FIXED_RTC is 0). In this case the driver can determine if the RTC was the reason of the wakeup from the resume callback by reading the RTC status register. - The platform has no fixed hardware feature event bits. In this case a GPE is used to wake the system and the driver clears the alarm from its handler. [1] http://www.acpi.info/DOWNLOADS/ACPI_5_Errata%20A.pdf Signed-off-by: Gabriele Mazzotta Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index fddde655cbd4f..e8f3a212d09ad 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -899,6 +899,9 @@ static inline int cmos_poweroff(struct device *dev) #ifdef CONFIG_PM_SLEEP +static void cmos_check_acpi_rtc_status(struct device *dev, + unsigned char *rtc_control); + static int cmos_resume(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); @@ -938,6 +941,9 @@ static int cmos_resume(struct device *dev) tmp &= ~RTC_AIE; hpet_mask_rtc_irq_bit(RTC_AIE); } while (mask & RTC_AIE); + + if (tmp & RTC_AIE) + cmos_check_acpi_rtc_status(dev, &tmp); } spin_unlock_irq(&rtc_lock); @@ -975,6 +981,20 @@ static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume); static u32 rtc_handler(void *context) { struct device *dev = context; + struct cmos_rtc *cmos = dev_get_drvdata(dev); + unsigned char rtc_control = 0; + unsigned char rtc_intr; + + spin_lock_irq(&rtc_lock); + if (cmos_rtc.suspend_ctrl) + rtc_control = CMOS_READ(RTC_CONTROL); + if (rtc_control & RTC_AIE) { + cmos_rtc.suspend_ctrl &= ~RTC_AIE; + CMOS_WRITE(rtc_control, RTC_CONTROL); + rtc_intr = CMOS_READ(RTC_INTR_FLAGS); + rtc_update_irq(cmos->rtc, 1, rtc_intr); + } + spin_unlock_irq(&rtc_lock); pm_wakeup_event(dev, 0); acpi_clear_event(ACPI_EVENT_RTC); @@ -1041,12 +1061,39 @@ static void cmos_wake_setup(struct device *dev) device_init_wakeup(dev, 1); } +static void cmos_check_acpi_rtc_status(struct device *dev, + unsigned char *rtc_control) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + acpi_event_status rtc_status; + acpi_status status; + + if (acpi_gbl_FADT.flags & ACPI_FADT_FIXED_RTC) + return; + + status = acpi_get_event_status(ACPI_EVENT_RTC, &rtc_status); + if (ACPI_FAILURE(status)) { + dev_err(dev, "Could not get RTC status\n"); + } else if (rtc_status & ACPI_EVENT_FLAG_SET) { + unsigned char mask; + *rtc_control &= ~RTC_AIE; + CMOS_WRITE(*rtc_control, RTC_CONTROL); + mask = CMOS_READ(RTC_INTR_FLAGS); + rtc_update_irq(cmos->rtc, 1, mask); + } +} + #else static void cmos_wake_setup(struct device *dev) { } +static void cmos_check_acpi_rtc_status(struct device *dev, + unsigned char *rtc_control) +{ +} + #endif #ifdef CONFIG_PNP -- GitLab From 68669d55f7ad31832692254485a07b6e412ae082 Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Tue, 20 Sep 2016 01:12:44 +0200 Subject: [PATCH 0086/1167] rtc: cmos: Restore alarm after resume Some platform firmware may interfere with the RTC alarm over suspend, resulting in the kernel and hardware having different ideas about system state but also potentially causing problems with firmware that assumes the OS will clean this case up. This patch restores the RTC alarm on resume to ensure that kernel and hardware are in sync. The case we've seen is Intel Rapid Start, which is a firmware-mediated feature that automatically transitions systems from suspend-to-RAM to suspend-to-disk without OS involvement. It does this by setting the RTC alarm and a flag that indicates that on wake it should perform the transition rather than re-starting the OS. However, if the OS has set a wakeup alarm that would wake the machine earlier, it refuses to overwrite it and allows the system to wake instead. This fails in the following situation: 1) User configures Intel Rapid Start to transition after (say) 15 minutes 2) User suspends to RAM. Firmware sets the wakeup alarm for 15 minutes in the future 3) User resumes after 5 minutes. Firmware does not reset the alarm, and as such it is still set for 10 minutes in the future 4) User suspends after 5 minutes. Firmware notices that the alarm is set for 5 minutes in the future, which is less than the 15 minute transition threshold. It therefore assumes that the user wants the machine to wake in 5 minutes 5) System resumes after 5 minutes The worst case scenario here is that the user may have put the system in a bag between (4) and (5), resulting in it running in a confined space and potentially overheating. This seems reasonably important. The Rapid Start support code got added in 3.11, but it can be configured in the firmware regardless of kernel support. Signed-off-by: Gabriele Mazzotta Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index e8f3a212d09ad..2943a0d58a3ad 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -62,6 +62,8 @@ struct cmos_rtc { u8 day_alrm; u8 mon_alrm; u8 century; + + struct rtc_wkalrm saved_wkalrm; }; /* both platform and pnp busses use negative numbers for invalid irqs */ @@ -879,6 +881,8 @@ static int cmos_suspend(struct device *dev) enable_irq_wake(cmos->irq); } + cmos_read_alarm(dev, &cmos->saved_wkalrm); + dev_dbg(dev, "suspend%s, ctrl %02x\n", (tmp & RTC_AIE) ? ", alarm may wake" : "", tmp); @@ -899,6 +903,22 @@ static inline int cmos_poweroff(struct device *dev) #ifdef CONFIG_PM_SLEEP +static void cmos_check_wkalrm(struct device *dev) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + struct rtc_wkalrm current_alarm; + time64_t t_current_expires; + time64_t t_saved_expires; + + cmos_read_alarm(dev, ¤t_alarm); + t_current_expires = rtc_tm_to_time64(¤t_alarm.time); + t_saved_expires = rtc_tm_to_time64(&cmos->saved_wkalrm.time); + if (t_current_expires != t_saved_expires || + cmos->saved_wkalrm.enabled != current_alarm.enabled) { + cmos_set_alarm(dev, &cmos->saved_wkalrm); + } +} + static void cmos_check_acpi_rtc_status(struct device *dev, unsigned char *rtc_control); @@ -915,6 +935,9 @@ static int cmos_resume(struct device *dev) cmos->enabled_wake = 0; } + /* The BIOS might have changed the alarm, restore it */ + cmos_check_wkalrm(dev); + spin_lock_irq(&rtc_lock); tmp = cmos->suspend_ctrl; cmos->suspend_ctrl = 0; -- GitLab From ee85bb5bbe4ae690b48625874bc2b6ecc981326e Mon Sep 17 00:00:00 2001 From: Raghavendra Ganiga Date: Wed, 31 Aug 2016 22:56:41 +0530 Subject: [PATCH 0087/1167] rtc: ds1347: changed raw spi calls to register map calls This patch changes calls of spi read write calls to register map read and write calls in rtc ds1347 Signed-off-by: Raghavendra Chandra Ganiga Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 1 + drivers/rtc/rtc-ds1347.c | 96 ++++++++++++++++++++++------------------ 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 531343a260f85..4f6bda83e0992 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -665,6 +665,7 @@ config RTC_DRV_DS1343 will be called rtc-ds1343. config RTC_DRV_DS1347 + select REGMAP_SPI tristate "Dallas/Maxim DS1347" help If you say yes here you get support for the diff --git a/drivers/rtc/rtc-ds1347.c b/drivers/rtc/rtc-ds1347.c index 641e8e8a0dd72..ccfc9d43eb1e6 100644 --- a/drivers/rtc/rtc-ds1347.c +++ b/drivers/rtc/rtc-ds1347.c @@ -18,6 +18,7 @@ #include #include #include +#include /* Registers in ds1347 rtc */ @@ -32,37 +33,28 @@ #define DS1347_STATUS_REG 0x17 #define DS1347_CLOCK_BURST 0x3F -static int ds1347_read_reg(struct device *dev, unsigned char address, - unsigned char *data) -{ - struct spi_device *spi = to_spi_device(dev); - - *data = address | 0x80; - - return spi_write_then_read(spi, data, 1, data, 1); -} - -static int ds1347_write_reg(struct device *dev, unsigned char address, - unsigned char data) -{ - struct spi_device *spi = to_spi_device(dev); - unsigned char buf[2]; - - buf[0] = address & 0x7F; - buf[1] = data; +static const struct regmap_range ds1347_ranges[] = { + { + .range_min = DS1347_SECONDS_REG, + .range_max = DS1347_STATUS_REG, + }, +}; - return spi_write_then_read(spi, buf, 2, NULL, 0); -} +static const struct regmap_access_table ds1347_access_table = { + .yes_ranges = ds1347_ranges, + .n_yes_ranges = ARRAY_SIZE(ds1347_ranges), +}; static int ds1347_read_time(struct device *dev, struct rtc_time *dt) { struct spi_device *spi = to_spi_device(dev); + struct regmap *map; int err; unsigned char buf[8]; - buf[0] = DS1347_CLOCK_BURST | 0x80; + map = spi_get_drvdata(spi); - err = spi_write_then_read(spi, buf, 1, buf, 8); + err = regmap_bulk_read(map, DS1347_CLOCK_BURST, buf, 8); if (err) return err; @@ -80,25 +72,27 @@ static int ds1347_read_time(struct device *dev, struct rtc_time *dt) static int ds1347_set_time(struct device *dev, struct rtc_time *dt) { struct spi_device *spi = to_spi_device(dev); - unsigned char buf[9]; + struct regmap *map; + unsigned char buf[8]; + + map = spi_get_drvdata(spi); - buf[0] = DS1347_CLOCK_BURST & 0x7F; - buf[1] = bin2bcd(dt->tm_sec); - buf[2] = bin2bcd(dt->tm_min); - buf[3] = (bin2bcd(dt->tm_hour) & 0x3F); - buf[4] = bin2bcd(dt->tm_mday); - buf[5] = bin2bcd(dt->tm_mon + 1); - buf[6] = bin2bcd(dt->tm_wday + 1); + buf[0] = bin2bcd(dt->tm_sec); + buf[1] = bin2bcd(dt->tm_min); + buf[2] = (bin2bcd(dt->tm_hour) & 0x3F); + buf[3] = bin2bcd(dt->tm_mday); + buf[4] = bin2bcd(dt->tm_mon + 1); + buf[5] = bin2bcd(dt->tm_wday + 1); /* year in linux is from 1900 i.e in range of 100 in rtc it is from 00 to 99 */ dt->tm_year = dt->tm_year % 100; - buf[7] = bin2bcd(dt->tm_year); - buf[8] = bin2bcd(0x00); + buf[6] = bin2bcd(dt->tm_year); + buf[7] = bin2bcd(0x00); /* write the rtc settings */ - return spi_write_then_read(spi, buf, 9, NULL, 0); + return regmap_bulk_write(map, DS1347_CLOCK_BURST, buf, 8); } static const struct rtc_class_ops ds1347_rtc_ops = { @@ -109,35 +103,53 @@ static const struct rtc_class_ops ds1347_rtc_ops = { static int ds1347_probe(struct spi_device *spi) { struct rtc_device *rtc; - unsigned char data; + struct regmap_config config; + struct regmap *map; + unsigned int data; int res; + memset(&config, 0, sizeof(config)); + config.reg_bits = 8; + config.val_bits = 8; + config.read_flag_mask = 0x80; + config.max_register = 0x3F; + config.wr_table = &ds1347_access_table; + /* spi setup with ds1347 in mode 3 and bits per word as 8 */ spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); + map = devm_regmap_init_spi(spi, &config); + + if (IS_ERR(map)) { + dev_err(&spi->dev, "ds1347 regmap init spi failed\n"); + return PTR_ERR(map); + } + + spi_set_drvdata(spi, map); + /* RTC Settings */ - res = ds1347_read_reg(&spi->dev, DS1347_SECONDS_REG, &data); + res = regmap_read(map, DS1347_SECONDS_REG, &data); if (res) return res; /* Disable the write protect of rtc */ - ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data); + regmap_read(map, DS1347_CONTROL_REG, &data); data = data & ~(1<<7); - ds1347_write_reg(&spi->dev, DS1347_CONTROL_REG, data); + regmap_write(map, DS1347_CONTROL_REG, data); /* Enable the oscillator , disable the oscillator stop flag, and glitch filter to reduce current consumption */ - ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data); + regmap_read(map, DS1347_STATUS_REG, &data); data = data & 0x1B; - ds1347_write_reg(&spi->dev, DS1347_STATUS_REG, data); + regmap_write(map, DS1347_STATUS_REG, data); /* display the settings */ - ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data); + regmap_read(map, DS1347_CONTROL_REG, &data); dev_info(&spi->dev, "DS1347 RTC CTRL Reg = 0x%02x\n", data); - ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data); + regmap_read(map, DS1347_STATUS_REG, &data); dev_info(&spi->dev, "DS1347 RTC Status Reg = 0x%02x\n", data); rtc = devm_rtc_device_register(&spi->dev, "ds1347", @@ -146,8 +158,6 @@ static int ds1347_probe(struct spi_device *spi) if (IS_ERR(rtc)) return PTR_ERR(rtc); - spi_set_drvdata(spi, rtc); - return 0; } -- GitLab From 473195f80f3940afc8a1461831d74f9a44bba538 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 9 Sep 2016 18:03:54 +0800 Subject: [PATCH 0088/1167] rtc: ac100: Add NULL checking for devm_kzalloc call devm_kzalloc can return NULL, add NULL checking to prevent NULL pointer dereference. Signed-off-by: Axel Lin Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ac100.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c index 2d0bb02a25d95..9e336184491cb 100644 --- a/drivers/rtc/rtc-ac100.c +++ b/drivers/rtc/rtc-ac100.c @@ -554,6 +554,9 @@ static int ac100_rtc_probe(struct platform_device *pdev) int ret; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + platform_set_drvdata(pdev, chip); chip->dev = &pdev->dev; chip->regmap = ac100->regmap; -- GitLab From 00f7f90c51dfc2403257e2c7410d453e72bf6a41 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Sep 2016 11:48:00 +0200 Subject: [PATCH 0089/1167] rtc: cmos: avoid unused function warning A bug fix for the ACPI side of this driver caused a harmless build warning: drivers/rtc/rtc-cmos.c:1115:13: error: 'cmos_check_acpi_rtc_status' defined but not used [-Werror=unused-function] static void cmos_check_acpi_rtc_status(struct device *dev, We can avoid the warning and simplify the driver at the same time by removing the #ifdef for CONFIG_PM and rely on the SIMPLE_DEV_PM_OPS() to set everything up correctly. cmos_resume() has to get marked as __maybe_unused so we don't introduce another warning, and the two variants of cmos_poweroff() can get merged into one using an IS_ENABLED() check. Fixes: 983bf1256edb ("rtc: cmos: Clear ACPI-driven alarms upon resume") Signed-off-by: Arnd Bergmann Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 2943a0d58a3ad..dd3d59806ffa0 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -848,8 +848,6 @@ static int cmos_aie_poweroff(struct device *dev) return retval; } -#ifdef CONFIG_PM - static int cmos_suspend(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); @@ -898,11 +896,12 @@ static int cmos_suspend(struct device *dev) */ static inline int cmos_poweroff(struct device *dev) { + if (!IS_ENABLED(CONFIG_PM)) + return -ENOSYS; + return cmos_suspend(dev); } -#ifdef CONFIG_PM_SLEEP - static void cmos_check_wkalrm(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); @@ -922,7 +921,7 @@ static void cmos_check_wkalrm(struct device *dev) static void cmos_check_acpi_rtc_status(struct device *dev, unsigned char *rtc_control); -static int cmos_resume(struct device *dev) +static int __maybe_unused cmos_resume(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char tmp; @@ -975,16 +974,6 @@ static int cmos_resume(struct device *dev) return 0; } -#endif -#else - -static inline int cmos_poweroff(struct device *dev) -{ - return -ENOSYS; -} - -#endif - static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume); /*----------------------------------------------------------------*/ @@ -1278,9 +1267,7 @@ static struct platform_driver cmos_platform_driver = { .shutdown = cmos_platform_shutdown, .driver = { .name = driver_name, -#ifdef CONFIG_PM .pm = &cmos_pm_ops, -#endif .of_match_table = of_match_ptr(of_cmos_match), } }; -- GitLab From 0f4c4af06eec5717041d6fe568b80ee4cf3c1475 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 14 Sep 2016 12:24:03 +1000 Subject: [PATCH 0090/1167] kbuild: -ffunction-sections fix for archs with conflicting sections Enabling -ffunction-sections modified the generic linker script to pull .text.* sections into regular TEXT_TEXT section, conflicting with some architectures. Revert that change and require archs that enable the option to ensure they have no conflicting section names, and do the appropriate merging. Reported-by: Guenter Roeck Tested-by: Guenter Roeck Fixes: b67067f1176d ("kbuild: allow archs to select link dead code/data elimination") Signed-off-by: Nicholas Piggin Signed-off-by: Michal Marek --- arch/Kconfig | 4 +++- include/asm-generic/vmlinux.lds.h | 15 ++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 3f948c422d9d1..48d1e76a1ee3c 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -478,7 +478,9 @@ config LD_DEAD_CODE_DATA_ELIMINATION This requires that the arch annotates or otherwise protects its external entry points from being discarded. Linker scripts must also merge .text.*, .data.*, and .bss.* correctly into - output sections. + output sections. Care must be taken not to pull in unrelated + sections (e.g., '.text.init'). Typically '.' in section names + is used to distinguish them from label names / C identifiers. config HAVE_CONTEXT_TRACKING bool diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index ad9d8f94dc7a9..48dd44f3f24bc 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -198,9 +198,9 @@ /* * .data section - * -fdata-sections generates .data.identifier which needs to be pulled in - * with .data, but don't want to pull in .data..stuff which has its own - * requirements. Same for bss. + * LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections generates + * .data.identifier which needs to be pulled in with .data, but don't want to + * pull in .data..stuff which has its own requirements. Same for bss. */ #define DATA_DATA \ *(.data .data.[0-9a-zA-Z_]*) \ @@ -434,10 +434,15 @@ } /* .text section. Map to function alignment to avoid address changes - * during second ld run in second ld pass when generating System.map */ + * during second ld run in second ld pass when generating System.map + * LD_DEAD_CODE_DATA_ELIMINATION option enables -ffunction-sections generates + * .text.identifier which needs to be pulled in with .text , but some + * architectures define .text.foo which is not intended to be pulled in here. + * Those enabling LD_DEAD_CODE_DATA_ELIMINATION must ensure they don't have + * conflicting section names, and must pull in .text.[0-9a-zA-Z_]* */ #define TEXT_TEXT \ ALIGN_FUNCTION(); \ - *(.text.hot .text .text.fixup .text.unlikely .text.*) \ + *(.text.hot .text .text.fixup .text.unlikely) \ *(.ref.text) \ MEM_KEEP(init.text) \ MEM_KEEP(exit.text) \ -- GitLab From 12eb901e01c7830a00e373ac311512cea26f54ef Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 14 Sep 2016 12:45:07 +1000 Subject: [PATCH 0091/1167] powerpc/64: whitelist unresolved modversions CRCs These are a symptom of CRC generation failure in generic build code, and not powerpc specific. Signed-off-by: Nicholas Piggin Tested-by: Stephen Rothwell Acked-by: Michael Ellerman Fixes: 9445aa1a3062 ("ppc: move exports to definitions") Signed-off-by: Michal Marek --- arch/powerpc/relocs_check.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/relocs_check.sh b/arch/powerpc/relocs_check.sh index 2e4ebd0e25b3e..ec2d5c835170a 100755 --- a/arch/powerpc/relocs_check.sh +++ b/arch/powerpc/relocs_check.sh @@ -30,6 +30,7 @@ bad_relocs=$( # On PPC64: # R_PPC64_RELATIVE, R_PPC64_NONE # R_PPC64_ADDR64 mach_ + # R_PPC64_ADDR64 __crc_ # On PPC: # R_PPC_RELATIVE, R_PPC_ADDR16_HI, # R_PPC_ADDR16_HA,R_PPC_ADDR16_LO, @@ -41,7 +42,8 @@ R_PPC_ADDR16_HI R_PPC_ADDR16_HA R_PPC_RELATIVE R_PPC_NONE' | - grep -E -v '\ Date: Thu, 15 Sep 2016 16:04:12 +1000 Subject: [PATCH 0092/1167] ppc: there is no clear_pages to export Fixes: 9445aa1a3062 ("ppc: move exports to definitions") Signed-off-by: Stephen Rothwell Signed-off-by: Michal Marek --- arch/powerpc/kernel/misc_32.S | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index ea26a9181586a..f5156105c5f31 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -453,7 +453,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) stw r7,8(r3); \ stw r8,12(r3); \ stwu r9,16(r3) -EXPORT_SYMBOL(clear_pages) _GLOBAL(copy_page) addi r3,r3,-4 -- GitLab From 02d9d3cbac53bd59fe18fc32adc7bc7cde1037ae Mon Sep 17 00:00:00 2001 From: Harman Kalra Date: Thu, 22 Sep 2016 01:29:48 +0530 Subject: [PATCH 0093/1167] ata: Replace BUG() with BUG_ON(). Replace BUG() with BUG_ON(). Caught by coccinelle. Signed-off-by: Harman Kalra Signed-off-by: Tejun Heo --- drivers/ata/pata_octeon_cf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index 27245957eee3c..475a006694273 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -152,8 +152,7 @@ static void octeon_cf_set_piomode(struct ata_port *ap, struct ata_device *dev) div = 8; T = (int)((1000000000000LL * div) / octeon_get_io_clock_rate()); - if (ata_timing_compute(dev, dev->pio_mode, &timing, T, T)) - BUG(); + BUG_ON(ata_timing_compute(dev, dev->pio_mode, &timing, T, T)); t1 = timing.setup; if (t1) -- GitLab From 70a19b7e406da9dc5cea20fedba443374a5cae70 Mon Sep 17 00:00:00 2001 From: Harman Kalra Date: Thu, 22 Sep 2016 01:18:31 +0530 Subject: [PATCH 0094/1167] pata_at91: Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR Signed-off-by: Harman Kalra Signed-off-by: Tejun Heo --- drivers/ata/pata_at91.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index 9f27b14009f9e..1611e0e8d7678 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -347,10 +347,8 @@ static int at91sam9_smc_fields_init(struct device *dev) field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC); fields.mode = devm_regmap_field_alloc(dev, smc, field); - if (IS_ERR(fields.mode)) - return PTR_ERR(fields.mode); - return 0; + return PTR_ERR_OR_ZERO(fields.mode); } static int pata_at91_probe(struct platform_device *pdev) -- GitLab From 014b44e7a4683ccef09cc58c53012e5bc53daece Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 22 Sep 2016 07:49:49 -0700 Subject: [PATCH 0095/1167] libata: remove unused definitions from Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- arch/ia64/include/asm/libata-portmap.h | 4 ---- arch/powerpc/include/asm/libata-portmap.h | 4 ---- 2 files changed, 8 deletions(-) diff --git a/arch/ia64/include/asm/libata-portmap.h b/arch/ia64/include/asm/libata-portmap.h index 0e00c9a9f4100..7a1f8310596be 100644 --- a/arch/ia64/include/asm/libata-portmap.h +++ b/arch/ia64/include/asm/libata-portmap.h @@ -1,12 +1,8 @@ #ifndef __ASM_IA64_LIBATA_PORTMAP_H #define __ASM_IA64_LIBATA_PORTMAP_H -#define ATA_PRIMARY_CMD 0x1F0 -#define ATA_PRIMARY_CTL 0x3F6 #define ATA_PRIMARY_IRQ(dev) isa_irq_to_vector(14) -#define ATA_SECONDARY_CMD 0x170 -#define ATA_SECONDARY_CTL 0x376 #define ATA_SECONDARY_IRQ(dev) isa_irq_to_vector(15) #endif diff --git a/arch/powerpc/include/asm/libata-portmap.h b/arch/powerpc/include/asm/libata-portmap.h index 4d8518049f4df..4396db57b8be1 100644 --- a/arch/powerpc/include/asm/libata-portmap.h +++ b/arch/powerpc/include/asm/libata-portmap.h @@ -1,12 +1,8 @@ #ifndef __ASM_POWERPC_LIBATA_PORTMAP_H #define __ASM_POWERPC_LIBATA_PORTMAP_H -#define ATA_PRIMARY_CMD 0x1F0 -#define ATA_PRIMARY_CTL 0x3F6 #define ATA_PRIMARY_IRQ(dev) pci_get_legacy_ide_irq(dev, 0) -#define ATA_SECONDARY_CMD 0x170 -#define ATA_SECONDARY_CTL 0x376 #define ATA_SECONDARY_IRQ(dev) pci_get_legacy_ide_irq(dev, 1) #endif -- GitLab From dcd3ea81f572fba57d18e91743a525a9787c1f6e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 22 Sep 2016 07:49:50 -0700 Subject: [PATCH 0096/1167] libata: remove asm-generic is only intended for architecture defaults, and we can simply kill it off by moving the two defintions directly to . Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- include/asm-generic/libata-portmap.h | 7 ------- include/linux/libata.h | 3 ++- 2 files changed, 2 insertions(+), 8 deletions(-) delete mode 100644 include/asm-generic/libata-portmap.h diff --git a/include/asm-generic/libata-portmap.h b/include/asm-generic/libata-portmap.h deleted file mode 100644 index cf14f2ff40b66..0000000000000 --- a/include/asm-generic/libata-portmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ASM_GENERIC_LIBATA_PORTMAP_H -#define __ASM_GENERIC_LIBATA_PORTMAP_H - -#define ATA_PRIMARY_IRQ(dev) 14 -#define ATA_SECONDARY_IRQ(dev) 15 - -#endif diff --git a/include/linux/libata.h b/include/linux/libata.h index e37d4f99f510a..616eef4d81ea3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -46,7 +46,8 @@ #ifdef CONFIG_ATA_NONSTANDARD #include #else -#include +#define ATA_PRIMARY_IRQ(dev) 14 +#define ATA_SECONDARY_IRQ(dev) 15 #endif /* -- GitLab From 1b5ca12127427c51be605a75ecd0141eb3357249 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 22 Sep 2016 11:55:54 -0400 Subject: [PATCH 0097/1167] percpu: improve generic percpu modify-return implementation Some architectures require an additional load to find the address of percpu pointers. In some implemenatations, the C aliasing rules do not allow the result of that load to be kept over the store that modifies the percpu variable, which causes additional loads. Work around this by finding the pointer first, then operating on that. It's also possible to mark things as restrict and those kind of games, but that can require larger and arch specific changes. On powerpc, __this_cpu_inc_return compiles to: ld 10,48(13) ldx 9,3,10 addi 9,9,1 stdx 9,3,10 ld 9,48(13) ldx 3,9,3 With this patch it compiles to: ld 10,48(13) ldx 9,3,10 addi 9,9,1 stdx 9,3,10 Signed-off-by: Nicholas Piggin To: Tejun Heo To: Christoph Lameter Cc: linux-kernel@vger.kernel.org Cc: linux-arch@vger.kernel.org Signed-off-by: Tejun Heo --- include/asm-generic/percpu.h | 53 ++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index 4d9f233c4ba83..40e887068da21 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h @@ -65,6 +65,11 @@ extern void setup_per_cpu_areas(void); #define PER_CPU_DEF_ATTRIBUTES #endif +#define raw_cpu_generic_read(pcp) \ +({ \ + *raw_cpu_ptr(&(pcp)); \ +}) + #define raw_cpu_generic_to_op(pcp, val, op) \ do { \ *raw_cpu_ptr(&(pcp)) op val; \ @@ -72,34 +77,39 @@ do { \ #define raw_cpu_generic_add_return(pcp, val) \ ({ \ - raw_cpu_add(pcp, val); \ - raw_cpu_read(pcp); \ + typeof(&(pcp)) __p = raw_cpu_ptr(&(pcp)); \ + \ + *__p += val; \ + *__p; \ }) #define raw_cpu_generic_xchg(pcp, nval) \ ({ \ + typeof(&(pcp)) __p = raw_cpu_ptr(&(pcp)); \ typeof(pcp) __ret; \ - __ret = raw_cpu_read(pcp); \ - raw_cpu_write(pcp, nval); \ + __ret = *__p; \ + *__p = nval; \ __ret; \ }) #define raw_cpu_generic_cmpxchg(pcp, oval, nval) \ ({ \ + typeof(&(pcp)) __p = raw_cpu_ptr(&(pcp)); \ typeof(pcp) __ret; \ - __ret = raw_cpu_read(pcp); \ + __ret = *__p; \ if (__ret == (oval)) \ - raw_cpu_write(pcp, nval); \ + *__p = nval; \ __ret; \ }) #define raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ ({ \ + typeof(&(pcp1)) __p1 = raw_cpu_ptr(&(pcp1)); \ + typeof(&(pcp2)) __p2 = raw_cpu_ptr(&(pcp2)); \ int __ret = 0; \ - if (raw_cpu_read(pcp1) == (oval1) && \ - raw_cpu_read(pcp2) == (oval2)) { \ - raw_cpu_write(pcp1, nval1); \ - raw_cpu_write(pcp2, nval2); \ + if (*__p1 == (oval1) && *__p2 == (oval2)) { \ + *__p1 = nval1; \ + *__p2 = nval2; \ __ret = 1; \ } \ (__ret); \ @@ -109,7 +119,7 @@ do { \ ({ \ typeof(pcp) __ret; \ preempt_disable(); \ - __ret = *this_cpu_ptr(&(pcp)); \ + __ret = raw_cpu_generic_read(pcp); \ preempt_enable(); \ __ret; \ }) @@ -118,17 +128,17 @@ do { \ do { \ unsigned long __flags; \ raw_local_irq_save(__flags); \ - *raw_cpu_ptr(&(pcp)) op val; \ + raw_cpu_generic_to_op(pcp, val, op); \ raw_local_irq_restore(__flags); \ } while (0) + #define this_cpu_generic_add_return(pcp, val) \ ({ \ typeof(pcp) __ret; \ unsigned long __flags; \ raw_local_irq_save(__flags); \ - raw_cpu_add(pcp, val); \ - __ret = raw_cpu_read(pcp); \ + __ret = raw_cpu_generic_add_return(pcp, val); \ raw_local_irq_restore(__flags); \ __ret; \ }) @@ -138,8 +148,7 @@ do { \ typeof(pcp) __ret; \ unsigned long __flags; \ raw_local_irq_save(__flags); \ - __ret = raw_cpu_read(pcp); \ - raw_cpu_write(pcp, nval); \ + __ret = raw_cpu_generic_xchg(pcp, nval); \ raw_local_irq_restore(__flags); \ __ret; \ }) @@ -149,9 +158,7 @@ do { \ typeof(pcp) __ret; \ unsigned long __flags; \ raw_local_irq_save(__flags); \ - __ret = raw_cpu_read(pcp); \ - if (__ret == (oval)) \ - raw_cpu_write(pcp, nval); \ + __ret = raw_cpu_generic_cmpxchg(pcp, oval, nval); \ raw_local_irq_restore(__flags); \ __ret; \ }) @@ -168,16 +175,16 @@ do { \ }) #ifndef raw_cpu_read_1 -#define raw_cpu_read_1(pcp) (*raw_cpu_ptr(&(pcp))) +#define raw_cpu_read_1(pcp) raw_cpu_generic_read(pcp) #endif #ifndef raw_cpu_read_2 -#define raw_cpu_read_2(pcp) (*raw_cpu_ptr(&(pcp))) +#define raw_cpu_read_2(pcp) raw_cpu_generic_read(pcp) #endif #ifndef raw_cpu_read_4 -#define raw_cpu_read_4(pcp) (*raw_cpu_ptr(&(pcp))) +#define raw_cpu_read_4(pcp) raw_cpu_generic_read(pcp) #endif #ifndef raw_cpu_read_8 -#define raw_cpu_read_8(pcp) (*raw_cpu_ptr(&(pcp))) +#define raw_cpu_read_8(pcp) raw_cpu_generic_read(pcp) #endif #ifndef raw_cpu_write_1 -- GitLab From 799bc3c51b2b120ca6e59e702ede23fff2efaf43 Mon Sep 17 00:00:00 2001 From: Lance Richardson Date: Thu, 22 Sep 2016 10:03:57 -0400 Subject: [PATCH 0098/1167] percpu: eliminate two sparse warnings Fix two cases where a __percpu pointer cast drops __percpu. Signed-off-by: Lance Richardson Signed-off-by: Tejun Heo --- arch/x86/include/asm/percpu.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index e02e3f80d363b..84f58de08c2bd 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -521,7 +521,8 @@ do { \ static __always_inline bool x86_this_cpu_constant_test_bit(unsigned int nr, const unsigned long __percpu *addr) { - unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG; + unsigned long __percpu *a = + (unsigned long __percpu *)addr + nr / BITS_PER_LONG; #ifdef CONFIG_X86_64 return ((1UL << (nr % BITS_PER_LONG)) & raw_cpu_read_8(*a)) != 0; @@ -538,7 +539,7 @@ static inline bool x86_this_cpu_variable_test_bit(int nr, asm volatile("bt "__percpu_arg(2)",%1\n\t" CC_SET(c) : CC_OUT(c) (oldbit) - : "m" (*(unsigned long *)addr), "Ir" (nr)); + : "m" (*(unsigned long __percpu *)addr), "Ir" (nr)); return oldbit; } -- GitLab From 590abbdd273304b55824bcb9ea91840ea375575d Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Fri, 23 Sep 2016 09:56:05 +0200 Subject: [PATCH 0099/1167] initramfs: Escape colons in depfile Special characters are problematic in depfiles, but we can fix colons easily. Reported-by: Florian Fainelli Signed-off-by: Michal Marek --- scripts/gen_initramfs_list.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh index 17fa901418ae6..0055b07b03b68 100755 --- a/scripts/gen_initramfs_list.sh +++ b/scripts/gen_initramfs_list.sh @@ -97,7 +97,10 @@ print_mtime() { } list_parse() { - [ ! -L "$1" ] && echo "$1 \\" || : + if [ -L "$1" ]; then + return + fi + echo "$1" | sed 's/:/\\:/g; s/$/ \\/' } # for each file print a line in following format -- GitLab From 986b891ad121c61200d3dffcc8ed128a1397682e Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 16 Sep 2016 16:07:20 -0600 Subject: [PATCH 0100/1167] samples: move misc-devices/mei example code from Documentation Move misc-devices/mei examples to samples/mei and remove it from Documentation Makefile. Delete misc-devices/Makefile. Create a new Makefile to build samples/mei. It can be built from top level directory or from mei directory: Run make -C samples/mei or cd samples/mei; make Acked-by: Jonathan Corbet Acked-by: Greg Kroah-Hartman Acked-by: Tomas Winkler Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/misc-devices/Makefile | 1 - Documentation/misc-devices/mei/Makefile | 5 ----- MAINTAINERS | 1 + {Documentation/misc-devices => samples}/mei/.gitignore | 0 samples/mei/Makefile | 9 +++++++++ {Documentation/misc-devices => samples}/mei/TODO | 0 .../misc-devices => samples}/mei/mei-amt-version.c | 0 8 files changed, 11 insertions(+), 7 deletions(-) delete mode 100644 Documentation/misc-devices/Makefile delete mode 100644 Documentation/misc-devices/mei/Makefile rename {Documentation/misc-devices => samples}/mei/.gitignore (100%) create mode 100644 samples/mei/Makefile rename {Documentation/misc-devices => samples}/mei/TODO (100%) rename {Documentation/misc-devices => samples}/mei/mei-amt-version.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index 80b5bdc65055f..3c2a207a7c40a 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ subdir-y := accounting auxdisplay blackfin \ - laptops misc-devices pcmcia timers watchdog + laptops pcmcia timers watchdog diff --git a/Documentation/misc-devices/Makefile b/Documentation/misc-devices/Makefile deleted file mode 100644 index e2b7aa4c9e21c..0000000000000 --- a/Documentation/misc-devices/Makefile +++ /dev/null @@ -1 +0,0 @@ -subdir-y := mei diff --git a/Documentation/misc-devices/mei/Makefile b/Documentation/misc-devices/mei/Makefile deleted file mode 100644 index d758047d1b6d5..0000000000000 --- a/Documentation/misc-devices/mei/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# List of programs to build -hostprogs-y := mei-amt-version -HOSTCFLAGS_mei-amt-version.o += -I$(objtree)/usr/include -# Tell kbuild to always build the programs -always := $(hostprogs-y) diff --git a/MAINTAINERS b/MAINTAINERS index 20bb1d00098c7..b76872ace843f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6244,6 +6244,7 @@ F: include/linux/mei_cl_bus.h F: drivers/misc/mei/* F: drivers/watchdog/mei_wdt.c F: Documentation/misc-devices/mei/* +F: samples/mei/* INTEL MIC DRIVERS (mic) M: Sudeep Dutt diff --git a/Documentation/misc-devices/mei/.gitignore b/samples/mei/.gitignore similarity index 100% rename from Documentation/misc-devices/mei/.gitignore rename to samples/mei/.gitignore diff --git a/samples/mei/Makefile b/samples/mei/Makefile new file mode 100644 index 0000000000000..7aac216dc420b --- /dev/null +++ b/samples/mei/Makefile @@ -0,0 +1,9 @@ +CC := $(CROSS_COMPILE)gcc +CFLAGS := -I../../usr/include + +PROGS := mei-amt-version + +all: $(PROGS) + +clean: + rm -fr $(PROGS) diff --git a/Documentation/misc-devices/mei/TODO b/samples/mei/TODO similarity index 100% rename from Documentation/misc-devices/mei/TODO rename to samples/mei/TODO diff --git a/Documentation/misc-devices/mei/mei-amt-version.c b/samples/mei/mei-amt-version.c similarity index 100% rename from Documentation/misc-devices/mei/mei-amt-version.c rename to samples/mei/mei-amt-version.c -- GitLab From 155fe001c6cd840c1cef3a8c42a8f14296a47c57 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 16 Sep 2016 17:20:42 -0600 Subject: [PATCH 0101/1167] samples: move timers example code from Documentation Move timers examples to samples and remove it from Documentation Makefile. Create a new Makefile to build timers. It can be built from top level directory or from timers directory: Run make -C samples/timers or cd samples/timers; make Acked-by: Jonathan Corbet Acked-by: Clemens Ladisch Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/timers/Makefile | 5 ----- Documentation/timers/hpet.txt | 2 +- {Documentation => samples}/timers/.gitignore | 0 samples/timers/Makefile | 15 +++++++++++++++ {Documentation => samples}/timers/hpet_example.c | 0 6 files changed, 17 insertions(+), 7 deletions(-) delete mode 100644 Documentation/timers/Makefile rename {Documentation => samples}/timers/.gitignore (100%) create mode 100644 samples/timers/Makefile rename {Documentation => samples}/timers/hpet_example.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index 3c2a207a7c40a..fc386b7a01b2b 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ subdir-y := accounting auxdisplay blackfin \ - laptops pcmcia timers watchdog + laptops pcmcia watchdog diff --git a/Documentation/timers/Makefile b/Documentation/timers/Makefile deleted file mode 100644 index 6c09ee6ca7219..0000000000000 --- a/Documentation/timers/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# List of programs to build -hostprogs-$(CONFIG_X86) := hpet_example - -# Tell kbuild to always build the programs -always := $(hostprogs-y) diff --git a/Documentation/timers/hpet.txt b/Documentation/timers/hpet.txt index a484d2c109d7f..895345ec513b5 100644 --- a/Documentation/timers/hpet.txt +++ b/Documentation/timers/hpet.txt @@ -25,4 +25,4 @@ arch/x86/kernel/hpet.c. The driver provides a userspace API which resembles the API found in the RTC driver framework. An example user space program is provided in -file:Documentation/timers/hpet_example.c +file:samples/timers/hpet_example.c diff --git a/Documentation/timers/.gitignore b/samples/timers/.gitignore similarity index 100% rename from Documentation/timers/.gitignore rename to samples/timers/.gitignore diff --git a/samples/timers/Makefile b/samples/timers/Makefile new file mode 100644 index 0000000000000..a5c3c4a35ca14 --- /dev/null +++ b/samples/timers/Makefile @@ -0,0 +1,15 @@ +ifndef CROSS_COMPILE +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) + +ifeq ($(ARCH),x86) +CC := $(CROSS_COMPILE)gcc +PROGS := hpet_example + +all: $(PROGS) + +clean: + rm -fr $(PROGS) + +endif +endif diff --git a/Documentation/timers/hpet_example.c b/samples/timers/hpet_example.c similarity index 100% rename from Documentation/timers/hpet_example.c rename to samples/timers/hpet_example.c -- GitLab From 071bf69a0220253a44acb8b2a27f7a262b9a46bf Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 16 Sep 2016 17:40:40 -0600 Subject: [PATCH 0102/1167] samples: move watchdog example code from Documentation Move watchdog examples to samples and remove it from Documentation Makefile. Create a new Makefile to build watchdog. It can be built from top level directory or from watchdog directory: Run make -C samples/watchdog or cd samples/watchdog; make Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/watchdog/Makefile | 1 - Documentation/watchdog/src/Makefile | 5 ----- Documentation/watchdog/watchdog-api.txt | 2 +- Documentation/watchdog/wdt.txt | 2 +- .../watchdog/src => samples/watchdog}/.gitignore | 0 samples/watchdog/Makefile | 8 ++++++++ .../watchdog/src => samples/watchdog}/watchdog-simple.c | 0 8 files changed, 11 insertions(+), 9 deletions(-) delete mode 100644 Documentation/watchdog/Makefile delete mode 100644 Documentation/watchdog/src/Makefile rename {Documentation/watchdog/src => samples/watchdog}/.gitignore (100%) create mode 100644 samples/watchdog/Makefile rename {Documentation/watchdog/src => samples/watchdog}/watchdog-simple.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index fc386b7a01b2b..b2210b7af2e5d 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ subdir-y := accounting auxdisplay blackfin \ - laptops pcmcia watchdog + laptops pcmcia diff --git a/Documentation/watchdog/Makefile b/Documentation/watchdog/Makefile deleted file mode 100644 index 6018f45f24714..0000000000000 --- a/Documentation/watchdog/Makefile +++ /dev/null @@ -1 +0,0 @@ -subdir-y := src diff --git a/Documentation/watchdog/src/Makefile b/Documentation/watchdog/src/Makefile deleted file mode 100644 index 47be791827d48..0000000000000 --- a/Documentation/watchdog/src/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# List of programs to build -hostprogs-y := watchdog-simple - -# Tell kbuild to always build the programs -always := $(hostprogs-y) diff --git a/Documentation/watchdog/watchdog-api.txt b/Documentation/watchdog/watchdog-api.txt index b3a701f481189..0e62ba33b7fbb 100644 --- a/Documentation/watchdog/watchdog-api.txt +++ b/Documentation/watchdog/watchdog-api.txt @@ -37,7 +37,7 @@ activates as soon as /dev/watchdog is opened and will reboot unless the watchdog is pinged within a certain time, this time is called the timeout or margin. The simplest way to ping the watchdog is to write some data to the device. So a very simple watchdog daemon would look -like this source file: see Documentation/watchdog/src/watchdog-simple.c +like this source file: see samples/watchdog/watchdog-simple.c A more advanced driver could for example check that a HTTP server is still responding before doing the write call to ping the watchdog. diff --git a/Documentation/watchdog/wdt.txt b/Documentation/watchdog/wdt.txt index 061c2e35384f5..ed2f0b860869b 100644 --- a/Documentation/watchdog/wdt.txt +++ b/Documentation/watchdog/wdt.txt @@ -47,4 +47,4 @@ The external event interfaces on the WDT boards are not currently supported. Minor numbers are however allocated for it. -Example Watchdog Driver: see Documentation/watchdog/src/watchdog-simple.c +Example Watchdog Driver: see samples/watchdog/watchdog-simple.c diff --git a/Documentation/watchdog/src/.gitignore b/samples/watchdog/.gitignore similarity index 100% rename from Documentation/watchdog/src/.gitignore rename to samples/watchdog/.gitignore diff --git a/samples/watchdog/Makefile b/samples/watchdog/Makefile new file mode 100644 index 0000000000000..9b53d89b1ccf2 --- /dev/null +++ b/samples/watchdog/Makefile @@ -0,0 +1,8 @@ +CC := $(CROSS_COMPILE)gcc +PROGS := watchdog-simple + +all: $(PROGS) + +clean: + rm -fr $(PROGS) + diff --git a/Documentation/watchdog/src/watchdog-simple.c b/samples/watchdog/watchdog-simple.c similarity index 100% rename from Documentation/watchdog/src/watchdog-simple.c rename to samples/watchdog/watchdog-simple.c -- GitLab From 8fc07ebe63a40c312730da28e54dbb4fc6029ca3 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 16 Sep 2016 07:36:21 -0600 Subject: [PATCH 0103/1167] samples: move auxdisplay example code from Documentation Move auxdisplay examples to samples and remove it from Documentation Makefile. Create a new Makefile to build auxdisplay. It can be built from top level directory or from auxdisplay directory: Run make -C samples/auxdisplay or cd samples/auxdisplay; make Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/auxdisplay/Makefile | 7 ------- Documentation/auxdisplay/cfag12864b | 2 +- {Documentation => samples}/auxdisplay/.gitignore | 0 samples/auxdisplay/Makefile | 9 +++++++++ .../auxdisplay/cfag12864b-example.c | 0 6 files changed, 11 insertions(+), 9 deletions(-) delete mode 100644 Documentation/auxdisplay/Makefile rename {Documentation => samples}/auxdisplay/.gitignore (100%) create mode 100644 samples/auxdisplay/Makefile rename {Documentation => samples}/auxdisplay/cfag12864b-example.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index b2210b7af2e5d..0b8cd503224cf 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ -subdir-y := accounting auxdisplay blackfin \ +subdir-y := accounting blackfin \ laptops pcmcia diff --git a/Documentation/auxdisplay/Makefile b/Documentation/auxdisplay/Makefile deleted file mode 100644 index ada4dac99ef40..0000000000000 --- a/Documentation/auxdisplay/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# List of programs to build -hostprogs-y := cfag12864b-example - -# Tell kbuild to always build the programs -always := $(hostprogs-y) - -HOSTCFLAGS_cfag12864b-example.o += -I$(objtree)/usr/include diff --git a/Documentation/auxdisplay/cfag12864b b/Documentation/auxdisplay/cfag12864b index eb7be393a5106..12fd51b8de757 100644 --- a/Documentation/auxdisplay/cfag12864b +++ b/Documentation/auxdisplay/cfag12864b @@ -101,5 +101,5 @@ Although the LCD won't get updated until the next refresh time arrives. Also, you can mmap the framebuffer: open & mmap, munmap & close... which is the best option for most uses. -Check Documentation/auxdisplay/cfag12864b-example.c +Check samples/auxdisplay/cfag12864b-example.c for a real working userspace complete program with usage examples. diff --git a/Documentation/auxdisplay/.gitignore b/samples/auxdisplay/.gitignore similarity index 100% rename from Documentation/auxdisplay/.gitignore rename to samples/auxdisplay/.gitignore diff --git a/samples/auxdisplay/Makefile b/samples/auxdisplay/Makefile new file mode 100644 index 0000000000000..05e471feb6e5f --- /dev/null +++ b/samples/auxdisplay/Makefile @@ -0,0 +1,9 @@ +CC := $(CROSS_COMPILE)gcc +CFLAGS := -I../../usr/include + +PROGS := cfag12864b-example + +all: $(PROGS) + +clean: + rm -fr $(PROGS) diff --git a/Documentation/auxdisplay/cfag12864b-example.c b/samples/auxdisplay/cfag12864b-example.c similarity index 100% rename from Documentation/auxdisplay/cfag12864b-example.c rename to samples/auxdisplay/cfag12864b-example.c -- GitLab From d522b2cdfed853e372d6b64a89d070368f0718f7 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 21 Sep 2016 16:19:35 -0600 Subject: [PATCH 0104/1167] tools: move accounting tool from Documentation Move accounting tool to tools and remove it from Documentation Makefile. Update location information for this tool. Create a new Makefile to build accounting. It can be built from top level directory or from accounting directory: Run make -C tools/accounting or cd tools/accounting; make Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/accounting/Makefile | 7 ------- Documentation/accounting/delay-accounting.txt | 6 +++--- {Documentation => tools}/accounting/.gitignore | 0 tools/accounting/Makefile | 9 +++++++++ {Documentation => tools}/accounting/getdelays.c | 0 6 files changed, 13 insertions(+), 11 deletions(-) delete mode 100644 Documentation/accounting/Makefile rename {Documentation => tools}/accounting/.gitignore (100%) create mode 100644 tools/accounting/Makefile rename {Documentation => tools}/accounting/getdelays.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index 0b8cd503224cf..e4dd5e4614a42 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ -subdir-y := accounting blackfin \ +subdir-y := blackfin \ laptops pcmcia diff --git a/Documentation/accounting/Makefile b/Documentation/accounting/Makefile deleted file mode 100644 index 7e232cb6fd7d1..0000000000000 --- a/Documentation/accounting/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# List of programs to build -hostprogs-y := getdelays - -# Tell kbuild to always build the programs -always := $(hostprogs-y) - -HOSTCFLAGS_getdelays.o += -I$(objtree)/usr/include diff --git a/Documentation/accounting/delay-accounting.txt b/Documentation/accounting/delay-accounting.txt index 8a12f0730c94d..042ea59b5853b 100644 --- a/Documentation/accounting/delay-accounting.txt +++ b/Documentation/accounting/delay-accounting.txt @@ -54,9 +54,9 @@ are sent to userspace without requiring a command. If it is the last exiting task of a thread group, the per-tgid statistics are also sent. More details are given in the taskstats interface description. -The getdelays.c userspace utility in this directory allows simple commands to -be run and the corresponding delay statistics to be displayed. It also serves -as an example of using the taskstats interface. +The getdelays.c userspace utility in tools/accounting directory allows simple +commands to be run and the corresponding delay statistics to be displayed. It +also serves as an example of using the taskstats interface. Usage ----- diff --git a/Documentation/accounting/.gitignore b/tools/accounting/.gitignore similarity index 100% rename from Documentation/accounting/.gitignore rename to tools/accounting/.gitignore diff --git a/tools/accounting/Makefile b/tools/accounting/Makefile new file mode 100644 index 0000000000000..647c94a219bf5 --- /dev/null +++ b/tools/accounting/Makefile @@ -0,0 +1,9 @@ +CC := $(CROSS_COMPILE)gcc +CFLAGS := -I../../usr/include + +PROGS := getdelays + +all: $(PROGS) + +clean: + rm -fr $(PROGS) diff --git a/Documentation/accounting/getdelays.c b/tools/accounting/getdelays.c similarity index 100% rename from Documentation/accounting/getdelays.c rename to tools/accounting/getdelays.c -- GitLab From 3ca9760fdfa411f7e5db54b3437fbb858d2ec825 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 21 Sep 2016 16:34:55 -0600 Subject: [PATCH 0105/1167] tools: move laptops dslm tool from Documentation Move laptops dslm tool to tools/laptop/dslm and remove it from Documentation Makefile. Update location information for this tool. Create a new Makefile to build dslm. It can be built from top level directory or from laptops directory: Run make -C tools/laptop/dslm or cd tools/laptop/dslm; make Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/laptops/00-INDEX | 4 ---- Documentation/laptops/Makefile | 5 ----- Documentation/laptops/laptop-mode.txt | 2 +- {Documentation/laptops => tools/laptop/dslm}/.gitignore | 0 tools/laptop/dslm/Makefile | 9 +++++++++ {Documentation/laptops => tools/laptop/dslm}/dslm.c | 0 7 files changed, 11 insertions(+), 11 deletions(-) delete mode 100644 Documentation/laptops/Makefile rename {Documentation/laptops => tools/laptop/dslm}/.gitignore (100%) create mode 100644 tools/laptop/dslm/Makefile rename {Documentation/laptops => tools/laptop/dslm}/dslm.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index e4dd5e4614a42..0ddb50c3cfc44 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ subdir-y := blackfin \ - laptops pcmcia + pcmcia diff --git a/Documentation/laptops/00-INDEX b/Documentation/laptops/00-INDEX index 7c0ac2a26b9e7..86169dc766f7b 100644 --- a/Documentation/laptops/00-INDEX +++ b/Documentation/laptops/00-INDEX @@ -1,13 +1,9 @@ 00-INDEX - This file -Makefile - - Makefile for building dslm example program. asus-laptop.txt - information on the Asus Laptop Extras driver. disk-shock-protection.txt - information on hard disk shock protection. -dslm.c - - Simple Disk Sleep Monitor program laptop-mode.txt - how to conserve battery power using laptop-mode. sony-laptop.txt diff --git a/Documentation/laptops/Makefile b/Documentation/laptops/Makefile deleted file mode 100644 index 0abe44f68965e..0000000000000 --- a/Documentation/laptops/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# List of programs to build -hostprogs-y := dslm - -# Tell kbuild to always build the programs -always := $(hostprogs-y) diff --git a/Documentation/laptops/laptop-mode.txt b/Documentation/laptops/laptop-mode.txt index 4ebbfc3f1c6ea..19276f5d195cb 100644 --- a/Documentation/laptops/laptop-mode.txt +++ b/Documentation/laptops/laptop-mode.txt @@ -779,4 +779,4 @@ Monitoring tool --------------- Bartek Kania submitted this, it can be used to measure how much time your disk -spends spun up/down. See Documentation/laptops/dslm.c +spends spun up/down. See tools/laptop/dslm/dslm.c diff --git a/Documentation/laptops/.gitignore b/tools/laptop/dslm/.gitignore similarity index 100% rename from Documentation/laptops/.gitignore rename to tools/laptop/dslm/.gitignore diff --git a/tools/laptop/dslm/Makefile b/tools/laptop/dslm/Makefile new file mode 100644 index 0000000000000..ff613b31730b3 --- /dev/null +++ b/tools/laptop/dslm/Makefile @@ -0,0 +1,9 @@ +CC := $(CROSS_COMPILE)gcc +CFLAGS := -I../../usr/include + +PROGS := dslm + +all: $(PROGS) + +clean: + rm -fr $(PROGS) diff --git a/Documentation/laptops/dslm.c b/tools/laptop/dslm/dslm.c similarity index 100% rename from Documentation/laptops/dslm.c rename to tools/laptop/dslm/dslm.c -- GitLab From a67cd5482f37a255b9990ddb942aa7009dcba12f Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 21 Sep 2016 16:54:36 -0600 Subject: [PATCH 0106/1167] tools: move pcmcia crc32hash tool from Documentation Move pcmcia crc32hash tool from Documentation to tools/pcmcia and remove it from Documentation Makefile. Update location information for this tool. Create a new Makefile to build pcmcia. It can be built from top level directory or from pcmcia directory: Run make -C tools/pcmcia or cd tools/pcmcia; make Acked-by: Dominik Brodowski Acked-by: Greg Kroah-Hartman Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 3 +-- Documentation/pcmcia/Makefile | 7 ------- Documentation/pcmcia/devicetable.txt | 4 ++-- MAINTAINERS | 1 + {Documentation => tools}/pcmcia/.gitignore | 0 tools/pcmcia/Makefile | 9 +++++++++ {Documentation => tools}/pcmcia/crc32hash.c | 0 7 files changed, 13 insertions(+), 11 deletions(-) delete mode 100644 Documentation/pcmcia/Makefile rename {Documentation => tools}/pcmcia/.gitignore (100%) create mode 100644 tools/pcmcia/Makefile rename {Documentation => tools}/pcmcia/crc32hash.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index 0ddb50c3cfc44..84359654cfcbd 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1 @@ -subdir-y := blackfin \ - pcmcia +subdir-y := blackfin diff --git a/Documentation/pcmcia/Makefile b/Documentation/pcmcia/Makefile deleted file mode 100644 index 47a8fa162683f..0000000000000 --- a/Documentation/pcmcia/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# List of programs to build -hostprogs-y := crc32hash - -# Tell kbuild to always build the programs -always := $(hostprogs-y) - -HOSTCFLAGS_crc32hash.o += -I$(objtree)/usr/include diff --git a/Documentation/pcmcia/devicetable.txt b/Documentation/pcmcia/devicetable.txt index 199afd100cf27..5f3e00ab54c42 100644 --- a/Documentation/pcmcia/devicetable.txt +++ b/Documentation/pcmcia/devicetable.txt @@ -27,7 +27,7 @@ pcmcia:m0149cC1ABf06pfn00fn00pa725B842DpbF1EFEE84pc0877B627pd00000000 The hex value after "pa" is the hash of product ID string 1, after "pb" for string 2 and so on. -Alternatively, you can use crc32hash (see Documentation/pcmcia/crc32hash.c) +Alternatively, you can use crc32hash (see tools/pcmcia/crc32hash.c) to determine the crc32 hash. Simply pass the string you want to evaluate as argument to this program, e.g.: -$ ./crc32hash "Dual Speed" +$ tools/pcmcia/crc32hash "Dual Speed" diff --git a/MAINTAINERS b/MAINTAINERS index b76872ace843f..01b13a5f331a2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9106,6 +9106,7 @@ W: http://lists.infradead.org/mailman/listinfo/linux-pcmcia T: git git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia.git S: Maintained F: Documentation/pcmcia/ +F: tools/pcmcia/ F: drivers/pcmcia/ F: include/pcmcia/ diff --git a/Documentation/pcmcia/.gitignore b/tools/pcmcia/.gitignore similarity index 100% rename from Documentation/pcmcia/.gitignore rename to tools/pcmcia/.gitignore diff --git a/tools/pcmcia/Makefile b/tools/pcmcia/Makefile new file mode 100644 index 0000000000000..81a7498c5cd9e --- /dev/null +++ b/tools/pcmcia/Makefile @@ -0,0 +1,9 @@ +CC := $(CROSS_COMPILE)gcc +CFLAGS := -I../../usr/include + +PROGS := crc32hash + +all: $(PROGS) + +clean: + rm -fr $(PROGS) diff --git a/Documentation/pcmcia/crc32hash.c b/tools/pcmcia/crc32hash.c similarity index 100% rename from Documentation/pcmcia/crc32hash.c rename to tools/pcmcia/crc32hash.c -- GitLab From 40f1ebd4e0997e81ac2eb3b2f64d6133051afe86 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Sat, 24 Sep 2016 12:10:06 +0530 Subject: [PATCH 0107/1167] soc/fsl/qe: Use resource_size Use the function resource_size instead of explicit computation. Problem found using Coccinelle. Signed-off-by: Vaishali Thakkar Signed-off-by: Scott Wood --- drivers/soc/fsl/qe/qe_tdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/qe_tdm.c b/drivers/soc/fsl/qe/qe_tdm.c index 5e48b14701786..124e222a0d189 100644 --- a/drivers/soc/fsl/qe/qe_tdm.c +++ b/drivers/soc/fsl/qe/qe_tdm.c @@ -167,7 +167,7 @@ int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm, } if (siram_init_flag == 0) { - memset_io(utdm->siram, 0, res->end - res->start + 1); + memset_io(utdm->siram, 0, resource_size(res)); siram_init_flag = 1; } -- GitLab From 5066943a5170838e58e07163d32ba45b0b360417 Mon Sep 17 00:00:00 2001 From: Zhao Qiang Date: Fri, 23 Sep 2016 10:20:31 +0800 Subject: [PATCH 0108/1167] soc/fsl/qe: Use of_adress_to_resource() in get_qe_base() modify get_qe_base function with of_address_to_resource instead of of_get_property and of_translate_address. Signed-off-by: Zhao Qiang Signed-off-by: Scott Wood --- drivers/soc/fsl/qe/qe.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c index 7026507e6f1d5..2707a827261b1 100644 --- a/drivers/soc/fsl/qe/qe.c +++ b/drivers/soc/fsl/qe/qe.c @@ -69,8 +69,8 @@ static phys_addr_t qebase = -1; phys_addr_t get_qe_base(void) { struct device_node *qe; - int size; - const u32 *prop; + int ret; + struct resource res; if (qebase != -1) return qebase; @@ -82,9 +82,9 @@ phys_addr_t get_qe_base(void) return qebase; } - prop = of_get_property(qe, "reg", &size); - if (prop && size >= sizeof(*prop)) - qebase = of_translate_address(qe, prop); + ret = of_address_to_resource(qe, 0, &res); + if (!ret) + qebase = res.start; of_node_put(qe); return qebase; -- GitLab From ddc6cd0d70a6f958b2c01758ee53279d36db2234 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 17 May 2016 14:01:39 +0200 Subject: [PATCH 0109/1167] powerpc32: Use instruction symbolic names in check_io_access() Signed-off-by: Christophe Leroy Signed-off-by: Scott Wood --- arch/powerpc/include/asm/ppc-opcode.h | 1 + arch/powerpc/kernel/traps.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 127ebf5862b46..e6d2c33781fc7 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -152,6 +152,7 @@ #define PPC_INST_LWSYNC 0x7c2004ac #define PPC_INST_SYNC 0x7c0004ac #define PPC_INST_SYNC_MASK 0xfc0007fe +#define PPC_INST_ISYNC 0x4c00012c #define PPC_INST_LXVD2X 0x7c000698 #define PPC_INST_MCRXR 0x7c000400 #define PPC_INST_MCRXR_MASK 0xfc0007fe diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 6b108ed29c204..68f8b5b0d8858 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -352,12 +352,11 @@ static inline int check_io_access(struct pt_regs *regs) * For the debug message, we look at the preceding * load or store. */ - if (*nip == 0x60000000) /* nop */ + if (*nip == PPC_INST_NOP) nip -= 2; - else if (*nip == 0x4c00012c) /* isync */ + else if (*nip == PPC_INST_ISYNC) --nip; - if (*nip == 0x7c0004ac || (*nip >> 26) == 3) { - /* sync or twi */ + if (*nip == PPC_INST_SYNC || (*nip >> 26) == OP_TRAP) { unsigned int rb; --nip; -- GitLab From 93c4ea38a19815d59f2f2afe8414ba27288b8b70 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 25 Jul 2016 21:30:09 -0700 Subject: [PATCH 0110/1167] powerpc/mpc85xx_mds: Select PHYLIB only if NETDEVICES is enabled PHYLIB depends on NETDEVICES, so to avoid unmet dependencies warning from Kconfig it needs to be selected conditionally. Also add checks if PHYLIB is built-in to avoid undefined references to PHYLIB's symbols. Signed-off-by: Andrey Smirnov Signed-off-by: Scott Wood --- arch/powerpc/platforms/85xx/Kconfig | 2 +- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index df25a3ed489dd..9dc1d28975b92 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -72,7 +72,7 @@ config MPC85xx_CDS config MPC85xx_MDS bool "Freescale MPC85xx MDS" select DEFAULT_UIMAGE - select PHYLIB + select PHYLIB if NETDEVICES select HAS_RAPIDIO select SWIOTLB help diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index fa9cd710d2aee..48fbd7bea968e 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -63,6 +63,8 @@ #define DBG(fmt...) #endif +#if IS_BUILTIN(CONFIG_PHYLIB) + #define MV88E1111_SCR 0x10 #define MV88E1111_SCR_125CLK 0x0010 static int mpc8568_fixup_125_clock(struct phy_device *phydev) @@ -152,6 +154,8 @@ static int mpc8568_mds_phy_fixups(struct phy_device *phydev) return err; } +#endif + /* ************************************************************************ * * Setup the architecture @@ -313,6 +317,7 @@ static void __init mpc85xx_mds_setup_arch(void) swiotlb_detect_4g(); } +#if IS_BUILTIN(CONFIG_PHYLIB) static int __init board_fixups(void) { @@ -342,9 +347,12 @@ static int __init board_fixups(void) return 0; } + machine_arch_initcall(mpc8568_mds, board_fixups); machine_arch_initcall(mpc8569_mds, board_fixups); +#endif + static int __init mpc85xx_publish_devices(void) { if (machine_is(mpc8568_mds)) @@ -434,4 +442,3 @@ define_machine(p1021_mds) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif }; - -- GitLab From 49bf9279cd3edb9d7178223f52d4656dbf2e46b5 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 25 Jul 2016 21:30:10 -0700 Subject: [PATCH 0111/1167] powerpc/e8248e: Select PHYLIB only if NETDEVICES is enabled Select PHYLIB only if NETDEVICES is enabled and MDIO_BITBANG only if PHYLIB is present to avoid warnings from Kconfig. To prevent undefined references during linking register MDIO driver only if CONFIG_MDIO_BITBANG is enabled. Signed-off-by: Andrey Smirnov Signed-off-by: Scott Wood --- arch/powerpc/platforms/82xx/Kconfig | 4 ++-- arch/powerpc/platforms/82xx/ep8248e.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index 7c7df40038207..994d1a959e20f 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -30,8 +30,8 @@ config EP8248E select 8272 select 8260 select FSL_SOC - select PHYLIB - select MDIO_BITBANG + select PHYLIB if NETDEVICES + select MDIO_BITBANG if PHYLIB help This enables support for the Embedded Planet EP8248E board. diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c index cdab847749e60..8fec050f2d5b8 100644 --- a/arch/powerpc/platforms/82xx/ep8248e.c +++ b/arch/powerpc/platforms/82xx/ep8248e.c @@ -298,7 +298,9 @@ static const struct of_device_id of_bus_ids[] __initconst = { static int __init declare_of_platform_devices(void) { of_platform_bus_probe(NULL, of_bus_ids, NULL); - platform_driver_register(&ep8248e_mdio_driver); + + if (IS_ENABLED(CONFIG_MDIO_BITBANG)) + platform_driver_register(&ep8248e_mdio_driver); return 0; } -- GitLab From 625f3eea40024d0fc6562fc737761bba696c662b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 25 Jul 2016 21:45:01 -0700 Subject: [PATCH 0112/1167] powerpc/sgy_cts1000: Fix gpio_halt_cb()'s signature Halt callback in struct machdep_calls is declared with __noreturn attribute, so omitting that attribute in gpio_halt_cb()'s signatrue results in compilation error. Change the signature to address the problem as well as change the code of the function to avoid ever returning from the function. Signed-off-by: Andrey Smirnov Signed-off-by: Scott Wood --- arch/powerpc/platforms/85xx/sgy_cts1000.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/85xx/sgy_cts1000.c b/arch/powerpc/platforms/85xx/sgy_cts1000.c index 79fd0dfd4b820..21d6aaa5c3e4a 100644 --- a/arch/powerpc/platforms/85xx/sgy_cts1000.c +++ b/arch/powerpc/platforms/85xx/sgy_cts1000.c @@ -38,18 +38,18 @@ static void gpio_halt_wfn(struct work_struct *work) } static DECLARE_WORK(gpio_halt_wq, gpio_halt_wfn); -static void gpio_halt_cb(void) +static void __noreturn gpio_halt_cb(void) { enum of_gpio_flags flags; int trigger, gpio; if (!halt_node) - return; + panic("No reset GPIO information was provided in DT\n"); gpio = of_get_gpio_flags(halt_node, 0, &flags); if (!gpio_is_valid(gpio)) - return; + panic("Provided GPIO is invalid\n"); trigger = (flags == OF_GPIO_ACTIVE_LOW); @@ -57,6 +57,8 @@ static void gpio_halt_cb(void) /* Probably wont return */ gpio_set_value(gpio, trigger); + + panic("Halt failed\n"); } /* This IRQ means someone pressed the power button and it is waiting for us -- GitLab From d0d738a41474a75b686b2a0b9c1a62928556e673 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 28 Jul 2016 16:07:16 -0700 Subject: [PATCH 0113/1167] powerpc: Factor out common code in setup-common.c Factor out a small bit of common code in machine_restart(), machine_power_off() and machine_halt(). Signed-off-by: Andrey Smirnov Signed-off-by: Scott Wood --- arch/powerpc/kernel/setup-common.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index dba265c586df0..a730d5b25eb4d 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -131,15 +131,22 @@ void machine_shutdown(void) ppc_md.machine_shutdown(); } +static void machine_hang(void) +{ + pr_emerg("System Halted, OK to turn off power\n"); + local_irq_disable(); + while (1) + ; +} + void machine_restart(char *cmd) { machine_shutdown(); if (ppc_md.restart) ppc_md.restart(cmd); + smp_send_stop(); - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; + machine_hang(); } void machine_power_off(void) @@ -147,10 +154,9 @@ void machine_power_off(void) machine_shutdown(); if (pm_power_off) pm_power_off(); + smp_send_stop(); - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; + machine_hang(); } /* Used by the G5 thermal driver */ EXPORT_SYMBOL_GPL(machine_power_off); @@ -163,10 +169,9 @@ void machine_halt(void) machine_shutdown(); if (ppc_md.halt) ppc_md.halt(); + smp_send_stop(); - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; + machine_hang(); } -- GitLab From ad24747304de84d2b158f2e8a1d31b18153d3878 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 28 Jul 2016 16:07:17 -0700 Subject: [PATCH 0114/1167] powerpc: Call chained reset handlers during reset Call out to all restart handlers that were added via register_restart_handler() API when restarting the machine. Signed-off-by: Andrey Smirnov Signed-off-by: Scott Wood --- arch/powerpc/kernel/setup-common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index a730d5b25eb4d..270ee30abdcf7 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -146,6 +146,10 @@ void machine_restart(char *cmd) ppc_md.restart(cmd); smp_send_stop(); + + do_kernel_restart(cmd); + mdelay(1000); + machine_hang(); } -- GitLab From 7120438e5d82f445acbfe131a1b58eab7e83fa33 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 28 Jul 2016 16:07:18 -0700 Subject: [PATCH 0115/1167] powerpc: Convert fsl_rstcr_restart to a reset handler Convert fsl_rstcr_restart into a function to be registered with register_reset_handler(). Signed-off-by: Andrey Smirnov [scottwood: Converted mvme7100 as well] Signed-off-by: Scott Wood --- arch/powerpc/platforms/85xx/bsc913x_qds.c | 1 - arch/powerpc/platforms/85xx/bsc913x_rdb.c | 1 - arch/powerpc/platforms/85xx/c293pcie.c | 1 - arch/powerpc/platforms/85xx/corenet_generic.c | 1 - arch/powerpc/platforms/85xx/ge_imp3a.c | 1 - arch/powerpc/platforms/85xx/mpc8536_ds.c | 1 - arch/powerpc/platforms/85xx/mpc85xx_ads.c | 1 - arch/powerpc/platforms/85xx/mpc85xx_cds.c | 25 ++++++++++---- arch/powerpc/platforms/85xx/mpc85xx_ds.c | 3 -- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 3 -- arch/powerpc/platforms/85xx/mpc85xx_rdb.c | 10 ------ arch/powerpc/platforms/85xx/mvme2500.c | 1 - arch/powerpc/platforms/85xx/p1010rdb.c | 1 - arch/powerpc/platforms/85xx/p1022_ds.c | 1 - arch/powerpc/platforms/85xx/p1022_rdk.c | 1 - arch/powerpc/platforms/85xx/p1023_rdb.c | 1 - arch/powerpc/platforms/85xx/ppa8548.c | 1 - arch/powerpc/platforms/85xx/qemu_e500.c | 1 - arch/powerpc/platforms/85xx/sbc8548.c | 1 - arch/powerpc/platforms/85xx/socrates.c | 1 - arch/powerpc/platforms/85xx/stx_gp3.c | 1 - arch/powerpc/platforms/85xx/tqm85xx.c | 1 - arch/powerpc/platforms/85xx/twr_p102x.c | 1 - arch/powerpc/platforms/85xx/xes_mpc85xx.c | 3 -- arch/powerpc/platforms/86xx/gef_ppc9a.c | 1 - arch/powerpc/platforms/86xx/gef_sbc310.c | 1 - arch/powerpc/platforms/86xx/gef_sbc610.c | 1 - arch/powerpc/platforms/86xx/mpc8610_hpcd.c | 1 - arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 1 - arch/powerpc/platforms/86xx/mvme7100.c | 1 - arch/powerpc/platforms/86xx/sbc8641d.c | 1 - arch/powerpc/sysdev/fsl_soc.c | 33 +++++++++++-------- arch/powerpc/sysdev/fsl_soc.h | 2 -- 33 files changed, 38 insertions(+), 67 deletions(-) diff --git a/arch/powerpc/platforms/85xx/bsc913x_qds.c b/arch/powerpc/platforms/85xx/bsc913x_qds.c index 07dd6ae3ec525..d2f45569a0264 100644 --- a/arch/powerpc/platforms/85xx/bsc913x_qds.c +++ b/arch/powerpc/platforms/85xx/bsc913x_qds.c @@ -72,7 +72,6 @@ define_machine(bsc9132_qds) { .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/bsc913x_rdb.c b/arch/powerpc/platforms/85xx/bsc913x_rdb.c index e48f6710e6d54..0ffdb4a80c2af 100644 --- a/arch/powerpc/platforms/85xx/bsc913x_rdb.c +++ b/arch/powerpc/platforms/85xx/bsc913x_rdb.c @@ -59,7 +59,6 @@ define_machine(bsc9131_rdb) { .setup_arch = bsc913x_rdb_setup_arch, .init_IRQ = bsc913x_rdb_pic_init, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/c293pcie.c b/arch/powerpc/platforms/85xx/c293pcie.c index 3b9e3f0f9aec2..4df1b4026eab4 100644 --- a/arch/powerpc/platforms/85xx/c293pcie.c +++ b/arch/powerpc/platforms/85xx/c293pcie.c @@ -65,7 +65,6 @@ define_machine(c293_pcie) { .setup_arch = c293_pcie_setup_arch, .init_IRQ = c293_pcie_pic_init, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c index 3a6a84f07f43c..1179115a4b5c6 100644 --- a/arch/powerpc/platforms/85xx/corenet_generic.c +++ b/arch/powerpc/platforms/85xx/corenet_generic.c @@ -225,7 +225,6 @@ define_machine(corenet_generic) { #else .get_irq = mpic_get_coreint_irq, #endif - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c index 14af36a7fa9ca..f29c6f0909f35 100644 --- a/arch/powerpc/platforms/85xx/ge_imp3a.c +++ b/arch/powerpc/platforms/85xx/ge_imp3a.c @@ -215,7 +215,6 @@ define_machine(ge_imp3a) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index 6ba687f19e45d..94a7f92c858ff 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -77,7 +77,6 @@ define_machine(mpc8536_ds) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 8756715c7a47f..f3e055fdd1de4 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -170,7 +170,6 @@ define_machine(mpc85xx_ads) { .init_IRQ = mpc85xx_ads_pic_init, .show_cpuinfo = mpc85xx_ads_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 86f20156178e9..224db30c497b0 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -83,7 +83,8 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, return PCIBIOS_SUCCESSFUL; } -static void __noreturn mpc85xx_cds_restart(char *cmd) +static int mpc85xx_cds_restart(struct notifier_block *this, + unsigned long mode, void *cmd) { struct pci_dev *dev; u_char tmp; @@ -108,12 +109,25 @@ static void __noreturn mpc85xx_cds_restart(char *cmd) } /* - * If we can't find the VIA chip (maybe the P2P bridge is disabled) - * or the VIA chip reset didn't work, just use the default reset. + * If we can't find the VIA chip (maybe the P2P bridge is + * disabled) or the VIA chip reset didn't work, just return + * and let default reset sequence happen. */ - fsl_rstcr_restart(NULL); + return NOTIFY_DONE; } +static int mpc85xx_cds_restart_register(void) +{ + static struct notifier_block restart_handler; + + restart_handler.notifier_call = mpc85xx_cds_restart; + restart_handler.priority = 192; + + return register_restart_handler(&restart_handler); +} +machine_arch_initcall(mpc85xx_cds, mpc85xx_cds_restart_register); + + static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev) { u_char c; @@ -380,11 +394,8 @@ define_machine(mpc85xx_cds) { .show_cpuinfo = mpc85xx_cds_show_cpuinfo, .get_irq = mpic_get_irq, #ifdef CONFIG_PCI - .restart = mpc85xx_cds_restart, .pcibios_fixup_bus = mpc85xx_cds_fixup_bus, .pcibios_fixup_phb = fsl_pcibios_fixup_phb, -#else - .restart = fsl_rstcr_restart, #endif .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index ed69c7ee1829b..dc9e035cc637a 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -204,7 +204,6 @@ define_machine(mpc8544_ds) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -219,7 +218,6 @@ define_machine(mpc8572_ds) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -234,7 +232,6 @@ define_machine(p2020_ds) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 48fbd7bea968e..d7e440e6dba3d 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -393,7 +393,6 @@ define_machine(mpc8568_mds) { .setup_arch = mpc85xx_mds_setup_arch, .init_IRQ = mpc85xx_mds_pic_init, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI @@ -413,7 +412,6 @@ define_machine(mpc8569_mds) { .setup_arch = mpc85xx_mds_setup_arch, .init_IRQ = mpc85xx_mds_pic_init, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI @@ -434,7 +432,6 @@ define_machine(p1021_mds) { .setup_arch = mpc85xx_mds_setup_arch, .init_IRQ = mpc85xx_mds_pic_init, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index c1499cbf37867..10069503e39f2 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -213,7 +213,6 @@ define_machine(p2020_rdb) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -228,7 +227,6 @@ define_machine(p1020_rdb) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -243,7 +241,6 @@ define_machine(p1021_rdb_pc) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -258,7 +255,6 @@ define_machine(p2020_rdb_pc) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -273,7 +269,6 @@ define_machine(p1025_rdb) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -288,7 +283,6 @@ define_machine(p1020_mbg_pc) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -303,7 +297,6 @@ define_machine(p1020_utm_pc) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -318,7 +311,6 @@ define_machine(p1020_rdb_pc) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -333,7 +325,6 @@ define_machine(p1020_rdb_pd) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -348,7 +339,6 @@ define_machine(p1024_rdb) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mvme2500.c b/arch/powerpc/platforms/85xx/mvme2500.c index acc3d0d6049d5..d5af0723a69e9 100644 --- a/arch/powerpc/platforms/85xx/mvme2500.c +++ b/arch/powerpc/platforms/85xx/mvme2500.c @@ -66,7 +66,6 @@ define_machine(mvme2500) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c index 661d7b59e4131..78d13b364cd63 100644 --- a/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/arch/powerpc/platforms/85xx/p1010rdb.c @@ -79,7 +79,6 @@ define_machine(p1010_rdb) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 63568d68c76f8..0908abd7e36f6 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -568,7 +568,6 @@ define_machine(p1022_ds) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/p1022_rdk.c b/arch/powerpc/platforms/85xx/p1022_rdk.c index 2f29436003011..276e00ab3dde9 100644 --- a/arch/powerpc/platforms/85xx/p1022_rdk.c +++ b/arch/powerpc/platforms/85xx/p1022_rdk.c @@ -148,7 +148,6 @@ define_machine(p1022_rdk) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/p1023_rdb.c b/arch/powerpc/platforms/85xx/p1023_rdb.c index 40d8de57c341d..3e8cd0324dfca 100644 --- a/arch/powerpc/platforms/85xx/p1023_rdb.c +++ b/arch/powerpc/platforms/85xx/p1023_rdb.c @@ -110,7 +110,6 @@ define_machine(p1023_rdb) { .setup_arch = mpc85xx_rdb_setup_arch, .init_IRQ = mpc85xx_rdb_pic_init, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI diff --git a/arch/powerpc/platforms/85xx/ppa8548.c b/arch/powerpc/platforms/85xx/ppa8548.c index 2410167b290a2..33c5ba644fa56 100644 --- a/arch/powerpc/platforms/85xx/ppa8548.c +++ b/arch/powerpc/platforms/85xx/ppa8548.c @@ -91,7 +91,6 @@ define_machine(ppa8548) { .init_IRQ = ppa8548_pic_init, .show_cpuinfo = ppa8548_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/qemu_e500.c b/arch/powerpc/platforms/85xx/qemu_e500.c index 50d745809809a..b63a8548366f8 100644 --- a/arch/powerpc/platforms/85xx/qemu_e500.c +++ b/arch/powerpc/platforms/85xx/qemu_e500.c @@ -77,7 +77,6 @@ define_machine(qemu_e500) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_coreint_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c index 62b6c45a5a9b1..2c670848ff080 100644 --- a/arch/powerpc/platforms/85xx/sbc8548.c +++ b/arch/powerpc/platforms/85xx/sbc8548.c @@ -130,7 +130,6 @@ define_machine(sbc8548) { .init_IRQ = sbc8548_pic_init, .show_cpuinfo = sbc8548_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, .pcibios_fixup_phb = fsl_pcibios_fixup_phb, diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c index cd255acde2e29..8da4ed90338d5 100644 --- a/arch/powerpc/platforms/85xx/socrates.c +++ b/arch/powerpc/platforms/85xx/socrates.c @@ -91,7 +91,6 @@ define_machine(socrates) { .setup_arch = socrates_setup_arch, .init_IRQ = socrates_pic_init, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c index 91b824c4dc082..1a1d44ea17541 100644 --- a/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/arch/powerpc/platforms/85xx/stx_gp3.c @@ -103,7 +103,6 @@ define_machine(stx_gp3) { .init_IRQ = stx_gp3_pic_init, .show_cpuinfo = stx_gp3_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index b7c54454d611a..9fc20a37835e6 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -132,7 +132,6 @@ define_machine(tqm85xx) { .init_IRQ = tqm85xx_pic_init, .show_cpuinfo = tqm85xx_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/twr_p102x.c b/arch/powerpc/platforms/85xx/twr_p102x.c index 1bc02a87f5971..360f6253e9ffc 100644 --- a/arch/powerpc/platforms/85xx/twr_p102x.c +++ b/arch/powerpc/platforms/85xx/twr_p102x.c @@ -140,7 +140,6 @@ define_machine(twr_p1025) { .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index cf0c70ff026e7..cd6ce845f398b 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -167,7 +167,6 @@ define_machine(xes_mpc8572) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -182,7 +181,6 @@ define_machine(xes_mpc8548) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -197,7 +195,6 @@ define_machine(xes_mpc8540) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c index ef684afb63c62..6b99300edd365 100644 --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c @@ -204,7 +204,6 @@ define_machine(gef_ppc9a) { .init_IRQ = gef_ppc9a_init_irq, .show_cpuinfo = gef_ppc9a_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c index 67dd0c2316460..8cdeca0611279 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c @@ -191,7 +191,6 @@ define_machine(gef_sbc310) { .init_IRQ = gef_sbc310_init_irq, .show_cpuinfo = gef_sbc310_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c index 805026976cacd..da8723ae23ecf 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c @@ -181,7 +181,6 @@ define_machine(gef_sbc610) { .init_IRQ = gef_sbc610_init_irq, .show_cpuinfo = gef_sbc610_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index fef0582eddf15..a5d73fabe4d11 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -331,7 +331,6 @@ define_machine(mpc86xx_hpcd) { .setup_arch = mpc86xx_hpcd_setup_arch, .init_IRQ = mpc86xx_init_irq, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 5ae42a037065f..a0e989ed4b6f4 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -130,7 +130,6 @@ define_machine(mpc86xx_hpcn) { .init_IRQ = mpc86xx_init_irq, .show_cpuinfo = mpc86xx_hpcn_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/86xx/mvme7100.c b/arch/powerpc/platforms/86xx/mvme7100.c index addb41e7cd144..835352e63dc3a 100644 --- a/arch/powerpc/platforms/86xx/mvme7100.c +++ b/arch/powerpc/platforms/86xx/mvme7100.c @@ -111,7 +111,6 @@ define_machine(mvme7100) { .setup_arch = mvme7100_setup_arch, .init_IRQ = mpc86xx_init_irq, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/86xx/sbc8641d.c b/arch/powerpc/platforms/86xx/sbc8641d.c index 52af5735742e4..93db35d4f6eb9 100644 --- a/arch/powerpc/platforms/86xx/sbc8641d.c +++ b/arch/powerpc/platforms/86xx/sbc8641d.c @@ -82,7 +82,6 @@ define_machine(sbc8641) { .init_IRQ = mpc86xx_init_irq, .show_cpuinfo = sbc8641_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index a09ca704de58a..d93056eedcb0a 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -180,23 +181,38 @@ EXPORT_SYMBOL(get_baudrate); #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) static __be32 __iomem *rstcr; +static int fsl_rstcr_restart(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + local_irq_disable(); + /* set reset control register */ + out_be32(rstcr, 0x2); /* HRESET_REQ */ + + return NOTIFY_DONE; +} + static int __init setup_rstcr(void) { struct device_node *np; + static struct notifier_block restart_handler = { + .notifier_call = fsl_rstcr_restart, + .priority = 128, + }; + for_each_node_by_name(np, "global-utilities") { if ((of_get_property(np, "fsl,has-rstcr", NULL))) { rstcr = of_iomap(np, 0) + 0xb0; - if (!rstcr) + if (!rstcr) { printk (KERN_ERR "Error: reset control " "register not mapped!\n"); + } else { + register_restart_handler(&restart_handler); + } break; } } - if (!rstcr && ppc_md.restart == fsl_rstcr_restart) - printk(KERN_ERR "No RSTCR register, warm reboot won't work\n"); - of_node_put(np); return 0; @@ -204,15 +220,6 @@ static int __init setup_rstcr(void) arch_initcall(setup_rstcr); -void __noreturn fsl_rstcr_restart(char *cmd) -{ - local_irq_disable(); - if (rstcr) - /* set reset control register */ - out_be32(rstcr, 0x2); /* HRESET_REQ */ - - while (1) ; -} #endif #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 433566a5ef192..d73daa4f0ccfc 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -19,8 +19,6 @@ extern u32 fsl_get_sys_freq(void); struct spi_board_info; struct device_node; -extern void __noreturn fsl_rstcr_restart(char *cmd); - /* The different ports that the DIU can be connected to */ enum fsl_diu_monitor_port { FSL_DIU_PORT_DVI, /* DVI */ -- GitLab From 74c269f69cdae83253be7f65840dd1ae589d5e99 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 5 Aug 2016 10:56:41 +0200 Subject: [PATCH 0116/1167] fsl/qe: use of_property_read_bool Use of_property_read_bool to check for the existence of a property. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression e1,e2; statement S2,S1; @@ - if (of_get_property(e1,e2,NULL)) + if (of_property_read_bool(e1,e2)) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Scott Wood --- drivers/soc/fsl/qe/qe_tdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/qe_tdm.c b/drivers/soc/fsl/qe/qe_tdm.c index 124e222a0d189..a1048b44e6b93 100644 --- a/drivers/soc/fsl/qe/qe_tdm.c +++ b/drivers/soc/fsl/qe/qe_tdm.c @@ -99,7 +99,7 @@ int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm, utdm->tdm_port = val; ut_info->uf_info.tdm_num = utdm->tdm_port; - if (of_get_property(np, "fsl,tdm-internal-loopback", NULL)) + if (of_property_read_bool(np, "fsl,tdm-internal-loopback")) utdm->tdm_mode = TDM_INTERNAL_LOOPBACK; else utdm->tdm_mode = TDM_NORMAL; -- GitLab From 1fadfe9e19c9d3c26b3e7e9baee5e6846175ad51 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 5 Aug 2016 10:56:49 +0200 Subject: [PATCH 0117/1167] powerpc/mpic: use of_property_read_bool Use of_property_read_bool to check for the existence of a property. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression e1,e2; statement S2,S1; @@ - if (of_get_property(e1,e2,NULL)) + if (of_property_read_bool(e1,e2)) S1 else S2 // Signed-off-by: Julia Lawall Acked-by: Michael Ellerman Signed-off-by: Scott Wood --- arch/powerpc/sysdev/mpic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 4d48cecfedd1d..b9aac951a90f6 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1249,7 +1249,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* Pick the physical address from the device tree if unspecified */ if (!phys_addr) { /* Check if it is DCR-based */ - if (of_get_property(node, "dcr-reg", NULL)) { + if (of_property_read_bool(node, "dcr-reg")) { flags |= MPIC_USES_DCR; } else { struct resource r; -- GitLab From 4d486e0083796b54d5aeddd7a5794f897fca1008 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 16 Aug 2016 08:26:20 +0200 Subject: [PATCH 0118/1167] soc/fsl/qe: fix Oops on CPM1 (and likely CPM2) Commit 0e6e01ff694ee ("CPM/QE: use genalloc to manage CPM/QE muram") has changed the way muram is managed. genalloc uses kmalloc(), hence requires the SLAB to be up and running. On powerpc 8xx, cpm_reset() is called early during startup. cpm_reset() then calls cpm_muram_init() before SLAB is available, hence the following Oops. cpm_reset() cannot be called during initcalls because the CPM is needed for console. This patch removes the call to cpm_muram_init() from cpm_reset(). cpm_muram_init() will be called from a new function called cpm_init() which is declared as subsys_initcall, unless cpm_muram_alloc() is called earlier for the serial console in which case cpm_muram_init() will be called from there. The reason for calling it from two places is that some drivers (e.g. i2c-cpm) need some of the initialisations done by cpm_muram_init() but don't call cpm_muram_alloc(). The console driver calls cpm_muram_alloc() but some platforms might not use the CPM serial ports for console. [ 0.000000] Unable to handle kernel paging request for data at address 0x00000008 [ 0.000000] Faulting instruction address: 0xc01acce0 [ 0.000000] Oops: Kernel access of bad area, sig: 11 [#1] [ 0.000000] PREEMPT CMPC885 [ 0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 4.4.14-g0886ed8 #5 [ 0.000000] task: c05183e0 ti: c0536000 task.ti: c0536000 [ 0.000000] NIP: c01acce0 LR: c0011068 CTR: 00000000 [ 0.000000] REGS: c0537e50 TRAP: 0300 Not tainted (4.4.14-s3k-dev-g0886ed8-svn) [ 0.000000] MSR: 00001032 CR: 28044428 XER: 00000000 [ 0.000000] DAR: 00000008 DSISR: c0000000 GPR00: c0011068 c0537f00 c05183e0 00000000 00009000 ffffffff 00000bc0 ffffffff GPR08: ff003000 ff00b000 ff003bbf 00000000 22044422 100d43a8 00000000 07ff94e8 GPR16: 00000000 07bb5d70 00000000 07ff81f4 07ff81f4 07ff81f4 00000000 00000000 GPR24: 07ffb3a0 07fe7628 c0550000 c7ffa190 c0540000 ff003bbf 00000000 00000001 [ 0.000000] NIP [c01acce0] gen_pool_add_virt+0x14/0xdc [ 0.000000] LR [c0011068] cpm_muram_init+0xd4/0x18c [ 0.000000] Call Trace: [ 0.000000] [c0537f00] [00000200] 0x200 (unreliable) [ 0.000000] [c0537f20] [c0011068] cpm_muram_init+0xd4/0x18c [ 0.000000] [c0537f70] [c0494684] cpm_reset+0xb4/0xc8 [ 0.000000] [c0537f90] [c0494c64] cmpc885_setup_arch+0x10/0x30 [ 0.000000] [c0537fa0] [c0493cd4] setup_arch+0x130/0x168 [ 0.000000] [c0537fb0] [c04906bc] start_kernel+0x88/0x380 [ 0.000000] [c0537ff0] [c0002224] start_here+0x38/0x98 [ 0.000000] Instruction dump: [ 0.000000] 91430010 91430014 80010014 83e1000c 7c0803a6 38210010 4e800020 7c0802a6 [ 0.000000] 9421ffe0 bf61000c 90010024 7c7e1b78 <80630008> 7c9c2378 7cc31c30 3863001f [ 0.000000] ---[ end trace dc8fa200cb88537f ]--- fixes: 0e6e01ff694ee ("CPM/QE: use genalloc to manage CPM/QE muram") Cc: stable@vger.linux.org Signed-off-by: Christophe Leroy [scottwood: Removed some string changes unrelated to bugfix] Signed-off-by: Scott Wood --- arch/powerpc/sysdev/cpm1.c | 2 -- arch/powerpc/sysdev/cpm2.c | 4 ---- arch/powerpc/sysdev/cpm_common.c | 15 +++++++++++++++ drivers/soc/fsl/qe/qe_common.c | 8 ++++++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 3c0eb9b255353..986cd111d4df1 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -233,8 +233,6 @@ void __init cpm_reset(void) else out_be32(&siu_conf->sc_sdcr, 1); immr_unmap(siu_conf); - - cpm_muram_init(); } static DEFINE_SPINLOCK(cmd_lock); diff --git a/arch/powerpc/sysdev/cpm2.c b/arch/powerpc/sysdev/cpm2.c index 8dc1e24f3c238..f78ff841652c2 100644 --- a/arch/powerpc/sysdev/cpm2.c +++ b/arch/powerpc/sysdev/cpm2.c @@ -66,10 +66,6 @@ void __init cpm2_reset(void) cpm2_immr = ioremap(get_immrbase(), CPM_MAP_SIZE); #endif - /* Reclaim the DP memory for our use. - */ - cpm_muram_init(); - /* Tell everyone where the comm processor resides. */ cpmp = &cpm2_immr->im_cpm; diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index 947f42007734c..51bf749a4f3a7 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c @@ -37,6 +37,21 @@ #include #endif +static int __init cpm_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,cpm1"); + if (!np) + np = of_find_compatible_node(NULL, NULL, "fsl,cpm2"); + if (!np) + return -ENODEV; + cpm_muram_init(); + of_node_put(np); + return 0; +} +subsys_initcall(cpm_init); + #ifdef CONFIG_PPC_EARLY_DEBUG_CPM static u32 __iomem *cpm_udbg_txdesc; static u8 __iomem *cpm_udbg_txbuf; diff --git a/drivers/soc/fsl/qe/qe_common.c b/drivers/soc/fsl/qe/qe_common.c index 41eff805a9041..104e68d9b84f2 100644 --- a/drivers/soc/fsl/qe/qe_common.c +++ b/drivers/soc/fsl/qe/qe_common.c @@ -70,6 +70,11 @@ int cpm_muram_init(void) } muram_pool = gen_pool_create(0, -1); + if (!muram_pool) { + pr_err("Cannot allocate memory pool for CPM/QE muram"); + ret = -ENOMEM; + goto out_muram; + } muram_pbase = of_translate_address(np, zero); if (muram_pbase == (phys_addr_t)OF_BAD_ADDR) { pr_err("Cannot translate zero through CPM muram node"); @@ -116,6 +121,9 @@ static unsigned long cpm_muram_alloc_common(unsigned long size, struct muram_block *entry; unsigned long start; + if (!muram_pool && cpm_muram_init()) + goto out2; + start = gen_pool_alloc_algo(muram_pool, size, algo, data); if (!start) goto out2; -- GitLab From fff69fd03d1290297fcd039b07819fafa69ffc0a Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Tue, 23 Aug 2016 10:06:58 +0800 Subject: [PATCH 0119/1167] powerpc/83xx: factor out the common codes of setup arch functions Factor out the common codes of setup arch functions to a separate function. It does make no sense to print a board specific info in setup arch functions, so use a more general one. For ASP8347E board, there is no pci device node. So it is safe to invoke mpc83xx_setup_pci() in its setup arch function even there is no such invocation in its original setup arch function. Signed-off-by: Kevin Hao Signed-off-by: Scott Wood --- arch/powerpc/platforms/83xx/asp834x.c | 4 +--- arch/powerpc/platforms/83xx/km83xx.c | 5 +---- arch/powerpc/platforms/83xx/misc.c | 8 ++++++++ arch/powerpc/platforms/83xx/mpc830x_rdb.c | 5 +---- arch/powerpc/platforms/83xx/mpc831x_rdb.c | 5 +---- arch/powerpc/platforms/83xx/mpc832x_mds.c | 5 +---- arch/powerpc/platforms/83xx/mpc832x_rdb.c | 5 +---- arch/powerpc/platforms/83xx/mpc834x_itx.c | 5 +---- arch/powerpc/platforms/83xx/mpc834x_mds.c | 5 +---- arch/powerpc/platforms/83xx/mpc836x_mds.c | 5 +---- arch/powerpc/platforms/83xx/mpc836x_rdk.c | 5 +---- arch/powerpc/platforms/83xx/mpc837x_mds.c | 5 +---- arch/powerpc/platforms/83xx/mpc837x_rdb.c | 5 +---- arch/powerpc/platforms/83xx/mpc83xx.h | 1 + arch/powerpc/platforms/83xx/sbc834x.c | 5 +---- 15 files changed, 22 insertions(+), 51 deletions(-) diff --git a/arch/powerpc/platforms/83xx/asp834x.c b/arch/powerpc/platforms/83xx/asp834x.c index 17e54339f8d98..575afd6eb36a4 100644 --- a/arch/powerpc/platforms/83xx/asp834x.c +++ b/arch/powerpc/platforms/83xx/asp834x.c @@ -30,9 +30,7 @@ */ static void __init asp834x_setup_arch(void) { - if (ppc_md.progress) - ppc_md.progress("asp834x_setup_arch()", 0); - + mpc83xx_setup_arch(); mpc834x_usb_cfg(); } diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c index e7fbd6366abbb..d8642a4afc743 100644 --- a/arch/powerpc/platforms/83xx/km83xx.c +++ b/arch/powerpc/platforms/83xx/km83xx.c @@ -130,10 +130,7 @@ static void __init mpc83xx_km_setup_arch(void) struct device_node *np; #endif - if (ppc_md.progress) - ppc_md.progress("kmpbec83xx_setup_arch()", 0); - - mpc83xx_setup_pci(); + mpc83xx_setup_arch(); #ifdef CONFIG_QUICC_ENGINE np = of_find_node_by_name(NULL, "par_io"); diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c index 8899aa9d11f5f..d75c9816a5c92 100644 --- a/arch/powerpc/platforms/83xx/misc.c +++ b/arch/powerpc/platforms/83xx/misc.c @@ -142,3 +142,11 @@ void __init mpc83xx_setup_pci(void) mpc83xx_add_bridge(np); } #endif + +void __init mpc83xx_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("mpc83xx_setup_arch()", 0); + + mpc83xx_setup_pci(); +} diff --git a/arch/powerpc/platforms/83xx/mpc830x_rdb.c b/arch/powerpc/platforms/83xx/mpc830x_rdb.c index 040d5d0854675..272c41c387b94 100644 --- a/arch/powerpc/platforms/83xx/mpc830x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc830x_rdb.c @@ -27,10 +27,7 @@ */ static void __init mpc830x_rdb_setup_arch(void) { - if (ppc_md.progress) - ppc_md.progress("mpc830x_rdb_setup_arch()", 0); - - mpc83xx_setup_pci(); + mpc83xx_setup_arch(); mpc831x_usb_cfg(); } diff --git a/arch/powerpc/platforms/83xx/mpc831x_rdb.c b/arch/powerpc/platforms/83xx/mpc831x_rdb.c index 40e0d8307b59e..fd80fd570e67b 100644 --- a/arch/powerpc/platforms/83xx/mpc831x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc831x_rdb.c @@ -28,10 +28,7 @@ */ static void __init mpc831x_rdb_setup_arch(void) { - if (ppc_md.progress) - ppc_md.progress("mpc831x_rdb_setup_arch()", 0); - - mpc83xx_setup_pci(); + mpc83xx_setup_arch(); mpc831x_usb_cfg(); } diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index cdfa47c4d3941..bb7b25acf26ff 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -58,8 +58,7 @@ static void __init mpc832x_sys_setup_arch(void) struct device_node *np; u8 __iomem *bcsr_regs = NULL; - if (ppc_md.progress) - ppc_md.progress("mpc832x_sys_setup_arch()", 0); + mpc83xx_setup_arch(); /* Map BCSR area */ np = of_find_node_by_name(NULL, "bcsr"); @@ -71,8 +70,6 @@ static void __init mpc832x_sys_setup_arch(void) of_node_put(np); } - mpc83xx_setup_pci(); - #ifdef CONFIG_QUICC_ENGINE if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) { par_io_init(np); diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 0d6a62fc58646..d7c9b186954d9 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -197,10 +197,7 @@ static void __init mpc832x_rdb_setup_arch(void) struct device_node *np; #endif - if (ppc_md.progress) - ppc_md.progress("mpc832x_rdb_setup_arch()", 0); - - mpc83xx_setup_pci(); + mpc83xx_setup_arch(); #ifdef CONFIG_QUICC_ENGINE if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) { diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 8fd0c1e8b1828..73a5267df497e 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -57,10 +57,7 @@ machine_device_initcall(mpc834x_itx, mpc834x_itx_declare_of_platform_devices); */ static void __init mpc834x_itx_setup_arch(void) { - if (ppc_md.progress) - ppc_md.progress("mpc834x_itx_setup_arch()", 0); - - mpc83xx_setup_pci(); + mpc83xx_setup_arch(); mpc834x_usb_cfg(); } diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index eeaee6123bb34..009cfc18a4ee3 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -76,10 +76,7 @@ static int mpc834xemds_usb_cfg(void) */ static void __init mpc834x_mds_setup_arch(void) { - if (ppc_md.progress) - ppc_md.progress("mpc834x_mds_setup_arch()", 0); - - mpc83xx_setup_pci(); + mpc83xx_setup_arch(); mpc834xemds_usb_cfg(); } diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index dacf4c2df0697..4fc3051c2b2ee 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -66,8 +66,7 @@ static void __init mpc836x_mds_setup_arch(void) struct device_node *np; u8 __iomem *bcsr_regs = NULL; - if (ppc_md.progress) - ppc_md.progress("mpc836x_mds_setup_arch()", 0); + mpc83xx_setup_arch(); /* Map BCSR area */ np = of_find_node_by_name(NULL, "bcsr"); @@ -79,8 +78,6 @@ static void __init mpc836x_mds_setup_arch(void) of_node_put(np); } - mpc83xx_setup_pci(); - #ifdef CONFIG_QUICC_ENGINE if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) { par_io_init(np); diff --git a/arch/powerpc/platforms/83xx/mpc836x_rdk.c b/arch/powerpc/platforms/83xx/mpc836x_rdk.c index cf67ac93ddcb8..93f024fd9b459 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_rdk.c +++ b/arch/powerpc/platforms/83xx/mpc836x_rdk.c @@ -31,10 +31,7 @@ machine_device_initcall(mpc836x_rdk, mpc83xx_declare_of_platform_devices); static void __init mpc836x_rdk_setup_arch(void) { - if (ppc_md.progress) - ppc_md.progress("mpc836x_rdk_setup_arch()", 0); - - mpc83xx_setup_pci(); + mpc83xx_setup_arch(); } /* diff --git a/arch/powerpc/platforms/83xx/mpc837x_mds.c b/arch/powerpc/platforms/83xx/mpc837x_mds.c index 652b97d699c9b..3b34cc1f626c1 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc837x_mds.c @@ -79,10 +79,7 @@ static int mpc837xmds_usb_cfg(void) */ static void __init mpc837x_mds_setup_arch(void) { - if (ppc_md.progress) - ppc_md.progress("mpc837x_mds_setup_arch()", 0); - - mpc83xx_setup_pci(); + mpc83xx_setup_arch(); mpc837xmds_usb_cfg(); } diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index 667731d81676a..0c55fa6af2d54 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -50,10 +50,7 @@ static void mpc837x_rdb_sd_cfg(void) */ static void __init mpc837x_rdb_setup_arch(void) { - if (ppc_md.progress) - ppc_md.progress("mpc837x_rdb_setup_arch()", 0); - - mpc83xx_setup_pci(); + mpc83xx_setup_arch(); mpc837x_usb_cfg(); mpc837x_rdb_sd_cfg(); } diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index ad484199eff78..636eb9d0401ae 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -86,5 +86,6 @@ extern void mpc83xx_setup_pci(void); #endif extern int mpc83xx_declare_of_platform_devices(void); +extern void mpc83xx_setup_arch(void); #endif /* __MPC83XX_H__ */ diff --git a/arch/powerpc/platforms/83xx/sbc834x.c b/arch/powerpc/platforms/83xx/sbc834x.c index b867e88dfb0d2..cb4bdabfdf1cd 100644 --- a/arch/powerpc/platforms/83xx/sbc834x.c +++ b/arch/powerpc/platforms/83xx/sbc834x.c @@ -47,10 +47,7 @@ */ static void __init sbc834x_setup_arch(void) { - if (ppc_md.progress) - ppc_md.progress("sbc834x_setup_arch()", 0); - - mpc83xx_setup_pci(); + mpc83xx_setup_arch(); } machine_device_initcall(sbc834x, mpc83xx_declare_of_platform_devices); -- GitLab From 834e5a692120cc25c3935e8652a1989c2bc1c9e9 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 23 Aug 2016 15:58:56 +0200 Subject: [PATCH 0120/1167] powerpc/8xx: use SPRN_EIE and SPRN_EID to enable/disable interrupts The 8xx has two special registers called EID (External Interrupt Disable) and EIE (External Interrupt Enable) for clearing/setting EE in MSR. It avoids the three instructions set mfmsr/ori/mtmsr or mfmsr/rlwinm/mtmsr and it avoids using a general register. We just have to write something in the special register to change MSR EE bit. So we write r0 into the register, regardless of r0 value. Writing to one of those two special registers also set the MSR RI bit, but this bit is only unset during beginning of exception prolog and end of exception epilog. When executing C-functions MSR RI is always set. Signed-off-by: Christophe Leroy Signed-off-by: Scott Wood --- arch/powerpc/include/asm/hw_irq.h | 6 ++++++ arch/powerpc/include/asm/reg.h | 2 ++ arch/powerpc/include/asm/reg_8xx.h | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index c7d82ff62a334..eba60416536ec 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -155,6 +155,8 @@ static inline unsigned long arch_local_irq_save(void) unsigned long flags = arch_local_save_flags(); #ifdef CONFIG_BOOKE asm volatile("wrteei 0" : : : "memory"); +#elif defined(CONFIG_PPC_8xx) + wrtspr(SPRN_EID); #else SET_MSR_EE(flags & ~MSR_EE); #endif @@ -165,6 +167,8 @@ static inline void arch_local_irq_disable(void) { #ifdef CONFIG_BOOKE asm volatile("wrteei 0" : : : "memory"); +#elif defined(CONFIG_PPC_8xx) + wrtspr(SPRN_EID); #else arch_local_irq_save(); #endif @@ -174,6 +178,8 @@ static inline void arch_local_irq_enable(void) { #ifdef CONFIG_BOOKE asm volatile("wrteei 1" : : : "memory"); +#elif defined(CONFIG_PPC_8xx) + wrtspr(SPRN_EIE); #else unsigned long msr = mfmsr(); SET_MSR_EE(msr | MSR_EE); diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 9dddabc2fcedd..b320c8fb04500 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1249,6 +1249,8 @@ static inline void mtmsr_isync(unsigned long val) : "r" ((unsigned long)(v)) \ : "memory") #endif +#define wrtspr(rn) asm volatile("mtspr " __stringify(rn) ",0" : \ + : : "memory") extern void msr_check_and_set(unsigned long bits); extern bool strict_msr_control; diff --git a/arch/powerpc/include/asm/reg_8xx.h b/arch/powerpc/include/asm/reg_8xx.h index 94d01f81e6687..0197e12f7d482 100644 --- a/arch/powerpc/include/asm/reg_8xx.h +++ b/arch/powerpc/include/asm/reg_8xx.h @@ -25,6 +25,10 @@ #define SPRN_MD_RAM0 825 #define SPRN_MD_RAM1 826 +/* Special MSR manipulation registers */ +#define SPRN_EIE 80 /* External interrupt enable (EE=1, RI=1) */ +#define SPRN_EID 81 /* External interrupt disable (EE=0, RI=1) */ + /* Commands. Only the first few are available to the instruction cache. */ #define IDC_ENABLE 0x02000000 /* Cache enable */ -- GitLab From 63f1de882081919f2b548d04b6cf617398b8da12 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 26 Aug 2016 01:38:25 -0500 Subject: [PATCH 0121/1167] powerpc/fsl_pci: Size upper inbound window based on RAM size This allows PCI devices that can only address (e.g.) 36 or 40 bit DMA to use direct DMA, at the cost of not being able to DMA to non-RAM addresses (this doesn't affect MSIs as there is a separate dedicated window for that) which we wouldn't have been able to do anyway if the RAM size didn't trigger the creation of the second inbound window. It also fixes an off-by-one error that set dma_direct_ops on PCI devices whose dma mask could address all the space below the DMA offset (previously 40 bits), but not the window that starts at the DMA offset. Signed-off-by: Scott Wood Cc: Tillmann Heidsieck Tested-by: Tillmann Heidsieck --- arch/powerpc/sysdev/fsl_pci.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 0ef9df49f0f2c..d3a597456b6e5 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -111,8 +111,7 @@ static struct pci_ops fsl_indirect_pcie_ops = .write = indirect_write_config, }; -#define MAX_PHYS_ADDR_BITS 40 -static u64 pci64_dma_offset = 1ull << MAX_PHYS_ADDR_BITS; +static u64 pci64_dma_offset; #ifdef CONFIG_SWIOTLB static void setup_swiotlb_ops(struct pci_controller *hose) @@ -132,12 +131,10 @@ static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask) return -EIO; /* - * Fixup PCI devices that are able to DMA to above the physical - * address width of the SoC such that we can address any internal - * SoC address from across PCI if needed + * Fix up PCI devices that are able to DMA to the large inbound + * mapping that allows addressing any RAM address from across PCI. */ - if ((dev_is_pci(dev)) && - dma_mask >= DMA_BIT_MASK(MAX_PHYS_ADDR_BITS)) { + if (dev_is_pci(dev) && dma_mask >= pci64_dma_offset * 2 - 1) { set_dma_ops(dev, &dma_direct_ops); set_dma_offset(dev, pci64_dma_offset); } @@ -387,6 +384,7 @@ static void setup_pci_atmu(struct pci_controller *hose) mem_log++; piwar = (piwar & ~PIWAR_SZ_MASK) | (mem_log - 1); + pci64_dma_offset = 1ULL << mem_log; if (setup_inbound) { /* Setup inbound memory window */ -- GitLab From f307939fb260c83e6875476695ac58a669348b8f Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Mon, 5 Sep 2016 08:42:31 +0200 Subject: [PATCH 0122/1167] powerpc/8xx: add system_reset_exception When the watchdog is in NMI mode, the system reset interrupt is generated when the watchdog counter expires. Signed-off-by: Christophe Leroy Signed-off-by: Scott Wood --- arch/powerpc/kernel/head_8xx.S | 2 +- arch/powerpc/kernel/traps.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 3a185c51ce8f6..f559f217cd87e 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -226,7 +226,7 @@ i##n: \ ret_from_except) /* System reset */ - EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD) + EXCEPTION(0x100, Reset, system_reset_exception, EXC_XFER_STD) /* Machine check */ . = 0x200 diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 68f8b5b0d8858..137b1371cce8d 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -273,7 +273,6 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) force_sig_info(signr, &info, current); } -#ifdef CONFIG_PPC64 void system_reset_exception(struct pt_regs *regs) { /* See if any machine dependent calls */ @@ -291,6 +290,7 @@ void system_reset_exception(struct pt_regs *regs) /* What should we do here? We could issue a shutdown or hard reset. */ } +#ifdef CONFIG_PPC64 /* * This function is called in real mode. Strictly no printk's please. * -- GitLab From e627f8dc9a6fb8c9fff371ab99cc36b4f4116433 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 16 Sep 2016 10:23:11 +0200 Subject: [PATCH 0123/1167] powerpc/8xx: add dedicated machine check handler During a machine check, the 8xx provides indication of whether the check is due to data or instruction access, so let's display it. Lets also move 8xx specific handling into the new handler. Signed-off-by: Christophe Leroy Signed-off-by: Scott Wood --- arch/powerpc/include/asm/cputable.h | 1 + arch/powerpc/kernel/cputable.c | 1 + arch/powerpc/kernel/traps.c | 36 ++++++++++++++++++++--------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index f752e6f7cfbe2..ab68d0ee77258 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -43,6 +43,7 @@ extern int machine_check_e500mc(struct pt_regs *regs); extern int machine_check_e500(struct pt_regs *regs); extern int machine_check_e200(struct pt_regs *regs); extern int machine_check_47x(struct pt_regs *regs); +int machine_check_8xx(struct pt_regs *regs); extern void cpu_down_flush_e500v2(void); extern void cpu_down_flush_e500mc(void); diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 6c4646ac9234d..6a82ef039c509 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1248,6 +1248,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .mmu_features = MMU_FTR_TYPE_8xx, .icache_bsize = 16, .dcache_bsize = 16, + .machine_check = machine_check_8xx, .platform = "ppc823", }, #endif /* CONFIG_8xx */ diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 137b1371cce8d..e493062937b00 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -667,6 +667,31 @@ int machine_check_e200(struct pt_regs *regs) return 0; } +#elif defined(CONFIG_PPC_8xx) +int machine_check_8xx(struct pt_regs *regs) +{ + unsigned long reason = get_mc_reason(regs); + + pr_err("Machine check in kernel mode.\n"); + pr_err("Caused by (from SRR1=%lx): ", reason); + if (reason & 0x40000000) + pr_err("Fetch error at address %lx\n", regs->nip); + else + pr_err("Data access error at address %lx\n", regs->dar); + +#ifdef CONFIG_PCI + /* the qspan pci read routines can cause machine checks -- Cort + * + * yuck !!! that totally needs to go away ! There are better ways + * to deal with that than having a wart in the mcheck handler. + * -- BenH + */ + bad_page_fault(regs, regs->dar, SIGBUS); + return 1; +#else + return 0; +#endif +} #else int machine_check_generic(struct pt_regs *regs) { @@ -726,17 +751,6 @@ void machine_check_exception(struct pt_regs *regs) if (recover > 0) goto bail; -#if defined(CONFIG_8xx) && defined(CONFIG_PCI) - /* the qspan pci read routines can cause machine checks -- Cort - * - * yuck !!! that totally needs to go away ! There are better ways - * to deal with that than having a wart in the mcheck handler. - * -- BenH - */ - bad_page_fault(regs, regs->dar, SIGBUS); - goto bail; -#endif - if (debugger_fault_handler(regs)) goto bail; -- GitLab From 5dc6f3fedee58efa343e822558fc3e2f0eb2ad1f Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 6 Sep 2016 00:52:16 +0200 Subject: [PATCH 0124/1167] soc/fsl/qe: fix gpio save_regs functions of_mm_gpiochip_add_data() calls mm_gc->save_regs() before setting the data. Therefore ->save_regs() cannot use gpiochip_get_data() An Oops is encountered without this fix. fixes: 1e714e54b5ca5 ("powerpc: qe_lib-gpio: use gpiochip data pointer") Signed-off-by: Christophe Leroy Cc: Reviewed-by: Linus Walleij Signed-off-by: Scott Wood --- drivers/soc/fsl/qe/gpio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c index 333eb2215a579..0aaf429f31d57 100644 --- a/drivers/soc/fsl/qe/gpio.c +++ b/drivers/soc/fsl/qe/gpio.c @@ -41,7 +41,8 @@ struct qe_gpio_chip { static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) { - struct qe_gpio_chip *qe_gc = gpiochip_get_data(&mm_gc->gc); + struct qe_gpio_chip *qe_gc = + container_of(mm_gc, struct qe_gpio_chip, mm_gc); struct qe_pio_regs __iomem *regs = mm_gc->regs; qe_gc->cpdata = in_be32(®s->cpdata); -- GitLab From d1b9f81456d27dd44c0e7193a8a24ec0bfeda98b Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 16 Sep 2016 08:42:04 +0200 Subject: [PATCH 0125/1167] powerpc/8xx: use r3 to scratch CR in ITLBmiss Signed-off-by: Christophe Leroy Signed-off-by: Scott Wood --- arch/powerpc/kernel/head_8xx.S | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index f559f217cd87e..451e78929f168 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -321,7 +321,7 @@ SystemCall: #endif InstructionTLBMiss: -#ifdef CONFIG_8xx_CPU6 +#if defined(CONFIG_8xx_CPU6) || defined(CONFIG_MODULES) || defined (CONFIG_DEBUG_PAGEALLOC) mtspr SPRN_SPRG_SCRATCH2, r3 #endif EXCEPTION_PROLOG_0 @@ -329,23 +329,20 @@ InstructionTLBMiss: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ + mfspr r10, SPRN_SRR0 /* Get effective address of fault */ + INVALIDATE_ADJACENT_PAGES_CPU15(r11, r10) #if defined(CONFIG_MODULES) || defined (CONFIG_DEBUG_PAGEALLOC) /* Only modules will cause ITLB Misses as we always * pin the first 8MB of kernel memory */ - mfspr r11, SPRN_SRR0 /* Get effective address of fault */ - INVALIDATE_ADJACENT_PAGES_CPU15(r10, r11) - mfcr r10 - IS_KERNEL(r11, r11) + mfcr r3 + IS_KERNEL(r11, r10) +#endif mfspr r11, SPRN_M_TW /* Get level 1 table */ +#if defined(CONFIG_MODULES) || defined (CONFIG_DEBUG_PAGEALLOC) BRANCH_UNLESS_KERNEL(3f) lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha 3: - mtcr r10 - mfspr r10, SPRN_SRR0 /* Get effective address of fault */ -#else - mfspr r10, SPRN_SRR0 /* Get effective address of fault */ - INVALIDATE_ADJACENT_PAGES_CPU15(r11, r10) - mfspr r11, SPRN_M_TW /* Get level 1 table base address */ + mtcr r3 #endif /* Insert level 1 index */ rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29 @@ -377,7 +374,7 @@ InstructionTLBMiss: MTSPR_CPU6(SPRN_MI_RPN, r10, r3) /* Update TLB entry */ /* Restore registers */ -#ifdef CONFIG_8xx_CPU6 +#if defined(CONFIG_8xx_CPU6) || defined(CONFIG_MODULES) || defined (CONFIG_DEBUG_PAGEALLOC) mfspr r3, SPRN_SPRG_SCRATCH2 #endif EXCEPTION_EPILOG_0 -- GitLab From 73a532061c65f4e15a3aa7d75fde81203749562b Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 16 Sep 2016 08:42:06 +0200 Subject: [PATCH 0126/1167] powerpc/8xx: Move additional DTLBMiss handlers out of exception area When all options are activated, there is not enough space for the DTLBMiss handlers that handles IMMR area and linear RAM pages in the exception area once we have added hugepage handling. So lets move them after .0x2000 Signed-off-by: Christophe Leroy Signed-off-by: Scott Wood --- arch/powerpc/kernel/head_8xx.S | 84 +++++++++++++++++----------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 451e78929f168..f674dfae1e95e 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -380,26 +380,6 @@ InstructionTLBMiss: EXCEPTION_EPILOG_0 rfi -/* - * Bottom part of DataStoreTLBMiss handler for IMMR area - * not enough space in the DataStoreTLBMiss area - */ -DTLBMissIMMR: - mtcr r10 - /* Set 512k byte guarded page and mark it valid */ - li r10, MD_PS512K | MD_GUARDED | MD_SVALID - MTSPR_CPU6(SPRN_MD_TWC, r10, r11) - mfspr r10, SPRN_IMMR /* Get current IMMR */ - rlwinm r10, r10, 0, 0xfff80000 /* Get 512 kbytes boundary */ - ori r10, r10, 0xf0 | MD_SPS16K | _PAGE_SHARED | _PAGE_DIRTY | \ - _PAGE_PRESENT | _PAGE_NO_CACHE - MTSPR_CPU6(SPRN_MD_RPN, r10, r11) /* Update TLB entry */ - - li r11, RPN_PATTERN - mtspr SPRN_DAR, r11 /* Tag DAR */ - EXCEPTION_EPILOG_0 - rfi - . = 0x1200 DataStoreTLBMiss: EXCEPTION_PROLOG_0 @@ -418,7 +398,7 @@ DataStoreTLBMiss: _ENTRY(DTLBMiss_jmp) beq- DTLBMissIMMR #endif - bge- cr7, 4f + bge- cr7, DTLBMissLinear mfspr r11, SPRN_M_TW /* Get level 1 table */ 3: @@ -485,27 +465,6 @@ _ENTRY(DTLBMiss_jmp) EXCEPTION_EPILOG_0 rfi -4: -_ENTRY(DTLBMiss_cmp) - cmpli cr0, r11, (PAGE_OFFSET + 0x1800000)@h - lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha - bge- 3b - - mtcr r10 - /* Set 8M byte page and mark it valid */ - li r10, MD_PS8MEG | MD_SVALID - MTSPR_CPU6(SPRN_MD_TWC, r10, r11) - mfspr r10, SPRN_MD_EPN - rlwinm r10, r10, 0, 0x0f800000 /* 8xx supports max 256Mb RAM */ - ori r10, r10, 0xf0 | MD_SPS16K | _PAGE_SHARED | _PAGE_DIRTY | \ - _PAGE_PRESENT - MTSPR_CPU6(SPRN_MD_RPN, r10, r11) /* Update TLB entry */ - - li r11, RPN_PATTERN - mtspr SPRN_DAR, r11 /* Tag DAR */ - EXCEPTION_EPILOG_0 - rfi - /* This is an instruction TLB error on the MPC8xx. This could be due * to many reasons, such as executing guarded memory or illegal instruction @@ -567,6 +526,47 @@ DARFixed:/* Return from dcbx instruction bug workaround */ . = 0x2000 +/* + * Bottom part of DataStoreTLBMiss handlers for IMMR area and linear RAM. + * not enough space in the DataStoreTLBMiss area. + */ +DTLBMissIMMR: + mtcr r10 + /* Set 512k byte guarded page and mark it valid */ + li r10, MD_PS512K | MD_GUARDED | MD_SVALID + MTSPR_CPU6(SPRN_MD_TWC, r10, r11) + mfspr r10, SPRN_IMMR /* Get current IMMR */ + rlwinm r10, r10, 0, 0xfff80000 /* Get 512 kbytes boundary */ + ori r10, r10, 0xf0 | MD_SPS16K | _PAGE_SHARED | _PAGE_DIRTY | \ + _PAGE_PRESENT | _PAGE_NO_CACHE + MTSPR_CPU6(SPRN_MD_RPN, r10, r11) /* Update TLB entry */ + + li r11, RPN_PATTERN + mtspr SPRN_DAR, r11 /* Tag DAR */ + EXCEPTION_EPILOG_0 + rfi + +DTLBMissLinear: +_ENTRY(DTLBMiss_cmp) + cmpli cr0, r11, (PAGE_OFFSET + 0x1800000)@h + lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha + bge- 3b + + mtcr r10 + /* Set 8M byte page and mark it valid */ + li r10, MD_PS8MEG | MD_SVALID + MTSPR_CPU6(SPRN_MD_TWC, r10, r11) + mfspr r10, SPRN_MD_EPN + rlwinm r10, r10, 0, 0x0f800000 /* 8xx supports max 256Mb RAM */ + ori r10, r10, 0xf0 | MD_SPS16K | _PAGE_SHARED | _PAGE_DIRTY | \ + _PAGE_PRESENT + MTSPR_CPU6(SPRN_MD_RPN, r10, r11) /* Update TLB entry */ + + li r11, RPN_PATTERN + mtspr SPRN_DAR, r11 /* Tag DAR */ + EXCEPTION_EPILOG_0 + rfi + /* This is the procedure to calculate the data EA for buggy dcbx,dcbi instructions * by decoding the registers used by the dcbx instruction and adding them. * DAR is set to the calculated address. -- GitLab From 36eb1542fc97c3164a08751b97dafdac0f9e1366 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 16 Sep 2016 08:42:08 +0200 Subject: [PATCH 0127/1167] powerpc/8xx: make user addr DTLB miss the short path User space DTLB miss represent approximatly 90% of TLB misses so make it the shortest path. Also remove an unneccessary double jump in FixupDAR Before this patch, we spend 3.3 TB ticks in the handler for each user address miss and 3.4 TB ticks for each kernel address miss After this patch, we send 3.0 TB ticks in the handler for each user address miss and 3.9 TB ticks for each kernel address miss Taking into account that user misses represent 90% of the total, this patch provides an improvement of approx. 9% Signed-off-by: Christophe Leroy Signed-off-by: Scott Wood --- arch/powerpc/kernel/head_8xx.S | 53 +++++++++++++++------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index f674dfae1e95e..033a6b7354872 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -382,30 +382,31 @@ InstructionTLBMiss: . = 0x1200 DataStoreTLBMiss: + mtspr SPRN_SPRG_SCRATCH2, r3 EXCEPTION_PROLOG_0 - mfcr r10 + mfcr r3 /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - mfspr r11, SPRN_MD_EPN - rlwinm r11, r11, 16, 0xfff8 + mfspr r10, SPRN_MD_EPN + rlwinm r10, r10, 16, 0xfff8 + cmpli cr0, r10, PAGE_OFFSET@h + mfspr r11, SPRN_M_TW /* Get level 1 table */ + blt+ 3f #ifndef CONFIG_PIN_TLB_IMMR - cmpli cr0, r11, VIRT_IMMR_BASE@h + cmpli cr0, r10, VIRT_IMMR_BASE@h #endif - cmpli cr7, r11, PAGE_OFFSET@h +_ENTRY(DTLBMiss_cmp) + cmpli cr7, r10, (PAGE_OFFSET + 0x1800000)@h + lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha #ifndef CONFIG_PIN_TLB_IMMR _ENTRY(DTLBMiss_jmp) beq- DTLBMissIMMR #endif - bge- cr7, DTLBMissLinear - - mfspr r11, SPRN_M_TW /* Get level 1 table */ + blt cr7, DTLBMissLinear 3: - mtcr r10 -#ifdef CONFIG_8xx_CPU6 - mtspr SPRN_SPRG_SCRATCH2, r3 -#endif + mtcr r3 mfspr r10, SPRN_MD_EPN /* Insert level 1 index */ @@ -458,9 +459,7 @@ _ENTRY(DTLBMiss_jmp) MTSPR_CPU6(SPRN_MD_RPN, r10, r3) /* Update TLB entry */ /* Restore registers */ -#ifdef CONFIG_8xx_CPU6 mfspr r3, SPRN_SPRG_SCRATCH2 -#endif mtspr SPRN_DAR, r11 /* Tag DAR */ EXCEPTION_EPILOG_0 rfi @@ -531,7 +530,7 @@ DARFixed:/* Return from dcbx instruction bug workaround */ * not enough space in the DataStoreTLBMiss area. */ DTLBMissIMMR: - mtcr r10 + mtcr r3 /* Set 512k byte guarded page and mark it valid */ li r10, MD_PS512K | MD_GUARDED | MD_SVALID MTSPR_CPU6(SPRN_MD_TWC, r10, r11) @@ -543,27 +542,23 @@ DTLBMissIMMR: li r11, RPN_PATTERN mtspr SPRN_DAR, r11 /* Tag DAR */ + mfspr r3, SPRN_SPRG_SCRATCH2 EXCEPTION_EPILOG_0 rfi DTLBMissLinear: -_ENTRY(DTLBMiss_cmp) - cmpli cr0, r11, (PAGE_OFFSET + 0x1800000)@h - lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha - bge- 3b - - mtcr r10 + mtcr r3 /* Set 8M byte page and mark it valid */ - li r10, MD_PS8MEG | MD_SVALID - MTSPR_CPU6(SPRN_MD_TWC, r10, r11) - mfspr r10, SPRN_MD_EPN - rlwinm r10, r10, 0, 0x0f800000 /* 8xx supports max 256Mb RAM */ + li r11, MD_PS8MEG | MD_SVALID + MTSPR_CPU6(SPRN_MD_TWC, r11, r3) + rlwinm r10, r10, 16, 0x0f800000 /* 8xx supports max 256Mb RAM */ ori r10, r10, 0xf0 | MD_SPS16K | _PAGE_SHARED | _PAGE_DIRTY | \ _PAGE_PRESENT MTSPR_CPU6(SPRN_MD_RPN, r10, r11) /* Update TLB entry */ li r11, RPN_PATTERN mtspr SPRN_DAR, r11 /* Tag DAR */ + mfspr r3, SPRN_SPRG_SCRATCH2 EXCEPTION_EPILOG_0 rfi @@ -583,7 +578,9 @@ FixupDAR:/* Entry point for dcbx workaround. */ rlwinm r11, r10, 16, 0xfff8 _ENTRY(FixupDAR_cmp) cmpli cr7, r11, (PAGE_OFFSET + 0x1800000)@h - blt- cr7, 200f + /* create physical page address from effective address */ + tophys(r11, r10) + blt- cr7, 201f lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha /* Insert level 1 index */ 3: rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29 @@ -613,10 +610,6 @@ _ENTRY(FixupDAR_cmp) 141: mfspr r10,SPRN_SPRG_SCRATCH2 b DARFixed /* Nope, go back to normal TLB processing */ - /* create physical page address from effective address */ -200: tophys(r11, r10) - b 201b - 144: mfspr r10, SPRN_DSISR rlwinm r10, r10,0,7,5 /* Clear store bit for buggy dcbst insn */ mtspr SPRN_DSISR, r10 -- GitLab From 1f9c0a77278bc9ec7df14bbd799fccfabff1010a Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 22 Sep 2016 18:04:08 +0300 Subject: [PATCH 0128/1167] soc/fsl: Introduce DPAA 1.x BMan device driver This driver enables the Freescale DPAA 1.x Buffer Manager block. BMan is a hardware accelerator that manages buffer pools. It allows CPUs and other accelerators connected to the SoC datapath to acquire and release buffers during data processing. Signed-off-by: Roy Pledge Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/Kconfig | 28 + drivers/soc/fsl/qbman/Makefile | 2 + drivers/soc/fsl/qbman/bman.c | 797 ++++++++++++++++++++++++++++ drivers/soc/fsl/qbman/bman_ccsr.c | 263 +++++++++ drivers/soc/fsl/qbman/bman_portal.c | 219 ++++++++ drivers/soc/fsl/qbman/bman_priv.h | 80 +++ drivers/soc/fsl/qbman/dpaa_sys.h | 103 ++++ include/soc/fsl/bman.h | 129 +++++ 8 files changed, 1621 insertions(+) create mode 100644 drivers/soc/fsl/qbman/Kconfig create mode 100644 drivers/soc/fsl/qbman/Makefile create mode 100644 drivers/soc/fsl/qbman/bman.c create mode 100644 drivers/soc/fsl/qbman/bman_ccsr.c create mode 100644 drivers/soc/fsl/qbman/bman_portal.c create mode 100644 drivers/soc/fsl/qbman/bman_priv.h create mode 100644 drivers/soc/fsl/qbman/dpaa_sys.h create mode 100644 include/soc/fsl/bman.h diff --git a/drivers/soc/fsl/qbman/Kconfig b/drivers/soc/fsl/qbman/Kconfig new file mode 100644 index 0000000000000..8f2df64224bf9 --- /dev/null +++ b/drivers/soc/fsl/qbman/Kconfig @@ -0,0 +1,28 @@ +menuconfig FSL_DPAA + bool "Freescale DPAA 1.x support" + depends on FSL_SOC_BOOKE + select GENERIC_ALLOCATOR + help + The Freescale Data Path Acceleration Architecture (DPAA) is a set of + hardware components on specific QorIQ multicore processors. + This architecture provides the infrastructure to support simplified + sharing of networking interfaces and accelerators by multiple CPUs. + The major h/w blocks composing DPAA are BMan and QMan. + + The Buffer Manager (BMan) is a hardware buffer pool management block + that allows software and accelerators on the datapath to acquire and + release buffers in order to build frames. + + The Queue Manager (QMan) is a hardware queue management block + that allows software and accelerators on the datapath to enqueue and + dequeue frames in order to communicate. + +if FSL_DPAA + +config FSL_DPAA_CHECKING + bool "Additional driver checking" + help + Compiles in additional checks, to sanity-check the drivers and + any use of the exported API. Not recommended for performance. + +endif # FSL_DPAA diff --git a/drivers/soc/fsl/qbman/Makefile b/drivers/soc/fsl/qbman/Makefile new file mode 100644 index 0000000000000..855c3ac0f89ee --- /dev/null +++ b/drivers/soc/fsl/qbman/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_FSL_DPAA) += bman_ccsr.o bman_portal.o \ + bman.o diff --git a/drivers/soc/fsl/qbman/bman.c b/drivers/soc/fsl/qbman/bman.c new file mode 100644 index 0000000000000..ffa48fdbb1a9a --- /dev/null +++ b/drivers/soc/fsl/qbman/bman.c @@ -0,0 +1,797 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_priv.h" + +#define IRQNAME "BMan portal %d" +#define MAX_IRQNAME 16 /* big enough for "BMan portal %d" */ + +/* Portal register assists */ + +/* Cache-inhibited register offsets */ +#define BM_REG_RCR_PI_CINH 0x0000 +#define BM_REG_RCR_CI_CINH 0x0004 +#define BM_REG_RCR_ITR 0x0008 +#define BM_REG_CFG 0x0100 +#define BM_REG_SCN(n) (0x0200 + ((n) << 2)) +#define BM_REG_ISR 0x0e00 +#define BM_REG_IER 0x0e04 +#define BM_REG_ISDR 0x0e08 +#define BM_REG_IIR 0x0e0c + +/* Cache-enabled register offsets */ +#define BM_CL_CR 0x0000 +#define BM_CL_RR0 0x0100 +#define BM_CL_RR1 0x0140 +#define BM_CL_RCR 0x1000 +#define BM_CL_RCR_PI_CENA 0x3000 +#define BM_CL_RCR_CI_CENA 0x3100 + +/* + * Portal modes. + * Enum types; + * pmode == production mode + * cmode == consumption mode, + * Enum values use 3 letter codes. First letter matches the portal mode, + * remaining two letters indicate; + * ci == cache-inhibited portal register + * ce == cache-enabled portal register + * vb == in-band valid-bit (cache-enabled) + */ +enum bm_rcr_pmode { /* matches BCSP_CFG::RPM */ + bm_rcr_pci = 0, /* PI index, cache-inhibited */ + bm_rcr_pce = 1, /* PI index, cache-enabled */ + bm_rcr_pvb = 2 /* valid-bit */ +}; +enum bm_rcr_cmode { /* s/w-only */ + bm_rcr_cci, /* CI index, cache-inhibited */ + bm_rcr_cce /* CI index, cache-enabled */ +}; + + +/* --- Portal structures --- */ + +#define BM_RCR_SIZE 8 + +/* Release Command */ +struct bm_rcr_entry { + union { + struct { + u8 _ncw_verb; /* writes to this are non-coherent */ + u8 bpid; /* used with BM_RCR_VERB_CMD_BPID_SINGLE */ + u8 __reserved1[62]; + }; + struct bm_buffer bufs[8]; + }; +}; +#define BM_RCR_VERB_VBIT 0x80 +#define BM_RCR_VERB_CMD_MASK 0x70 /* one of two values; */ +#define BM_RCR_VERB_CMD_BPID_SINGLE 0x20 +#define BM_RCR_VERB_CMD_BPID_MULTI 0x30 +#define BM_RCR_VERB_BUFCOUNT_MASK 0x0f /* values 1..8 */ + +struct bm_rcr { + struct bm_rcr_entry *ring, *cursor; + u8 ci, available, ithresh, vbit; +#ifdef CONFIG_FSL_DPAA_CHECKING + u32 busy; + enum bm_rcr_pmode pmode; + enum bm_rcr_cmode cmode; +#endif +}; + +/* MC (Management Command) command */ +struct bm_mc_command { + u8 _ncw_verb; /* writes to this are non-coherent */ + u8 bpid; /* used by acquire command */ + u8 __reserved[62]; +}; +#define BM_MCC_VERB_VBIT 0x80 +#define BM_MCC_VERB_CMD_MASK 0x70 /* where the verb contains; */ +#define BM_MCC_VERB_CMD_ACQUIRE 0x10 +#define BM_MCC_VERB_CMD_QUERY 0x40 +#define BM_MCC_VERB_ACQUIRE_BUFCOUNT 0x0f /* values 1..8 go here */ + +/* MC result, Acquire and Query Response */ +union bm_mc_result { + struct { + u8 verb; + u8 bpid; + u8 __reserved[62]; + }; + struct bm_buffer bufs[8]; +}; +#define BM_MCR_VERB_VBIT 0x80 +#define BM_MCR_VERB_CMD_MASK BM_MCC_VERB_CMD_MASK +#define BM_MCR_VERB_CMD_ACQUIRE BM_MCC_VERB_CMD_ACQUIRE +#define BM_MCR_VERB_CMD_QUERY BM_MCC_VERB_CMD_QUERY +#define BM_MCR_VERB_CMD_ERR_INVALID 0x60 +#define BM_MCR_VERB_CMD_ERR_ECC 0x70 +#define BM_MCR_VERB_ACQUIRE_BUFCOUNT BM_MCC_VERB_ACQUIRE_BUFCOUNT /* 0..8 */ +#define BM_MCR_TIMEOUT 10000 /* us */ + +struct bm_mc { + struct bm_mc_command *cr; + union bm_mc_result *rr; + u8 rridx, vbit; +#ifdef CONFIG_FSL_DPAA_CHECKING + enum { + /* Can only be _mc_start()ed */ + mc_idle, + /* Can only be _mc_commit()ed or _mc_abort()ed */ + mc_user, + /* Can only be _mc_retry()ed */ + mc_hw + } state; +#endif +}; + +struct bm_addr { + void __iomem *ce; /* cache-enabled */ + void __iomem *ci; /* cache-inhibited */ +}; + +struct bm_portal { + struct bm_addr addr; + struct bm_rcr rcr; + struct bm_mc mc; +} ____cacheline_aligned; + +/* Cache-inhibited register access. */ +static inline u32 bm_in(struct bm_portal *p, u32 offset) +{ + return __raw_readl(p->addr.ci + offset); +} + +static inline void bm_out(struct bm_portal *p, u32 offset, u32 val) +{ + __raw_writel(val, p->addr.ci + offset); +} + +/* Cache Enabled Portal Access */ +static inline void bm_cl_invalidate(struct bm_portal *p, u32 offset) +{ + dpaa_invalidate(p->addr.ce + offset); +} + +static inline void bm_cl_touch_ro(struct bm_portal *p, u32 offset) +{ + dpaa_touch_ro(p->addr.ce + offset); +} + +static inline u32 bm_ce_in(struct bm_portal *p, u32 offset) +{ + return __raw_readl(p->addr.ce + offset); +} + +struct bman_portal { + struct bm_portal p; + /* interrupt sources processed by portal_isr(), configurable */ + unsigned long irq_sources; + /* probing time config params for cpu-affine portals */ + const struct bm_portal_config *config; + char irqname[MAX_IRQNAME]; +}; + +static cpumask_t affine_mask; +static DEFINE_SPINLOCK(affine_mask_lock); +static DEFINE_PER_CPU(struct bman_portal, bman_affine_portal); + +static inline struct bman_portal *get_affine_portal(void) +{ + return &get_cpu_var(bman_affine_portal); +} + +static inline void put_affine_portal(void) +{ + put_cpu_var(bman_affine_portal); +} + +/* + * This object type refers to a pool, it isn't *the* pool. There may be + * more than one such object per BMan buffer pool, eg. if different users of the + * pool are operating via different portals. + */ +struct bman_pool { + /* index of the buffer pool to encapsulate (0-63) */ + u32 bpid; + /* Used for hash-table admin when using depletion notifications. */ + struct bman_portal *portal; + struct bman_pool *next; +}; + +static u32 poll_portal_slow(struct bman_portal *p, u32 is); + +static irqreturn_t portal_isr(int irq, void *ptr) +{ + struct bman_portal *p = ptr; + struct bm_portal *portal = &p->p; + u32 clear = p->irq_sources; + u32 is = bm_in(portal, BM_REG_ISR) & p->irq_sources; + + if (unlikely(!is)) + return IRQ_NONE; + + clear |= poll_portal_slow(p, is); + bm_out(portal, BM_REG_ISR, clear); + return IRQ_HANDLED; +} + +/* --- RCR API --- */ + +#define RCR_SHIFT ilog2(sizeof(struct bm_rcr_entry)) +#define RCR_CARRY (uintptr_t)(BM_RCR_SIZE << RCR_SHIFT) + +/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */ +static struct bm_rcr_entry *rcr_carryclear(struct bm_rcr_entry *p) +{ + uintptr_t addr = (uintptr_t)p; + + addr &= ~RCR_CARRY; + + return (struct bm_rcr_entry *)addr; +} + +#ifdef CONFIG_FSL_DPAA_CHECKING +/* Bit-wise logic to convert a ring pointer to a ring index */ +static int rcr_ptr2idx(struct bm_rcr_entry *e) +{ + return ((uintptr_t)e >> RCR_SHIFT) & (BM_RCR_SIZE - 1); +} +#endif + +/* Increment the 'cursor' ring pointer, taking 'vbit' into account */ +static inline void rcr_inc(struct bm_rcr *rcr) +{ + /* increment to the next RCR pointer and handle overflow and 'vbit' */ + struct bm_rcr_entry *partial = rcr->cursor + 1; + + rcr->cursor = rcr_carryclear(partial); + if (partial != rcr->cursor) + rcr->vbit ^= BM_RCR_VERB_VBIT; +} + +static int bm_rcr_get_avail(struct bm_portal *portal) +{ + struct bm_rcr *rcr = &portal->rcr; + + return rcr->available; +} + +static int bm_rcr_get_fill(struct bm_portal *portal) +{ + struct bm_rcr *rcr = &portal->rcr; + + return BM_RCR_SIZE - 1 - rcr->available; +} + +static void bm_rcr_set_ithresh(struct bm_portal *portal, u8 ithresh) +{ + struct bm_rcr *rcr = &portal->rcr; + + rcr->ithresh = ithresh; + bm_out(portal, BM_REG_RCR_ITR, ithresh); +} + +static void bm_rcr_cce_prefetch(struct bm_portal *portal) +{ + __maybe_unused struct bm_rcr *rcr = &portal->rcr; + + DPAA_ASSERT(rcr->cmode == bm_rcr_cce); + bm_cl_touch_ro(portal, BM_CL_RCR_CI_CENA); +} + +static u8 bm_rcr_cce_update(struct bm_portal *portal) +{ + struct bm_rcr *rcr = &portal->rcr; + u8 diff, old_ci = rcr->ci; + + DPAA_ASSERT(rcr->cmode == bm_rcr_cce); + rcr->ci = bm_ce_in(portal, BM_CL_RCR_CI_CENA) & (BM_RCR_SIZE - 1); + bm_cl_invalidate(portal, BM_CL_RCR_CI_CENA); + diff = dpaa_cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci); + rcr->available += diff; + return diff; +} + +static inline struct bm_rcr_entry *bm_rcr_start(struct bm_portal *portal) +{ + struct bm_rcr *rcr = &portal->rcr; + + DPAA_ASSERT(!rcr->busy); + if (!rcr->available) + return NULL; +#ifdef CONFIG_FSL_DPAA_CHECKING + rcr->busy = 1; +#endif + dpaa_zero(rcr->cursor); + return rcr->cursor; +} + +static inline void bm_rcr_pvb_commit(struct bm_portal *portal, u8 myverb) +{ + struct bm_rcr *rcr = &portal->rcr; + struct bm_rcr_entry *rcursor; + + DPAA_ASSERT(rcr->busy); + DPAA_ASSERT(rcr->pmode == bm_rcr_pvb); + DPAA_ASSERT(rcr->available >= 1); + dma_wmb(); + rcursor = rcr->cursor; + rcursor->_ncw_verb = myverb | rcr->vbit; + dpaa_flush(rcursor); + rcr_inc(rcr); + rcr->available--; +#ifdef CONFIG_FSL_DPAA_CHECKING + rcr->busy = 0; +#endif +} + +static int bm_rcr_init(struct bm_portal *portal, enum bm_rcr_pmode pmode, + enum bm_rcr_cmode cmode) +{ + struct bm_rcr *rcr = &portal->rcr; + u32 cfg; + u8 pi; + + rcr->ring = portal->addr.ce + BM_CL_RCR; + rcr->ci = bm_in(portal, BM_REG_RCR_CI_CINH) & (BM_RCR_SIZE - 1); + pi = bm_in(portal, BM_REG_RCR_PI_CINH) & (BM_RCR_SIZE - 1); + rcr->cursor = rcr->ring + pi; + rcr->vbit = (bm_in(portal, BM_REG_RCR_PI_CINH) & BM_RCR_SIZE) ? + BM_RCR_VERB_VBIT : 0; + rcr->available = BM_RCR_SIZE - 1 + - dpaa_cyc_diff(BM_RCR_SIZE, rcr->ci, pi); + rcr->ithresh = bm_in(portal, BM_REG_RCR_ITR); +#ifdef CONFIG_FSL_DPAA_CHECKING + rcr->busy = 0; + rcr->pmode = pmode; + rcr->cmode = cmode; +#endif + cfg = (bm_in(portal, BM_REG_CFG) & 0xffffffe0) + | (pmode & 0x3); /* BCSP_CFG::RPM */ + bm_out(portal, BM_REG_CFG, cfg); + return 0; +} + +static void bm_rcr_finish(struct bm_portal *portal) +{ +#ifdef CONFIG_FSL_DPAA_CHECKING + struct bm_rcr *rcr = &portal->rcr; + int i; + + DPAA_ASSERT(!rcr->busy); + + i = bm_in(portal, BM_REG_RCR_PI_CINH) & (BM_RCR_SIZE - 1); + if (i != rcr_ptr2idx(rcr->cursor)) + pr_crit("losing uncommited RCR entries\n"); + + i = bm_in(portal, BM_REG_RCR_CI_CINH) & (BM_RCR_SIZE - 1); + if (i != rcr->ci) + pr_crit("missing existing RCR completions\n"); + if (rcr->ci != rcr_ptr2idx(rcr->cursor)) + pr_crit("RCR destroyed unquiesced\n"); +#endif +} + +/* --- Management command API --- */ +static int bm_mc_init(struct bm_portal *portal) +{ + struct bm_mc *mc = &portal->mc; + + mc->cr = portal->addr.ce + BM_CL_CR; + mc->rr = portal->addr.ce + BM_CL_RR0; + mc->rridx = (__raw_readb(&mc->cr->_ncw_verb) & BM_MCC_VERB_VBIT) ? + 0 : 1; + mc->vbit = mc->rridx ? BM_MCC_VERB_VBIT : 0; +#ifdef CONFIG_FSL_DPAA_CHECKING + mc->state = mc_idle; +#endif + return 0; +} + +static void bm_mc_finish(struct bm_portal *portal) +{ +#ifdef CONFIG_FSL_DPAA_CHECKING + struct bm_mc *mc = &portal->mc; + + DPAA_ASSERT(mc->state == mc_idle); + if (mc->state != mc_idle) + pr_crit("Losing incomplete MC command\n"); +#endif +} + +static inline struct bm_mc_command *bm_mc_start(struct bm_portal *portal) +{ + struct bm_mc *mc = &portal->mc; + + DPAA_ASSERT(mc->state == mc_idle); +#ifdef CONFIG_FSL_DPAA_CHECKING + mc->state = mc_user; +#endif + dpaa_zero(mc->cr); + return mc->cr; +} + +static inline void bm_mc_commit(struct bm_portal *portal, u8 myverb) +{ + struct bm_mc *mc = &portal->mc; + union bm_mc_result *rr = mc->rr + mc->rridx; + + DPAA_ASSERT(mc->state == mc_user); + dma_wmb(); + mc->cr->_ncw_verb = myverb | mc->vbit; + dpaa_flush(mc->cr); + dpaa_invalidate_touch_ro(rr); +#ifdef CONFIG_FSL_DPAA_CHECKING + mc->state = mc_hw; +#endif +} + +static inline union bm_mc_result *bm_mc_result(struct bm_portal *portal) +{ + struct bm_mc *mc = &portal->mc; + union bm_mc_result *rr = mc->rr + mc->rridx; + + DPAA_ASSERT(mc->state == mc_hw); + /* + * The inactive response register's verb byte always returns zero until + * its command is submitted and completed. This includes the valid-bit, + * in case you were wondering... + */ + if (!__raw_readb(&rr->verb)) { + dpaa_invalidate_touch_ro(rr); + return NULL; + } + mc->rridx ^= 1; + mc->vbit ^= BM_MCC_VERB_VBIT; +#ifdef CONFIG_FSL_DPAA_CHECKING + mc->state = mc_idle; +#endif + return rr; +} + +static inline int bm_mc_result_timeout(struct bm_portal *portal, + union bm_mc_result **mcr) +{ + int timeout = BM_MCR_TIMEOUT; + + do { + *mcr = bm_mc_result(portal); + if (*mcr) + break; + udelay(1); + } while (--timeout); + + return timeout; +} + +/* Disable all BSCN interrupts for the portal */ +static void bm_isr_bscn_disable(struct bm_portal *portal) +{ + bm_out(portal, BM_REG_SCN(0), 0); + bm_out(portal, BM_REG_SCN(1), 0); +} + +static int bman_create_portal(struct bman_portal *portal, + const struct bm_portal_config *c) +{ + struct bm_portal *p; + int ret; + + p = &portal->p; + /* + * prep the low-level portal struct with the mapped addresses from the + * config, everything that follows depends on it and "config" is more + * for (de)reference... + */ + p->addr.ce = c->addr_virt[DPAA_PORTAL_CE]; + p->addr.ci = c->addr_virt[DPAA_PORTAL_CI]; + if (bm_rcr_init(p, bm_rcr_pvb, bm_rcr_cce)) { + dev_err(c->dev, "RCR initialisation failed\n"); + goto fail_rcr; + } + if (bm_mc_init(p)) { + dev_err(c->dev, "MC initialisation failed\n"); + goto fail_mc; + } + /* + * Default to all BPIDs disabled, we enable as required at + * run-time. + */ + bm_isr_bscn_disable(p); + + /* Write-to-clear any stale interrupt status bits */ + bm_out(p, BM_REG_ISDR, 0xffffffff); + portal->irq_sources = 0; + bm_out(p, BM_REG_IER, 0); + bm_out(p, BM_REG_ISR, 0xffffffff); + snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu); + if (request_irq(c->irq, portal_isr, 0, portal->irqname, portal)) { + dev_err(c->dev, "request_irq() failed\n"); + goto fail_irq; + } + if (c->cpu != -1 && irq_can_set_affinity(c->irq) && + irq_set_affinity(c->irq, cpumask_of(c->cpu))) { + dev_err(c->dev, "irq_set_affinity() failed\n"); + goto fail_affinity; + } + + /* Need RCR to be empty before continuing */ + ret = bm_rcr_get_fill(p); + if (ret) { + dev_err(c->dev, "RCR unclean\n"); + goto fail_rcr_empty; + } + /* Success */ + portal->config = c; + + bm_out(p, BM_REG_ISDR, 0); + bm_out(p, BM_REG_IIR, 0); + + return 0; + +fail_rcr_empty: +fail_affinity: + free_irq(c->irq, portal); +fail_irq: + bm_mc_finish(p); +fail_mc: + bm_rcr_finish(p); +fail_rcr: + return -EIO; +} + +struct bman_portal *bman_create_affine_portal(const struct bm_portal_config *c) +{ + struct bman_portal *portal; + int err; + + portal = &per_cpu(bman_affine_portal, c->cpu); + err = bman_create_portal(portal, c); + if (err) + return NULL; + + spin_lock(&affine_mask_lock); + cpumask_set_cpu(c->cpu, &affine_mask); + spin_unlock(&affine_mask_lock); + + return portal; +} + +static u32 poll_portal_slow(struct bman_portal *p, u32 is) +{ + u32 ret = is; + + if (is & BM_PIRQ_RCRI) { + bm_rcr_cce_update(&p->p); + bm_rcr_set_ithresh(&p->p, 0); + bm_out(&p->p, BM_REG_ISR, BM_PIRQ_RCRI); + is &= ~BM_PIRQ_RCRI; + } + + /* There should be no status register bits left undefined */ + DPAA_ASSERT(!is); + return ret; +} + +int bman_p_irqsource_add(struct bman_portal *p, u32 bits) +{ + unsigned long irqflags; + + local_irq_save(irqflags); + set_bits(bits & BM_PIRQ_VISIBLE, &p->irq_sources); + bm_out(&p->p, BM_REG_IER, p->irq_sources); + local_irq_restore(irqflags); + return 0; +} + +static int bm_shutdown_pool(u32 bpid) +{ + struct bm_mc_command *bm_cmd; + union bm_mc_result *bm_res; + + while (1) { + struct bman_portal *p = get_affine_portal(); + /* Acquire buffers until empty */ + bm_cmd = bm_mc_start(&p->p); + bm_cmd->bpid = bpid; + bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | 1); + if (!bm_mc_result_timeout(&p->p, &bm_res)) { + put_affine_portal(); + pr_crit("BMan Acquire Command timedout\n"); + return -ETIMEDOUT; + } + if (!(bm_res->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT)) { + put_affine_portal(); + /* Pool is empty */ + return 0; + } + put_affine_portal(); + } + + return 0; +} + +struct gen_pool *bm_bpalloc; + +static int bm_alloc_bpid_range(u32 *result, u32 count) +{ + unsigned long addr; + + addr = gen_pool_alloc(bm_bpalloc, count); + if (!addr) + return -ENOMEM; + + *result = addr & ~DPAA_GENALLOC_OFF; + + return 0; +} + +static int bm_release_bpid(u32 bpid) +{ + int ret; + + ret = bm_shutdown_pool(bpid); + if (ret) { + pr_debug("BPID %d leaked\n", bpid); + return ret; + } + + gen_pool_free(bm_bpalloc, bpid | DPAA_GENALLOC_OFF, 1); + return 0; +} + +struct bman_pool *bman_new_pool(void) +{ + struct bman_pool *pool = NULL; + u32 bpid; + + if (bm_alloc_bpid_range(&bpid, 1)) + return NULL; + + pool = kmalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + goto err; + + pool->bpid = bpid; + + return pool; +err: + bm_release_bpid(bpid); + kfree(pool); + return NULL; +} +EXPORT_SYMBOL(bman_new_pool); + +void bman_free_pool(struct bman_pool *pool) +{ + bm_release_bpid(pool->bpid); + + kfree(pool); +} +EXPORT_SYMBOL(bman_free_pool); + +int bman_get_bpid(const struct bman_pool *pool) +{ + return pool->bpid; +} +EXPORT_SYMBOL(bman_get_bpid); + +static void update_rcr_ci(struct bman_portal *p, int avail) +{ + if (avail) + bm_rcr_cce_prefetch(&p->p); + else + bm_rcr_cce_update(&p->p); +} + +int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num) +{ + struct bman_portal *p; + struct bm_rcr_entry *r; + unsigned long irqflags; + int avail, timeout = 1000; /* 1ms */ + int i = num - 1; + + DPAA_ASSERT(num > 0 && num <= 8); + + do { + p = get_affine_portal(); + local_irq_save(irqflags); + avail = bm_rcr_get_avail(&p->p); + if (avail < 2) + update_rcr_ci(p, avail); + r = bm_rcr_start(&p->p); + local_irq_restore(irqflags); + put_affine_portal(); + if (likely(r)) + break; + + udelay(1); + } while (--timeout); + + if (unlikely(!timeout)) + return -ETIMEDOUT; + + p = get_affine_portal(); + local_irq_save(irqflags); + /* + * we can copy all but the first entry, as this can trigger badness + * with the valid-bit + */ + bm_buffer_set64(r->bufs, bm_buffer_get64(bufs)); + bm_buffer_set_bpid(r->bufs, pool->bpid); + if (i) + memcpy(&r->bufs[1], &bufs[1], i * sizeof(bufs[0])); + + bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE | + (num & BM_RCR_VERB_BUFCOUNT_MASK)); + + local_irq_restore(irqflags); + put_affine_portal(); + return 0; +} +EXPORT_SYMBOL(bman_release); + +int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num) +{ + struct bman_portal *p = get_affine_portal(); + struct bm_mc_command *mcc; + union bm_mc_result *mcr; + int ret; + + DPAA_ASSERT(num > 0 && num <= 8); + + mcc = bm_mc_start(&p->p); + mcc->bpid = pool->bpid; + bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | + (num & BM_MCC_VERB_ACQUIRE_BUFCOUNT)); + if (!bm_mc_result_timeout(&p->p, &mcr)) { + put_affine_portal(); + pr_crit("BMan Acquire Timeout\n"); + return -ETIMEDOUT; + } + ret = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT; + if (bufs) + memcpy(&bufs[0], &mcr->bufs[0], num * sizeof(bufs[0])); + + put_affine_portal(); + if (ret != num) + ret = -ENOMEM; + return ret; +} +EXPORT_SYMBOL(bman_acquire); + +const struct bm_portal_config * +bman_get_bm_portal_config(const struct bman_portal *portal) +{ + return portal->config; +} diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c b/drivers/soc/fsl/qbman/bman_ccsr.c new file mode 100644 index 0000000000000..9deb0524543f0 --- /dev/null +++ b/drivers/soc/fsl/qbman/bman_ccsr.c @@ -0,0 +1,263 @@ +/* Copyright (c) 2009 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_priv.h" + +u16 bman_ip_rev; +EXPORT_SYMBOL(bman_ip_rev); + +/* Register offsets */ +#define REG_FBPR_FPC 0x0800 +#define REG_ECSR 0x0a00 +#define REG_ECIR 0x0a04 +#define REG_EADR 0x0a08 +#define REG_EDATA(n) (0x0a10 + ((n) * 0x04)) +#define REG_SBEC(n) (0x0a80 + ((n) * 0x04)) +#define REG_IP_REV_1 0x0bf8 +#define REG_IP_REV_2 0x0bfc +#define REG_FBPR_BARE 0x0c00 +#define REG_FBPR_BAR 0x0c04 +#define REG_FBPR_AR 0x0c10 +#define REG_SRCIDR 0x0d04 +#define REG_LIODNR 0x0d08 +#define REG_ERR_ISR 0x0e00 +#define REG_ERR_IER 0x0e04 +#define REG_ERR_ISDR 0x0e08 + +/* Used by all error interrupt registers except 'inhibit' */ +#define BM_EIRQ_IVCI 0x00000010 /* Invalid Command Verb */ +#define BM_EIRQ_FLWI 0x00000008 /* FBPR Low Watermark */ +#define BM_EIRQ_MBEI 0x00000004 /* Multi-bit ECC Error */ +#define BM_EIRQ_SBEI 0x00000002 /* Single-bit ECC Error */ +#define BM_EIRQ_BSCN 0x00000001 /* pool State Change Notification */ + +struct bman_hwerr_txt { + u32 mask; + const char *txt; +}; + +static const struct bman_hwerr_txt bman_hwerr_txts[] = { + { BM_EIRQ_IVCI, "Invalid Command Verb" }, + { BM_EIRQ_FLWI, "FBPR Low Watermark" }, + { BM_EIRQ_MBEI, "Multi-bit ECC Error" }, + { BM_EIRQ_SBEI, "Single-bit ECC Error" }, + { BM_EIRQ_BSCN, "Pool State Change Notification" }, +}; + +/* Only trigger low water mark interrupt once only */ +#define BMAN_ERRS_TO_DISABLE BM_EIRQ_FLWI + +/* Pointer to the start of the BMan's CCSR space */ +static u32 __iomem *bm_ccsr_start; + +static inline u32 bm_ccsr_in(u32 offset) +{ + return ioread32be(bm_ccsr_start + offset/4); +} +static inline void bm_ccsr_out(u32 offset, u32 val) +{ + iowrite32be(val, bm_ccsr_start + offset/4); +} + +static void bm_get_version(u16 *id, u8 *major, u8 *minor) +{ + u32 v = bm_ccsr_in(REG_IP_REV_1); + *id = (v >> 16); + *major = (v >> 8) & 0xff; + *minor = v & 0xff; +} + +/* signal transactions for FBPRs with higher priority */ +#define FBPR_AR_RPRIO_HI BIT(30) + +static void bm_set_memory(u64 ba, u32 size) +{ + u32 exp = ilog2(size); + /* choke if size isn't within range */ + DPAA_ASSERT(size >= 4096 && size <= 1024*1024*1024 && + is_power_of_2(size)); + /* choke if '[e]ba' has lower-alignment than 'size' */ + DPAA_ASSERT(!(ba & (size - 1))); + bm_ccsr_out(REG_FBPR_BARE, upper_32_bits(ba)); + bm_ccsr_out(REG_FBPR_BAR, lower_32_bits(ba)); + bm_ccsr_out(REG_FBPR_AR, exp - 1); +} + +/* + * Location and size of BMan private memory + * + * Ideally we would use the DMA API to turn rmem->base into a DMA address + * (especially if iommu translations ever get involved). Unfortunately, the + * DMA API currently does not allow mapping anything that is not backed with + * a struct page. + */ +static dma_addr_t fbpr_a; +static size_t fbpr_sz; + +static int bman_fbpr(struct reserved_mem *rmem) +{ + fbpr_a = rmem->base; + fbpr_sz = rmem->size; + + WARN_ON(!(fbpr_a && fbpr_sz)); + + return 0; +} +RESERVEDMEM_OF_DECLARE(bman_fbpr, "fsl,bman-fbpr", bman_fbpr); + +static irqreturn_t bman_isr(int irq, void *ptr) +{ + u32 isr_val, ier_val, ecsr_val, isr_mask, i; + struct device *dev = ptr; + + ier_val = bm_ccsr_in(REG_ERR_IER); + isr_val = bm_ccsr_in(REG_ERR_ISR); + ecsr_val = bm_ccsr_in(REG_ECSR); + isr_mask = isr_val & ier_val; + + if (!isr_mask) + return IRQ_NONE; + + for (i = 0; i < ARRAY_SIZE(bman_hwerr_txts); i++) { + if (bman_hwerr_txts[i].mask & isr_mask) { + dev_err_ratelimited(dev, "ErrInt: %s\n", + bman_hwerr_txts[i].txt); + if (bman_hwerr_txts[i].mask & ecsr_val) { + /* Re-arm error capture registers */ + bm_ccsr_out(REG_ECSR, ecsr_val); + } + if (bman_hwerr_txts[i].mask & BMAN_ERRS_TO_DISABLE) { + dev_dbg(dev, "Disabling error 0x%x\n", + bman_hwerr_txts[i].mask); + ier_val &= ~bman_hwerr_txts[i].mask; + bm_ccsr_out(REG_ERR_IER, ier_val); + } + } + } + bm_ccsr_out(REG_ERR_ISR, isr_val); + + return IRQ_HANDLED; +} + +static int fsl_bman_probe(struct platform_device *pdev) +{ + int ret, err_irq; + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct resource *res; + u16 id, bm_pool_cnt; + u8 major, minor; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "Can't get %s property 'IORESOURCE_MEM'\n", + node->full_name); + return -ENXIO; + } + bm_ccsr_start = devm_ioremap(dev, res->start, + res->end - res->start + 1); + if (!bm_ccsr_start) + return -ENXIO; + + bm_get_version(&id, &major, &minor); + if (major == 1 && minor == 0) { + bman_ip_rev = BMAN_REV10; + bm_pool_cnt = BM_POOL_MAX; + } else if (major == 2 && minor == 0) { + bman_ip_rev = BMAN_REV20; + bm_pool_cnt = 8; + } else if (major == 2 && minor == 1) { + bman_ip_rev = BMAN_REV21; + bm_pool_cnt = BM_POOL_MAX; + } else { + dev_err(dev, "Unknown Bman version:%04x,%02x,%02x\n", + id, major, minor); + return -ENODEV; + } + + bm_set_memory(fbpr_a, fbpr_sz); + + err_irq = platform_get_irq(pdev, 0); + if (err_irq <= 0) { + dev_info(dev, "Can't get %s IRQ\n", node->full_name); + return -ENODEV; + } + ret = devm_request_irq(dev, err_irq, bman_isr, IRQF_SHARED, "bman-err", + dev); + if (ret) { + dev_err(dev, "devm_request_irq() failed %d for '%s'\n", + ret, node->full_name); + return ret; + } + /* Disable Buffer Pool State Change */ + bm_ccsr_out(REG_ERR_ISDR, BM_EIRQ_BSCN); + /* + * Write-to-clear any stale bits, (eg. starvation being asserted prior + * to resource allocation during driver init). + */ + bm_ccsr_out(REG_ERR_ISR, 0xffffffff); + /* Enable Error Interrupts */ + bm_ccsr_out(REG_ERR_IER, 0xffffffff); + + bm_bpalloc = devm_gen_pool_create(dev, 0, -1, "bman-bpalloc"); + if (IS_ERR(bm_bpalloc)) { + ret = PTR_ERR(bm_bpalloc); + dev_err(dev, "bman-bpalloc pool init failed (%d)\n", ret); + return ret; + } + + /* seed BMan resource pool */ + ret = gen_pool_add(bm_bpalloc, DPAA_GENALLOC_OFF, bm_pool_cnt, -1); + if (ret) { + dev_err(dev, "Failed to seed BPID range [%d..%d] (%d)\n", + 0, bm_pool_cnt - 1, ret); + return ret; + } + + return 0; +}; + +static const struct of_device_id fsl_bman_ids[] = { + { + .compatible = "fsl,bman", + }, + {} +}; + +static struct platform_driver fsl_bman_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = fsl_bman_ids, + .suppress_bind_attrs = true, + }, + .probe = fsl_bman_probe, +}; + +builtin_platform_driver(fsl_bman_driver); diff --git a/drivers/soc/fsl/qbman/bman_portal.c b/drivers/soc/fsl/qbman/bman_portal.c new file mode 100644 index 0000000000000..6579cc18811ac --- /dev/null +++ b/drivers/soc/fsl/qbman/bman_portal.c @@ -0,0 +1,219 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_priv.h" + +static struct bman_portal *affine_bportals[NR_CPUS]; +static struct cpumask portal_cpus; +/* protect bman global registers and global data shared among portals */ +static DEFINE_SPINLOCK(bman_lock); + +static struct bman_portal *init_pcfg(struct bm_portal_config *pcfg) +{ + struct bman_portal *p = bman_create_affine_portal(pcfg); + + if (!p) { + dev_crit(pcfg->dev, "%s: Portal failure on cpu %d\n", + __func__, pcfg->cpu); + return NULL; + } + + bman_p_irqsource_add(p, BM_PIRQ_RCRI); + affine_bportals[pcfg->cpu] = p; + + dev_info(pcfg->dev, "Portal initialised, cpu %d\n", pcfg->cpu); + + return p; +} + +static void bman_offline_cpu(unsigned int cpu) +{ + struct bman_portal *p = affine_bportals[cpu]; + const struct bm_portal_config *pcfg; + + if (!p) + return; + + pcfg = bman_get_bm_portal_config(p); + if (!pcfg) + return; + + irq_set_affinity(pcfg->irq, cpumask_of(0)); +} + +static void bman_online_cpu(unsigned int cpu) +{ + struct bman_portal *p = affine_bportals[cpu]; + const struct bm_portal_config *pcfg; + + if (!p) + return; + + pcfg = bman_get_bm_portal_config(p); + if (!pcfg) + return; + + irq_set_affinity(pcfg->irq, cpumask_of(cpu)); +} + +static int bman_hotplug_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + bman_online_cpu(cpu); + break; + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + bman_offline_cpu(cpu); + } + + return NOTIFY_OK; +} + +static struct notifier_block bman_hotplug_cpu_notifier = { + .notifier_call = bman_hotplug_cpu_callback, +}; + +static int bman_portal_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct bm_portal_config *pcfg; + struct resource *addr_phys[2]; + void __iomem *va; + int irq, cpu; + + pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL); + if (!pcfg) + return -ENOMEM; + + pcfg->dev = dev; + + addr_phys[0] = platform_get_resource(pdev, IORESOURCE_MEM, + DPAA_PORTAL_CE); + if (!addr_phys[0]) { + dev_err(dev, "Can't get %s property 'reg::CE'\n", + node->full_name); + return -ENXIO; + } + + addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM, + DPAA_PORTAL_CI); + if (!addr_phys[1]) { + dev_err(dev, "Can't get %s property 'reg::CI'\n", + node->full_name); + return -ENXIO; + } + + pcfg->cpu = -1; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(dev, "Can't get %s IRQ'\n", node->full_name); + return -ENXIO; + } + pcfg->irq = irq; + + va = ioremap_prot(addr_phys[0]->start, resource_size(addr_phys[0]), 0); + if (!va) + goto err_ioremap1; + + pcfg->addr_virt[DPAA_PORTAL_CE] = va; + + va = ioremap_prot(addr_phys[1]->start, resource_size(addr_phys[1]), + _PAGE_GUARDED | _PAGE_NO_CACHE); + if (!va) + goto err_ioremap2; + + pcfg->addr_virt[DPAA_PORTAL_CI] = va; + + spin_lock(&bman_lock); + cpu = cpumask_next_zero(-1, &portal_cpus); + if (cpu >= nr_cpu_ids) { + /* unassigned portal, skip init */ + spin_unlock(&bman_lock); + return 0; + } + + cpumask_set_cpu(cpu, &portal_cpus); + spin_unlock(&bman_lock); + pcfg->cpu = cpu; + + if (!init_pcfg(pcfg)) + goto err_ioremap2; + + /* clear irq affinity if assigned cpu is offline */ + if (!cpu_online(cpu)) + bman_offline_cpu(cpu); + + return 0; + +err_ioremap2: + iounmap(pcfg->addr_virt[DPAA_PORTAL_CE]); +err_ioremap1: + dev_err(dev, "ioremap failed\n"); + return -ENXIO; +} + +static const struct of_device_id bman_portal_ids[] = { + { + .compatible = "fsl,bman-portal", + }, + {} +}; +MODULE_DEVICE_TABLE(of, bman_portal_ids); + +static struct platform_driver bman_portal_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = bman_portal_ids, + }, + .probe = bman_portal_probe, +}; + +static int __init bman_portal_driver_register(struct platform_driver *drv) +{ + int ret; + + ret = platform_driver_register(drv); + if (ret < 0) + return ret; + + register_hotcpu_notifier(&bman_hotplug_cpu_notifier); + + return 0; +} + +module_driver(bman_portal_driver, + bman_portal_driver_register, platform_driver_unregister); diff --git a/drivers/soc/fsl/qbman/bman_priv.h b/drivers/soc/fsl/qbman/bman_priv.h new file mode 100644 index 0000000000000..f6896a2f6d90e --- /dev/null +++ b/drivers/soc/fsl/qbman/bman_priv.h @@ -0,0 +1,80 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "dpaa_sys.h" + +#include + +/* Portal processing (interrupt) sources */ +#define BM_PIRQ_RCRI 0x00000002 /* RCR Ring (below threshold) */ + +/* Revision info (for errata and feature handling) */ +#define BMAN_REV10 0x0100 +#define BMAN_REV20 0x0200 +#define BMAN_REV21 0x0201 +extern u16 bman_ip_rev; /* 0 if uninitialised, otherwise BMAN_REVx */ + +extern struct gen_pool *bm_bpalloc; + +struct bm_portal_config { + /* + * Corenet portal addresses; + * [0]==cache-enabled, [1]==cache-inhibited. + */ + void __iomem *addr_virt[2]; + /* Allow these to be joined in lists */ + struct list_head list; + struct device *dev; + /* User-visible portal configuration settings */ + /* portal is affined to this cpu */ + int cpu; + /* portal interrupt line */ + int irq; +}; + +struct bman_portal *bman_create_affine_portal( + const struct bm_portal_config *config); +/* + * The below bman_p_***() variant might be called in a situation that the cpu + * which the portal affine to is not online yet. + * @bman_portal specifies which portal the API will use. + */ +int bman_p_irqsource_add(struct bman_portal *p, u32 bits); + +/* + * Used by all portal interrupt registers except 'inhibit' + * This mask contains all the "irqsource" bits visible to API users + */ +#define BM_PIRQ_VISIBLE BM_PIRQ_RCRI + +const struct bm_portal_config * +bman_get_bm_portal_config(const struct bman_portal *portal); diff --git a/drivers/soc/fsl/qbman/dpaa_sys.h b/drivers/soc/fsl/qbman/dpaa_sys.h new file mode 100644 index 0000000000000..b63fd72295c6d --- /dev/null +++ b/drivers/soc/fsl/qbman/dpaa_sys.h @@ -0,0 +1,103 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DPAA_SYS_H +#define __DPAA_SYS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* For 2-element tables related to cache-inhibited and cache-enabled mappings */ +#define DPAA_PORTAL_CE 0 +#define DPAA_PORTAL_CI 1 + +#if (L1_CACHE_BYTES != 32) && (L1_CACHE_BYTES != 64) +#error "Unsupported Cacheline Size" +#endif + +static inline void dpaa_flush(void *p) +{ +#ifdef CONFIG_PPC + flush_dcache_range((unsigned long)p, (unsigned long)p+64); +#elif defined(CONFIG_ARM32) + __cpuc_flush_dcache_area(p, 64); +#elif defined(CONFIG_ARM64) + __flush_dcache_area(p, 64); +#endif +} + +#define dpaa_invalidate(p) dpaa_flush(p) + +#define dpaa_zero(p) memset(p, 0, 64) + +static inline void dpaa_touch_ro(void *p) +{ +#if (L1_CACHE_BYTES == 32) + prefetch(p+32); +#endif + prefetch(p); +} + +/* Commonly used combo */ +static inline void dpaa_invalidate_touch_ro(void *p) +{ + dpaa_invalidate(p); + dpaa_touch_ro(p); +} + + +#ifdef CONFIG_FSL_DPAA_CHECKING +#define DPAA_ASSERT(x) WARN_ON(!(x)) +#else +#define DPAA_ASSERT(x) +#endif + +/* cyclic helper for rings */ +static inline u8 dpaa_cyc_diff(u8 ringsize, u8 first, u8 last) +{ + /* 'first' is included, 'last' is excluded */ + if (first <= last) + return last - first; + return ringsize + last - first; +} + +/* Offset applied to genalloc pools due to zero being an error return */ +#define DPAA_GENALLOC_OFF 0x80000000 + +#endif /* __DPAA_SYS_H */ diff --git a/include/soc/fsl/bman.h b/include/soc/fsl/bman.h new file mode 100644 index 0000000000000..eaaf56df4086e --- /dev/null +++ b/include/soc/fsl/bman.h @@ -0,0 +1,129 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FSL_BMAN_H +#define __FSL_BMAN_H + +/* wrapper for 48-bit buffers */ +struct bm_buffer { + union { + struct { + __be16 bpid; /* hi 8-bits reserved */ + __be16 hi; /* High 16-bits of 48-bit address */ + __be32 lo; /* Low 32-bits of 48-bit address */ + }; + __be64 data; + }; +} __aligned(8); +/* + * Restore the 48 bit address previously stored in BMan + * hardware pools as a dma_addr_t + */ +static inline dma_addr_t bm_buf_addr(const struct bm_buffer *buf) +{ + return be64_to_cpu(buf->data) & 0xffffffffffffLLU; +} + +static inline u64 bm_buffer_get64(const struct bm_buffer *buf) +{ + return be64_to_cpu(buf->data) & 0xffffffffffffLLU; +} + +static inline void bm_buffer_set64(struct bm_buffer *buf, u64 addr) +{ + buf->hi = cpu_to_be16(upper_32_bits(addr)); + buf->lo = cpu_to_be32(lower_32_bits(addr)); +} + +static inline u8 bm_buffer_get_bpid(const struct bm_buffer *buf) +{ + return be16_to_cpu(buf->bpid) & 0xff; +} + +static inline void bm_buffer_set_bpid(struct bm_buffer *buf, int bpid) +{ + buf->bpid = cpu_to_be16(bpid & 0xff); +} + +/* Managed portal, high-level i/face */ + +/* Portal and Buffer Pools */ +struct bman_portal; +struct bman_pool; + +#define BM_POOL_MAX 64 /* max # of buffer pools */ + +/** + * bman_new_pool - Allocates a Buffer Pool object + * + * Creates a pool object, and returns a reference to it or NULL on error. + */ +struct bman_pool *bman_new_pool(void); + +/** + * bman_free_pool - Deallocates a Buffer Pool object + * @pool: the pool object to release + */ +void bman_free_pool(struct bman_pool *pool); + +/** + * bman_get_bpid - Returns a pool object's BPID. + * @pool: the pool object + * + * The returned value is the index of the encapsulated buffer pool, + * in the range of [0, @BM_POOL_MAX-1]. + */ +int bman_get_bpid(const struct bman_pool *pool); + +/** + * bman_release - Release buffer(s) to the buffer pool + * @pool: the buffer pool object to release to + * @bufs: an array of buffers to release + * @num: the number of buffers in @bufs (1-8) + * + * Adds the given buffers to RCR entries. If the RCR ring is unresponsive, + * the function will return -ETIMEDOUT. Otherwise, it returns zero. + */ +int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num); + +/** + * bman_acquire - Acquire buffer(s) from a buffer pool + * @pool: the buffer pool object to acquire from + * @bufs: array for storing the acquired buffers + * @num: the number of buffers desired (@bufs is at least this big) + * + * Issues an "Acquire" command via the portal's management command interface. + * The return value will be the number of buffers obtained from the pool, or a + * negative error code if a h/w error or pool starvation was encountered. In + * the latter case, the content of @bufs is undefined. + */ +int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num); + +#endif /* __FSL_BMAN_H */ -- GitLab From c535e923bb97a4b361e89a6383693482057f8b0c Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 22 Sep 2016 18:04:09 +0300 Subject: [PATCH 0129/1167] soc/fsl: Introduce DPAA 1.x QMan device driver This driver enables the Freescale DPAA 1.x Queue Manager block. QMan is a hardware accelerator that manages frame queues. It allows CPUs and other accelerators connected to the SoC datapath to enqueue and dequeue ethernet frames, thus providing the infrastructure for data exchange among CPUs and datapath accelerators. Signed-off-by: Roy Pledge Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/Makefile | 5 +- drivers/soc/fsl/qbman/qman.c | 2881 +++++++++++++++++++++++++++ drivers/soc/fsl/qbman/qman_ccsr.c | 808 ++++++++ drivers/soc/fsl/qbman/qman_portal.c | 355 ++++ drivers/soc/fsl/qbman/qman_priv.h | 371 ++++ include/soc/fsl/qman.h | 1074 ++++++++++ 6 files changed, 5492 insertions(+), 2 deletions(-) create mode 100644 drivers/soc/fsl/qbman/qman.c create mode 100644 drivers/soc/fsl/qbman/qman_ccsr.c create mode 100644 drivers/soc/fsl/qbman/qman_portal.c create mode 100644 drivers/soc/fsl/qbman/qman_priv.h create mode 100644 include/soc/fsl/qman.h diff --git a/drivers/soc/fsl/qbman/Makefile b/drivers/soc/fsl/qbman/Makefile index 855c3ac0f89ee..6e0ee30b28344 100644 --- a/drivers/soc/fsl/qbman/Makefile +++ b/drivers/soc/fsl/qbman/Makefile @@ -1,2 +1,3 @@ -obj-$(CONFIG_FSL_DPAA) += bman_ccsr.o bman_portal.o \ - bman.o +obj-$(CONFIG_FSL_DPAA) += bman_ccsr.o qman_ccsr.o \ + bman_portal.o qman_portal.o \ + bman.o qman.o diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c new file mode 100644 index 0000000000000..119054bc922bf --- /dev/null +++ b/drivers/soc/fsl/qbman/qman.c @@ -0,0 +1,2881 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_priv.h" + +#define DQRR_MAXFILL 15 +#define EQCR_ITHRESH 4 /* if EQCR congests, interrupt threshold */ +#define IRQNAME "QMan portal %d" +#define MAX_IRQNAME 16 /* big enough for "QMan portal %d" */ +#define QMAN_POLL_LIMIT 32 +#define QMAN_PIRQ_DQRR_ITHRESH 12 +#define QMAN_PIRQ_MR_ITHRESH 4 +#define QMAN_PIRQ_IPERIOD 100 + +/* Portal register assists */ + +/* Cache-inhibited register offsets */ +#define QM_REG_EQCR_PI_CINH 0x0000 +#define QM_REG_EQCR_CI_CINH 0x0004 +#define QM_REG_EQCR_ITR 0x0008 +#define QM_REG_DQRR_PI_CINH 0x0040 +#define QM_REG_DQRR_CI_CINH 0x0044 +#define QM_REG_DQRR_ITR 0x0048 +#define QM_REG_DQRR_DCAP 0x0050 +#define QM_REG_DQRR_SDQCR 0x0054 +#define QM_REG_DQRR_VDQCR 0x0058 +#define QM_REG_DQRR_PDQCR 0x005c +#define QM_REG_MR_PI_CINH 0x0080 +#define QM_REG_MR_CI_CINH 0x0084 +#define QM_REG_MR_ITR 0x0088 +#define QM_REG_CFG 0x0100 +#define QM_REG_ISR 0x0e00 +#define QM_REG_IER 0x0e04 +#define QM_REG_ISDR 0x0e08 +#define QM_REG_IIR 0x0e0c +#define QM_REG_ITPR 0x0e14 + +/* Cache-enabled register offsets */ +#define QM_CL_EQCR 0x0000 +#define QM_CL_DQRR 0x1000 +#define QM_CL_MR 0x2000 +#define QM_CL_EQCR_PI_CENA 0x3000 +#define QM_CL_EQCR_CI_CENA 0x3100 +#define QM_CL_DQRR_PI_CENA 0x3200 +#define QM_CL_DQRR_CI_CENA 0x3300 +#define QM_CL_MR_PI_CENA 0x3400 +#define QM_CL_MR_CI_CENA 0x3500 +#define QM_CL_CR 0x3800 +#define QM_CL_RR0 0x3900 +#define QM_CL_RR1 0x3940 + +/* + * BTW, the drivers (and h/w programming model) already obtain the required + * synchronisation for portal accesses and data-dependencies. Use of barrier()s + * or other order-preserving primitives simply degrade performance. Hence the + * use of the __raw_*() interfaces, which simply ensure that the compiler treats + * the portal registers as volatile + */ + +/* Cache-enabled ring access */ +#define qm_cl(base, idx) ((void *)base + ((idx) << 6)) + +/* + * Portal modes. + * Enum types; + * pmode == production mode + * cmode == consumption mode, + * dmode == h/w dequeue mode. + * Enum values use 3 letter codes. First letter matches the portal mode, + * remaining two letters indicate; + * ci == cache-inhibited portal register + * ce == cache-enabled portal register + * vb == in-band valid-bit (cache-enabled) + * dc == DCA (Discrete Consumption Acknowledgment), DQRR-only + * As for "enum qm_dqrr_dmode", it should be self-explanatory. + */ +enum qm_eqcr_pmode { /* matches QCSP_CFG::EPM */ + qm_eqcr_pci = 0, /* PI index, cache-inhibited */ + qm_eqcr_pce = 1, /* PI index, cache-enabled */ + qm_eqcr_pvb = 2 /* valid-bit */ +}; +enum qm_dqrr_dmode { /* matches QCSP_CFG::DP */ + qm_dqrr_dpush = 0, /* SDQCR + VDQCR */ + qm_dqrr_dpull = 1 /* PDQCR */ +}; +enum qm_dqrr_pmode { /* s/w-only */ + qm_dqrr_pci, /* reads DQRR_PI_CINH */ + qm_dqrr_pce, /* reads DQRR_PI_CENA */ + qm_dqrr_pvb /* reads valid-bit */ +}; +enum qm_dqrr_cmode { /* matches QCSP_CFG::DCM */ + qm_dqrr_cci = 0, /* CI index, cache-inhibited */ + qm_dqrr_cce = 1, /* CI index, cache-enabled */ + qm_dqrr_cdc = 2 /* Discrete Consumption Acknowledgment */ +}; +enum qm_mr_pmode { /* s/w-only */ + qm_mr_pci, /* reads MR_PI_CINH */ + qm_mr_pce, /* reads MR_PI_CENA */ + qm_mr_pvb /* reads valid-bit */ +}; +enum qm_mr_cmode { /* matches QCSP_CFG::MM */ + qm_mr_cci = 0, /* CI index, cache-inhibited */ + qm_mr_cce = 1 /* CI index, cache-enabled */ +}; + +/* --- Portal structures --- */ + +#define QM_EQCR_SIZE 8 +#define QM_DQRR_SIZE 16 +#define QM_MR_SIZE 8 + +/* "Enqueue Command" */ +struct qm_eqcr_entry { + u8 _ncw_verb; /* writes to this are non-coherent */ + u8 dca; + u16 seqnum; + u32 orp; /* 24-bit */ + u32 fqid; /* 24-bit */ + u32 tag; + struct qm_fd fd; + u8 __reserved3[32]; +} __packed; +#define QM_EQCR_VERB_VBIT 0x80 +#define QM_EQCR_VERB_CMD_MASK 0x61 /* but only one value; */ +#define QM_EQCR_VERB_CMD_ENQUEUE 0x01 +#define QM_EQCR_SEQNUM_NESN 0x8000 /* Advance NESN */ +#define QM_EQCR_SEQNUM_NLIS 0x4000 /* More fragments to come */ +#define QM_EQCR_SEQNUM_SEQMASK 0x3fff /* sequence number goes here */ + +struct qm_eqcr { + struct qm_eqcr_entry *ring, *cursor; + u8 ci, available, ithresh, vbit; +#ifdef CONFIG_FSL_DPAA_CHECKING + u32 busy; + enum qm_eqcr_pmode pmode; +#endif +}; + +struct qm_dqrr { + const struct qm_dqrr_entry *ring, *cursor; + u8 pi, ci, fill, ithresh, vbit; +#ifdef CONFIG_FSL_DPAA_CHECKING + enum qm_dqrr_dmode dmode; + enum qm_dqrr_pmode pmode; + enum qm_dqrr_cmode cmode; +#endif +}; + +struct qm_mr { + union qm_mr_entry *ring, *cursor; + u8 pi, ci, fill, ithresh, vbit; +#ifdef CONFIG_FSL_DPAA_CHECKING + enum qm_mr_pmode pmode; + enum qm_mr_cmode cmode; +#endif +}; + +/* MC (Management Command) command */ +/* "Query FQ" */ +struct qm_mcc_queryfq { + u8 _ncw_verb; + u8 __reserved1[3]; + u32 fqid; /* 24-bit */ + u8 __reserved2[56]; +} __packed; +/* "Alter FQ State Commands " */ +struct qm_mcc_alterfq { + u8 _ncw_verb; + u8 __reserved1[3]; + u32 fqid; /* 24-bit */ + u8 __reserved2; + u8 count; /* number of consecutive FQID */ + u8 __reserved3[10]; + u32 context_b; /* frame queue context b */ + u8 __reserved4[40]; +} __packed; + +/* "Query CGR" */ +struct qm_mcc_querycgr { + u8 _ncw_verb; + u8 __reserved1[30]; + u8 cgid; + u8 __reserved2[32]; +}; + +struct qm_mcc_querywq { + u8 _ncw_verb; + u8 __reserved; + /* select channel if verb != QUERYWQ_DEDICATED */ + u16 channel_wq; /* ignores wq (3 lsbits): _res[0-2] */ + u8 __reserved2[60]; +} __packed; + +#define QM_MCC_VERB_VBIT 0x80 +#define QM_MCC_VERB_MASK 0x7f /* where the verb contains; */ +#define QM_MCC_VERB_INITFQ_PARKED 0x40 +#define QM_MCC_VERB_INITFQ_SCHED 0x41 +#define QM_MCC_VERB_QUERYFQ 0x44 +#define QM_MCC_VERB_QUERYFQ_NP 0x45 /* "non-programmable" fields */ +#define QM_MCC_VERB_QUERYWQ 0x46 +#define QM_MCC_VERB_QUERYWQ_DEDICATED 0x47 +#define QM_MCC_VERB_ALTER_SCHED 0x48 /* Schedule FQ */ +#define QM_MCC_VERB_ALTER_FE 0x49 /* Force Eligible FQ */ +#define QM_MCC_VERB_ALTER_RETIRE 0x4a /* Retire FQ */ +#define QM_MCC_VERB_ALTER_OOS 0x4b /* Take FQ out of service */ +#define QM_MCC_VERB_ALTER_FQXON 0x4d /* FQ XON */ +#define QM_MCC_VERB_ALTER_FQXOFF 0x4e /* FQ XOFF */ +#define QM_MCC_VERB_INITCGR 0x50 +#define QM_MCC_VERB_MODIFYCGR 0x51 +#define QM_MCC_VERB_CGRTESTWRITE 0x52 +#define QM_MCC_VERB_QUERYCGR 0x58 +#define QM_MCC_VERB_QUERYCONGESTION 0x59 +union qm_mc_command { + struct { + u8 _ncw_verb; /* writes to this are non-coherent */ + u8 __reserved[63]; + }; + struct qm_mcc_initfq initfq; + struct qm_mcc_queryfq queryfq; + struct qm_mcc_alterfq alterfq; + struct qm_mcc_initcgr initcgr; + struct qm_mcc_querycgr querycgr; + struct qm_mcc_querywq querywq; + struct qm_mcc_queryfq_np queryfq_np; +}; + +/* MC (Management Command) result */ +/* "Query FQ" */ +struct qm_mcr_queryfq { + u8 verb; + u8 result; + u8 __reserved1[8]; + struct qm_fqd fqd; /* the FQD fields are here */ + u8 __reserved2[30]; +} __packed; + +/* "Alter FQ State Commands" */ +struct qm_mcr_alterfq { + u8 verb; + u8 result; + u8 fqs; /* Frame Queue Status */ + u8 __reserved1[61]; +}; +#define QM_MCR_VERB_RRID 0x80 +#define QM_MCR_VERB_MASK QM_MCC_VERB_MASK +#define QM_MCR_VERB_INITFQ_PARKED QM_MCC_VERB_INITFQ_PARKED +#define QM_MCR_VERB_INITFQ_SCHED QM_MCC_VERB_INITFQ_SCHED +#define QM_MCR_VERB_QUERYFQ QM_MCC_VERB_QUERYFQ +#define QM_MCR_VERB_QUERYFQ_NP QM_MCC_VERB_QUERYFQ_NP +#define QM_MCR_VERB_QUERYWQ QM_MCC_VERB_QUERYWQ +#define QM_MCR_VERB_QUERYWQ_DEDICATED QM_MCC_VERB_QUERYWQ_DEDICATED +#define QM_MCR_VERB_ALTER_SCHED QM_MCC_VERB_ALTER_SCHED +#define QM_MCR_VERB_ALTER_FE QM_MCC_VERB_ALTER_FE +#define QM_MCR_VERB_ALTER_RETIRE QM_MCC_VERB_ALTER_RETIRE +#define QM_MCR_VERB_ALTER_OOS QM_MCC_VERB_ALTER_OOS +#define QM_MCR_RESULT_NULL 0x00 +#define QM_MCR_RESULT_OK 0xf0 +#define QM_MCR_RESULT_ERR_FQID 0xf1 +#define QM_MCR_RESULT_ERR_FQSTATE 0xf2 +#define QM_MCR_RESULT_ERR_NOTEMPTY 0xf3 /* OOS fails if FQ is !empty */ +#define QM_MCR_RESULT_ERR_BADCHANNEL 0xf4 +#define QM_MCR_RESULT_PENDING 0xf8 +#define QM_MCR_RESULT_ERR_BADCOMMAND 0xff +#define QM_MCR_FQS_ORLPRESENT 0x02 /* ORL fragments to come */ +#define QM_MCR_FQS_NOTEMPTY 0x01 /* FQ has enqueued frames */ +#define QM_MCR_TIMEOUT 10000 /* us */ +union qm_mc_result { + struct { + u8 verb; + u8 result; + u8 __reserved1[62]; + }; + struct qm_mcr_queryfq queryfq; + struct qm_mcr_alterfq alterfq; + struct qm_mcr_querycgr querycgr; + struct qm_mcr_querycongestion querycongestion; + struct qm_mcr_querywq querywq; + struct qm_mcr_queryfq_np queryfq_np; +}; + +struct qm_mc { + union qm_mc_command *cr; + union qm_mc_result *rr; + u8 rridx, vbit; +#ifdef CONFIG_FSL_DPAA_CHECKING + enum { + /* Can be _mc_start()ed */ + qman_mc_idle, + /* Can be _mc_commit()ed or _mc_abort()ed */ + qman_mc_user, + /* Can only be _mc_retry()ed */ + qman_mc_hw + } state; +#endif +}; + +struct qm_addr { + void __iomem *ce; /* cache-enabled */ + void __iomem *ci; /* cache-inhibited */ +}; + +struct qm_portal { + /* + * In the non-CONFIG_FSL_DPAA_CHECKING case, the following stuff up to + * and including 'mc' fits within a cacheline (yay!). The 'config' part + * is setup-only, so isn't a cause for a concern. In other words, don't + * rearrange this structure on a whim, there be dragons ... + */ + struct qm_addr addr; + struct qm_eqcr eqcr; + struct qm_dqrr dqrr; + struct qm_mr mr; + struct qm_mc mc; +} ____cacheline_aligned; + +/* Cache-inhibited register access. */ +static inline u32 qm_in(struct qm_portal *p, u32 offset) +{ + return __raw_readl(p->addr.ci + offset); +} + +static inline void qm_out(struct qm_portal *p, u32 offset, u32 val) +{ + __raw_writel(val, p->addr.ci + offset); +} + +/* Cache Enabled Portal Access */ +static inline void qm_cl_invalidate(struct qm_portal *p, u32 offset) +{ + dpaa_invalidate(p->addr.ce + offset); +} + +static inline void qm_cl_touch_ro(struct qm_portal *p, u32 offset) +{ + dpaa_touch_ro(p->addr.ce + offset); +} + +static inline u32 qm_ce_in(struct qm_portal *p, u32 offset) +{ + return __raw_readl(p->addr.ce + offset); +} + +/* --- EQCR API --- */ + +#define EQCR_SHIFT ilog2(sizeof(struct qm_eqcr_entry)) +#define EQCR_CARRY (uintptr_t)(QM_EQCR_SIZE << EQCR_SHIFT) + +/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */ +static struct qm_eqcr_entry *eqcr_carryclear(struct qm_eqcr_entry *p) +{ + uintptr_t addr = (uintptr_t)p; + + addr &= ~EQCR_CARRY; + + return (struct qm_eqcr_entry *)addr; +} + +/* Bit-wise logic to convert a ring pointer to a ring index */ +static int eqcr_ptr2idx(struct qm_eqcr_entry *e) +{ + return ((uintptr_t)e >> EQCR_SHIFT) & (QM_EQCR_SIZE - 1); +} + +/* Increment the 'cursor' ring pointer, taking 'vbit' into account */ +static inline void eqcr_inc(struct qm_eqcr *eqcr) +{ + /* increment to the next EQCR pointer and handle overflow and 'vbit' */ + struct qm_eqcr_entry *partial = eqcr->cursor + 1; + + eqcr->cursor = eqcr_carryclear(partial); + if (partial != eqcr->cursor) + eqcr->vbit ^= QM_EQCR_VERB_VBIT; +} + +static inline int qm_eqcr_init(struct qm_portal *portal, + enum qm_eqcr_pmode pmode, + unsigned int eq_stash_thresh, + int eq_stash_prio) +{ + struct qm_eqcr *eqcr = &portal->eqcr; + u32 cfg; + u8 pi; + + eqcr->ring = portal->addr.ce + QM_CL_EQCR; + eqcr->ci = qm_in(portal, QM_REG_EQCR_CI_CINH) & (QM_EQCR_SIZE - 1); + qm_cl_invalidate(portal, QM_CL_EQCR_CI_CENA); + pi = qm_in(portal, QM_REG_EQCR_PI_CINH) & (QM_EQCR_SIZE - 1); + eqcr->cursor = eqcr->ring + pi; + eqcr->vbit = (qm_in(portal, QM_REG_EQCR_PI_CINH) & QM_EQCR_SIZE) ? + QM_EQCR_VERB_VBIT : 0; + eqcr->available = QM_EQCR_SIZE - 1 - + dpaa_cyc_diff(QM_EQCR_SIZE, eqcr->ci, pi); + eqcr->ithresh = qm_in(portal, QM_REG_EQCR_ITR); +#ifdef CONFIG_FSL_DPAA_CHECKING + eqcr->busy = 0; + eqcr->pmode = pmode; +#endif + cfg = (qm_in(portal, QM_REG_CFG) & 0x00ffffff) | + (eq_stash_thresh << 28) | /* QCSP_CFG: EST */ + (eq_stash_prio << 26) | /* QCSP_CFG: EP */ + ((pmode & 0x3) << 24); /* QCSP_CFG::EPM */ + qm_out(portal, QM_REG_CFG, cfg); + return 0; +} + +static inline unsigned int qm_eqcr_get_ci_stashing(struct qm_portal *portal) +{ + return (qm_in(portal, QM_REG_CFG) >> 28) & 0x7; +} + +static inline void qm_eqcr_finish(struct qm_portal *portal) +{ + struct qm_eqcr *eqcr = &portal->eqcr; + u8 pi = qm_in(portal, QM_REG_EQCR_PI_CINH) & (QM_EQCR_SIZE - 1); + u8 ci = qm_in(portal, QM_REG_EQCR_CI_CINH) & (QM_EQCR_SIZE - 1); + + DPAA_ASSERT(!eqcr->busy); + if (pi != eqcr_ptr2idx(eqcr->cursor)) + pr_crit("losing uncommited EQCR entries\n"); + if (ci != eqcr->ci) + pr_crit("missing existing EQCR completions\n"); + if (eqcr->ci != eqcr_ptr2idx(eqcr->cursor)) + pr_crit("EQCR destroyed unquiesced\n"); +} + +static inline struct qm_eqcr_entry *qm_eqcr_start_no_stash(struct qm_portal + *portal) +{ + struct qm_eqcr *eqcr = &portal->eqcr; + + DPAA_ASSERT(!eqcr->busy); + if (!eqcr->available) + return NULL; + +#ifdef CONFIG_FSL_DPAA_CHECKING + eqcr->busy = 1; +#endif + dpaa_zero(eqcr->cursor); + return eqcr->cursor; +} + +static inline struct qm_eqcr_entry *qm_eqcr_start_stash(struct qm_portal + *portal) +{ + struct qm_eqcr *eqcr = &portal->eqcr; + u8 diff, old_ci; + + DPAA_ASSERT(!eqcr->busy); + if (!eqcr->available) { + old_ci = eqcr->ci; + eqcr->ci = qm_ce_in(portal, QM_CL_EQCR_CI_CENA) & + (QM_EQCR_SIZE - 1); + diff = dpaa_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci); + eqcr->available += diff; + if (!diff) + return NULL; + } +#ifdef CONFIG_FSL_DPAA_CHECKING + eqcr->busy = 1; +#endif + dpaa_zero(eqcr->cursor); + return eqcr->cursor; +} + +static inline void eqcr_commit_checks(struct qm_eqcr *eqcr) +{ + DPAA_ASSERT(eqcr->busy); + DPAA_ASSERT(eqcr->cursor->orp == (eqcr->cursor->orp & 0x00ffffff)); + DPAA_ASSERT(eqcr->cursor->fqid == (eqcr->cursor->fqid & 0x00ffffff)); + DPAA_ASSERT(eqcr->available >= 1); +} + +static inline void qm_eqcr_pvb_commit(struct qm_portal *portal, u8 myverb) +{ + struct qm_eqcr *eqcr = &portal->eqcr; + struct qm_eqcr_entry *eqcursor; + + eqcr_commit_checks(eqcr); + DPAA_ASSERT(eqcr->pmode == qm_eqcr_pvb); + dma_wmb(); + eqcursor = eqcr->cursor; + eqcursor->_ncw_verb = myverb | eqcr->vbit; + dpaa_flush(eqcursor); + eqcr_inc(eqcr); + eqcr->available--; +#ifdef CONFIG_FSL_DPAA_CHECKING + eqcr->busy = 0; +#endif +} + +static inline void qm_eqcr_cce_prefetch(struct qm_portal *portal) +{ + qm_cl_touch_ro(portal, QM_CL_EQCR_CI_CENA); +} + +static inline u8 qm_eqcr_cce_update(struct qm_portal *portal) +{ + struct qm_eqcr *eqcr = &portal->eqcr; + u8 diff, old_ci = eqcr->ci; + + eqcr->ci = qm_ce_in(portal, QM_CL_EQCR_CI_CENA) & (QM_EQCR_SIZE - 1); + qm_cl_invalidate(portal, QM_CL_EQCR_CI_CENA); + diff = dpaa_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci); + eqcr->available += diff; + return diff; +} + +static inline void qm_eqcr_set_ithresh(struct qm_portal *portal, u8 ithresh) +{ + struct qm_eqcr *eqcr = &portal->eqcr; + + eqcr->ithresh = ithresh; + qm_out(portal, QM_REG_EQCR_ITR, ithresh); +} + +static inline u8 qm_eqcr_get_avail(struct qm_portal *portal) +{ + struct qm_eqcr *eqcr = &portal->eqcr; + + return eqcr->available; +} + +static inline u8 qm_eqcr_get_fill(struct qm_portal *portal) +{ + struct qm_eqcr *eqcr = &portal->eqcr; + + return QM_EQCR_SIZE - 1 - eqcr->available; +} + +/* --- DQRR API --- */ + +#define DQRR_SHIFT ilog2(sizeof(struct qm_dqrr_entry)) +#define DQRR_CARRY (uintptr_t)(QM_DQRR_SIZE << DQRR_SHIFT) + +static const struct qm_dqrr_entry *dqrr_carryclear( + const struct qm_dqrr_entry *p) +{ + uintptr_t addr = (uintptr_t)p; + + addr &= ~DQRR_CARRY; + + return (const struct qm_dqrr_entry *)addr; +} + +static inline int dqrr_ptr2idx(const struct qm_dqrr_entry *e) +{ + return ((uintptr_t)e >> DQRR_SHIFT) & (QM_DQRR_SIZE - 1); +} + +static const struct qm_dqrr_entry *dqrr_inc(const struct qm_dqrr_entry *e) +{ + return dqrr_carryclear(e + 1); +} + +static inline void qm_dqrr_set_maxfill(struct qm_portal *portal, u8 mf) +{ + qm_out(portal, QM_REG_CFG, (qm_in(portal, QM_REG_CFG) & 0xff0fffff) | + ((mf & (QM_DQRR_SIZE - 1)) << 20)); +} + +static inline int qm_dqrr_init(struct qm_portal *portal, + const struct qm_portal_config *config, + enum qm_dqrr_dmode dmode, + enum qm_dqrr_pmode pmode, + enum qm_dqrr_cmode cmode, u8 max_fill) +{ + struct qm_dqrr *dqrr = &portal->dqrr; + u32 cfg; + + /* Make sure the DQRR will be idle when we enable */ + qm_out(portal, QM_REG_DQRR_SDQCR, 0); + qm_out(portal, QM_REG_DQRR_VDQCR, 0); + qm_out(portal, QM_REG_DQRR_PDQCR, 0); + dqrr->ring = portal->addr.ce + QM_CL_DQRR; + dqrr->pi = qm_in(portal, QM_REG_DQRR_PI_CINH) & (QM_DQRR_SIZE - 1); + dqrr->ci = qm_in(portal, QM_REG_DQRR_CI_CINH) & (QM_DQRR_SIZE - 1); + dqrr->cursor = dqrr->ring + dqrr->ci; + dqrr->fill = dpaa_cyc_diff(QM_DQRR_SIZE, dqrr->ci, dqrr->pi); + dqrr->vbit = (qm_in(portal, QM_REG_DQRR_PI_CINH) & QM_DQRR_SIZE) ? + QM_DQRR_VERB_VBIT : 0; + dqrr->ithresh = qm_in(portal, QM_REG_DQRR_ITR); +#ifdef CONFIG_FSL_DPAA_CHECKING + dqrr->dmode = dmode; + dqrr->pmode = pmode; + dqrr->cmode = cmode; +#endif + /* Invalidate every ring entry before beginning */ + for (cfg = 0; cfg < QM_DQRR_SIZE; cfg++) + dpaa_invalidate(qm_cl(dqrr->ring, cfg)); + cfg = (qm_in(portal, QM_REG_CFG) & 0xff000f00) | + ((max_fill & (QM_DQRR_SIZE - 1)) << 20) | /* DQRR_MF */ + ((dmode & 1) << 18) | /* DP */ + ((cmode & 3) << 16) | /* DCM */ + 0xa0 | /* RE+SE */ + (0 ? 0x40 : 0) | /* Ignore RP */ + (0 ? 0x10 : 0); /* Ignore SP */ + qm_out(portal, QM_REG_CFG, cfg); + qm_dqrr_set_maxfill(portal, max_fill); + return 0; +} + +static inline void qm_dqrr_finish(struct qm_portal *portal) +{ +#ifdef CONFIG_FSL_DPAA_CHECKING + struct qm_dqrr *dqrr = &portal->dqrr; + + if (dqrr->cmode != qm_dqrr_cdc && + dqrr->ci != dqrr_ptr2idx(dqrr->cursor)) + pr_crit("Ignoring completed DQRR entries\n"); +#endif +} + +static inline const struct qm_dqrr_entry *qm_dqrr_current( + struct qm_portal *portal) +{ + struct qm_dqrr *dqrr = &portal->dqrr; + + if (!dqrr->fill) + return NULL; + return dqrr->cursor; +} + +static inline u8 qm_dqrr_next(struct qm_portal *portal) +{ + struct qm_dqrr *dqrr = &portal->dqrr; + + DPAA_ASSERT(dqrr->fill); + dqrr->cursor = dqrr_inc(dqrr->cursor); + return --dqrr->fill; +} + +static inline void qm_dqrr_pvb_update(struct qm_portal *portal) +{ + struct qm_dqrr *dqrr = &portal->dqrr; + struct qm_dqrr_entry *res = qm_cl(dqrr->ring, dqrr->pi); + + DPAA_ASSERT(dqrr->pmode == qm_dqrr_pvb); +#ifndef CONFIG_FSL_PAMU + /* + * If PAMU is not available we need to invalidate the cache. + * When PAMU is available the cache is updated by stash + */ + dpaa_invalidate_touch_ro(res); +#endif + /* + * when accessing 'verb', use __raw_readb() to ensure that compiler + * inlining doesn't try to optimise out "excess reads". + */ + if ((__raw_readb(&res->verb) & QM_DQRR_VERB_VBIT) == dqrr->vbit) { + dqrr->pi = (dqrr->pi + 1) & (QM_DQRR_SIZE - 1); + if (!dqrr->pi) + dqrr->vbit ^= QM_DQRR_VERB_VBIT; + dqrr->fill++; + } +} + +static inline void qm_dqrr_cdc_consume_1ptr(struct qm_portal *portal, + const struct qm_dqrr_entry *dq, + int park) +{ + __maybe_unused struct qm_dqrr *dqrr = &portal->dqrr; + int idx = dqrr_ptr2idx(dq); + + DPAA_ASSERT(dqrr->cmode == qm_dqrr_cdc); + DPAA_ASSERT((dqrr->ring + idx) == dq); + DPAA_ASSERT(idx < QM_DQRR_SIZE); + qm_out(portal, QM_REG_DQRR_DCAP, (0 << 8) | /* DQRR_DCAP::S */ + ((park ? 1 : 0) << 6) | /* DQRR_DCAP::PK */ + idx); /* DQRR_DCAP::DCAP_CI */ +} + +static inline void qm_dqrr_cdc_consume_n(struct qm_portal *portal, u32 bitmask) +{ + __maybe_unused struct qm_dqrr *dqrr = &portal->dqrr; + + DPAA_ASSERT(dqrr->cmode == qm_dqrr_cdc); + qm_out(portal, QM_REG_DQRR_DCAP, (1 << 8) | /* DQRR_DCAP::S */ + (bitmask << 16)); /* DQRR_DCAP::DCAP_CI */ +} + +static inline void qm_dqrr_sdqcr_set(struct qm_portal *portal, u32 sdqcr) +{ + qm_out(portal, QM_REG_DQRR_SDQCR, sdqcr); +} + +static inline void qm_dqrr_vdqcr_set(struct qm_portal *portal, u32 vdqcr) +{ + qm_out(portal, QM_REG_DQRR_VDQCR, vdqcr); +} + +static inline void qm_dqrr_set_ithresh(struct qm_portal *portal, u8 ithresh) +{ + qm_out(portal, QM_REG_DQRR_ITR, ithresh); +} + +/* --- MR API --- */ + +#define MR_SHIFT ilog2(sizeof(union qm_mr_entry)) +#define MR_CARRY (uintptr_t)(QM_MR_SIZE << MR_SHIFT) + +static union qm_mr_entry *mr_carryclear(union qm_mr_entry *p) +{ + uintptr_t addr = (uintptr_t)p; + + addr &= ~MR_CARRY; + + return (union qm_mr_entry *)addr; +} + +static inline int mr_ptr2idx(const union qm_mr_entry *e) +{ + return ((uintptr_t)e >> MR_SHIFT) & (QM_MR_SIZE - 1); +} + +static inline union qm_mr_entry *mr_inc(union qm_mr_entry *e) +{ + return mr_carryclear(e + 1); +} + +static inline int qm_mr_init(struct qm_portal *portal, enum qm_mr_pmode pmode, + enum qm_mr_cmode cmode) +{ + struct qm_mr *mr = &portal->mr; + u32 cfg; + + mr->ring = portal->addr.ce + QM_CL_MR; + mr->pi = qm_in(portal, QM_REG_MR_PI_CINH) & (QM_MR_SIZE - 1); + mr->ci = qm_in(portal, QM_REG_MR_CI_CINH) & (QM_MR_SIZE - 1); + mr->cursor = mr->ring + mr->ci; + mr->fill = dpaa_cyc_diff(QM_MR_SIZE, mr->ci, mr->pi); + mr->vbit = (qm_in(portal, QM_REG_MR_PI_CINH) & QM_MR_SIZE) + ? QM_MR_VERB_VBIT : 0; + mr->ithresh = qm_in(portal, QM_REG_MR_ITR); +#ifdef CONFIG_FSL_DPAA_CHECKING + mr->pmode = pmode; + mr->cmode = cmode; +#endif + cfg = (qm_in(portal, QM_REG_CFG) & 0xfffff0ff) | + ((cmode & 1) << 8); /* QCSP_CFG:MM */ + qm_out(portal, QM_REG_CFG, cfg); + return 0; +} + +static inline void qm_mr_finish(struct qm_portal *portal) +{ + struct qm_mr *mr = &portal->mr; + + if (mr->ci != mr_ptr2idx(mr->cursor)) + pr_crit("Ignoring completed MR entries\n"); +} + +static inline const union qm_mr_entry *qm_mr_current(struct qm_portal *portal) +{ + struct qm_mr *mr = &portal->mr; + + if (!mr->fill) + return NULL; + return mr->cursor; +} + +static inline int qm_mr_next(struct qm_portal *portal) +{ + struct qm_mr *mr = &portal->mr; + + DPAA_ASSERT(mr->fill); + mr->cursor = mr_inc(mr->cursor); + return --mr->fill; +} + +static inline void qm_mr_pvb_update(struct qm_portal *portal) +{ + struct qm_mr *mr = &portal->mr; + union qm_mr_entry *res = qm_cl(mr->ring, mr->pi); + + DPAA_ASSERT(mr->pmode == qm_mr_pvb); + /* + * when accessing 'verb', use __raw_readb() to ensure that compiler + * inlining doesn't try to optimise out "excess reads". + */ + if ((__raw_readb(&res->verb) & QM_MR_VERB_VBIT) == mr->vbit) { + mr->pi = (mr->pi + 1) & (QM_MR_SIZE - 1); + if (!mr->pi) + mr->vbit ^= QM_MR_VERB_VBIT; + mr->fill++; + res = mr_inc(res); + } + dpaa_invalidate_touch_ro(res); +} + +static inline void qm_mr_cci_consume(struct qm_portal *portal, u8 num) +{ + struct qm_mr *mr = &portal->mr; + + DPAA_ASSERT(mr->cmode == qm_mr_cci); + mr->ci = (mr->ci + num) & (QM_MR_SIZE - 1); + qm_out(portal, QM_REG_MR_CI_CINH, mr->ci); +} + +static inline void qm_mr_cci_consume_to_current(struct qm_portal *portal) +{ + struct qm_mr *mr = &portal->mr; + + DPAA_ASSERT(mr->cmode == qm_mr_cci); + mr->ci = mr_ptr2idx(mr->cursor); + qm_out(portal, QM_REG_MR_CI_CINH, mr->ci); +} + +static inline void qm_mr_set_ithresh(struct qm_portal *portal, u8 ithresh) +{ + qm_out(portal, QM_REG_MR_ITR, ithresh); +} + +/* --- Management command API --- */ + +static inline int qm_mc_init(struct qm_portal *portal) +{ + struct qm_mc *mc = &portal->mc; + + mc->cr = portal->addr.ce + QM_CL_CR; + mc->rr = portal->addr.ce + QM_CL_RR0; + mc->rridx = (__raw_readb(&mc->cr->_ncw_verb) & QM_MCC_VERB_VBIT) + ? 0 : 1; + mc->vbit = mc->rridx ? QM_MCC_VERB_VBIT : 0; +#ifdef CONFIG_FSL_DPAA_CHECKING + mc->state = qman_mc_idle; +#endif + return 0; +} + +static inline void qm_mc_finish(struct qm_portal *portal) +{ +#ifdef CONFIG_FSL_DPAA_CHECKING + struct qm_mc *mc = &portal->mc; + + DPAA_ASSERT(mc->state == qman_mc_idle); + if (mc->state != qman_mc_idle) + pr_crit("Losing incomplete MC command\n"); +#endif +} + +static inline union qm_mc_command *qm_mc_start(struct qm_portal *portal) +{ + struct qm_mc *mc = &portal->mc; + + DPAA_ASSERT(mc->state == qman_mc_idle); +#ifdef CONFIG_FSL_DPAA_CHECKING + mc->state = qman_mc_user; +#endif + dpaa_zero(mc->cr); + return mc->cr; +} + +static inline void qm_mc_commit(struct qm_portal *portal, u8 myverb) +{ + struct qm_mc *mc = &portal->mc; + union qm_mc_result *rr = mc->rr + mc->rridx; + + DPAA_ASSERT(mc->state == qman_mc_user); + dma_wmb(); + mc->cr->_ncw_verb = myverb | mc->vbit; + dpaa_flush(mc->cr); + dpaa_invalidate_touch_ro(rr); +#ifdef CONFIG_FSL_DPAA_CHECKING + mc->state = qman_mc_hw; +#endif +} + +static inline union qm_mc_result *qm_mc_result(struct qm_portal *portal) +{ + struct qm_mc *mc = &portal->mc; + union qm_mc_result *rr = mc->rr + mc->rridx; + + DPAA_ASSERT(mc->state == qman_mc_hw); + /* + * The inactive response register's verb byte always returns zero until + * its command is submitted and completed. This includes the valid-bit, + * in case you were wondering... + */ + if (!__raw_readb(&rr->verb)) { + dpaa_invalidate_touch_ro(rr); + return NULL; + } + mc->rridx ^= 1; + mc->vbit ^= QM_MCC_VERB_VBIT; +#ifdef CONFIG_FSL_DPAA_CHECKING + mc->state = qman_mc_idle; +#endif + return rr; +} + +static inline int qm_mc_result_timeout(struct qm_portal *portal, + union qm_mc_result **mcr) +{ + int timeout = QM_MCR_TIMEOUT; + + do { + *mcr = qm_mc_result(portal); + if (*mcr) + break; + udelay(1); + } while (--timeout); + + return timeout; +} + +static inline void fq_set(struct qman_fq *fq, u32 mask) +{ + set_bits(mask, &fq->flags); +} + +static inline void fq_clear(struct qman_fq *fq, u32 mask) +{ + clear_bits(mask, &fq->flags); +} + +static inline int fq_isset(struct qman_fq *fq, u32 mask) +{ + return fq->flags & mask; +} + +static inline int fq_isclear(struct qman_fq *fq, u32 mask) +{ + return !(fq->flags & mask); +} + +struct qman_portal { + struct qm_portal p; + /* PORTAL_BITS_*** - dynamic, strictly internal */ + unsigned long bits; + /* interrupt sources processed by portal_isr(), configurable */ + unsigned long irq_sources; + u32 use_eqcr_ci_stashing; + /* only 1 volatile dequeue at a time */ + struct qman_fq *vdqcr_owned; + u32 sdqcr; + /* probing time config params for cpu-affine portals */ + const struct qm_portal_config *config; + /* needed for providing a non-NULL device to dma_map_***() */ + struct platform_device *pdev; + /* 2-element array. cgrs[0] is mask, cgrs[1] is snapshot. */ + struct qman_cgrs *cgrs; + /* linked-list of CSCN handlers. */ + struct list_head cgr_cbs; + /* list lock */ + spinlock_t cgr_lock; + struct work_struct congestion_work; + struct work_struct mr_work; + char irqname[MAX_IRQNAME]; +}; + +static cpumask_t affine_mask; +static DEFINE_SPINLOCK(affine_mask_lock); +static u16 affine_channels[NR_CPUS]; +static DEFINE_PER_CPU(struct qman_portal, qman_affine_portal); +struct qman_portal *affine_portals[NR_CPUS]; + +static inline struct qman_portal *get_affine_portal(void) +{ + return &get_cpu_var(qman_affine_portal); +} + +static inline void put_affine_portal(void) +{ + put_cpu_var(qman_affine_portal); +} + +static struct workqueue_struct *qm_portal_wq; + +int qman_wq_alloc(void) +{ + qm_portal_wq = alloc_workqueue("qman_portal_wq", 0, 1); + if (!qm_portal_wq) + return -ENOMEM; + return 0; +} + +/* + * This is what everything can wait on, even if it migrates to a different cpu + * to the one whose affine portal it is waiting on. + */ +static DECLARE_WAIT_QUEUE_HEAD(affine_queue); + +static struct qman_fq **fq_table; +static u32 num_fqids; + +int qman_alloc_fq_table(u32 _num_fqids) +{ + num_fqids = _num_fqids; + + fq_table = vzalloc(num_fqids * 2 * sizeof(struct qman_fq *)); + if (!fq_table) + return -ENOMEM; + + pr_debug("Allocated fq lookup table at %p, entry count %u\n", + fq_table, num_fqids * 2); + return 0; +} + +static struct qman_fq *idx_to_fq(u32 idx) +{ + struct qman_fq *fq; + +#ifdef CONFIG_FSL_DPAA_CHECKING + if (WARN_ON(idx >= num_fqids * 2)) + return NULL; +#endif + fq = fq_table[idx]; + DPAA_ASSERT(!fq || idx == fq->idx); + + return fq; +} + +/* + * Only returns full-service fq objects, not enqueue-only + * references (QMAN_FQ_FLAG_NO_MODIFY). + */ +static struct qman_fq *fqid_to_fq(u32 fqid) +{ + return idx_to_fq(fqid * 2); +} + +static struct qman_fq *tag_to_fq(u32 tag) +{ +#if BITS_PER_LONG == 64 + return idx_to_fq(tag); +#else + return (struct qman_fq *)tag; +#endif +} + +static u32 fq_to_tag(struct qman_fq *fq) +{ +#if BITS_PER_LONG == 64 + return fq->idx; +#else + return (u32)fq; +#endif +} + +static u32 __poll_portal_slow(struct qman_portal *p, u32 is); +static inline unsigned int __poll_portal_fast(struct qman_portal *p, + unsigned int poll_limit); +static void qm_congestion_task(struct work_struct *work); +static void qm_mr_process_task(struct work_struct *work); + +static irqreturn_t portal_isr(int irq, void *ptr) +{ + struct qman_portal *p = ptr; + + u32 clear = QM_DQAVAIL_MASK | p->irq_sources; + u32 is = qm_in(&p->p, QM_REG_ISR) & p->irq_sources; + + if (unlikely(!is)) + return IRQ_NONE; + + /* DQRR-handling if it's interrupt-driven */ + if (is & QM_PIRQ_DQRI) + __poll_portal_fast(p, QMAN_POLL_LIMIT); + /* Handling of anything else that's interrupt-driven */ + clear |= __poll_portal_slow(p, is); + qm_out(&p->p, QM_REG_ISR, clear); + return IRQ_HANDLED; +} + +static int drain_mr_fqrni(struct qm_portal *p) +{ + const union qm_mr_entry *msg; +loop: + msg = qm_mr_current(p); + if (!msg) { + /* + * if MR was full and h/w had other FQRNI entries to produce, we + * need to allow it time to produce those entries once the + * existing entries are consumed. A worst-case situation + * (fully-loaded system) means h/w sequencers may have to do 3-4 + * other things before servicing the portal's MR pump, each of + * which (if slow) may take ~50 qman cycles (which is ~200 + * processor cycles). So rounding up and then multiplying this + * worst-case estimate by a factor of 10, just to be + * ultra-paranoid, goes as high as 10,000 cycles. NB, we consume + * one entry at a time, so h/w has an opportunity to produce new + * entries well before the ring has been fully consumed, so + * we're being *really* paranoid here. + */ + u64 now, then = jiffies; + + do { + now = jiffies; + } while ((then + 10000) > now); + msg = qm_mr_current(p); + if (!msg) + return 0; + } + if ((msg->verb & QM_MR_VERB_TYPE_MASK) != QM_MR_VERB_FQRNI) { + /* We aren't draining anything but FQRNIs */ + pr_err("Found verb 0x%x in MR\n", msg->verb); + return -1; + } + qm_mr_next(p); + qm_mr_cci_consume(p, 1); + goto loop; +} + +static int qman_create_portal(struct qman_portal *portal, + const struct qm_portal_config *c, + const struct qman_cgrs *cgrs) +{ + struct qm_portal *p; + char buf[16]; + int ret; + u32 isdr; + + p = &portal->p; + +#ifdef CONFIG_FSL_PAMU + /* PAMU is required for stashing */ + portal->use_eqcr_ci_stashing = ((qman_ip_rev >= QMAN_REV30) ? 1 : 0); +#else + portal->use_eqcr_ci_stashing = 0; +#endif + /* + * prep the low-level portal struct with the mapped addresses from the + * config, everything that follows depends on it and "config" is more + * for (de)reference + */ + p->addr.ce = c->addr_virt[DPAA_PORTAL_CE]; + p->addr.ci = c->addr_virt[DPAA_PORTAL_CI]; + /* + * If CI-stashing is used, the current defaults use a threshold of 3, + * and stash with high-than-DQRR priority. + */ + if (qm_eqcr_init(p, qm_eqcr_pvb, + portal->use_eqcr_ci_stashing ? 3 : 0, 1)) { + dev_err(c->dev, "EQCR initialisation failed\n"); + goto fail_eqcr; + } + if (qm_dqrr_init(p, c, qm_dqrr_dpush, qm_dqrr_pvb, + qm_dqrr_cdc, DQRR_MAXFILL)) { + dev_err(c->dev, "DQRR initialisation failed\n"); + goto fail_dqrr; + } + if (qm_mr_init(p, qm_mr_pvb, qm_mr_cci)) { + dev_err(c->dev, "MR initialisation failed\n"); + goto fail_mr; + } + if (qm_mc_init(p)) { + dev_err(c->dev, "MC initialisation failed\n"); + goto fail_mc; + } + /* static interrupt-gating controls */ + qm_dqrr_set_ithresh(p, QMAN_PIRQ_DQRR_ITHRESH); + qm_mr_set_ithresh(p, QMAN_PIRQ_MR_ITHRESH); + qm_out(p, QM_REG_ITPR, QMAN_PIRQ_IPERIOD); + portal->cgrs = kmalloc(2 * sizeof(*cgrs), GFP_KERNEL); + if (!portal->cgrs) + goto fail_cgrs; + /* initial snapshot is no-depletion */ + qman_cgrs_init(&portal->cgrs[1]); + if (cgrs) + portal->cgrs[0] = *cgrs; + else + /* if the given mask is NULL, assume all CGRs can be seen */ + qman_cgrs_fill(&portal->cgrs[0]); + INIT_LIST_HEAD(&portal->cgr_cbs); + spin_lock_init(&portal->cgr_lock); + INIT_WORK(&portal->congestion_work, qm_congestion_task); + INIT_WORK(&portal->mr_work, qm_mr_process_task); + portal->bits = 0; + portal->sdqcr = QM_SDQCR_SOURCE_CHANNELS | QM_SDQCR_COUNT_UPTO3 | + QM_SDQCR_DEDICATED_PRECEDENCE | QM_SDQCR_TYPE_PRIO_QOS | + QM_SDQCR_TOKEN_SET(0xab) | QM_SDQCR_CHANNELS_DEDICATED; + sprintf(buf, "qportal-%d", c->channel); + portal->pdev = platform_device_alloc(buf, -1); + if (!portal->pdev) + goto fail_devalloc; + if (dma_set_mask(&portal->pdev->dev, DMA_BIT_MASK(40))) + goto fail_devadd; + ret = platform_device_add(portal->pdev); + if (ret) + goto fail_devadd; + isdr = 0xffffffff; + qm_out(p, QM_REG_ISDR, isdr); + portal->irq_sources = 0; + qm_out(p, QM_REG_IER, 0); + qm_out(p, QM_REG_ISR, 0xffffffff); + snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu); + if (request_irq(c->irq, portal_isr, 0, portal->irqname, portal)) { + dev_err(c->dev, "request_irq() failed\n"); + goto fail_irq; + } + if (c->cpu != -1 && irq_can_set_affinity(c->irq) && + irq_set_affinity(c->irq, cpumask_of(c->cpu))) { + dev_err(c->dev, "irq_set_affinity() failed\n"); + goto fail_affinity; + } + + /* Need EQCR to be empty before continuing */ + isdr &= ~QM_PIRQ_EQCI; + qm_out(p, QM_REG_ISDR, isdr); + ret = qm_eqcr_get_fill(p); + if (ret) { + dev_err(c->dev, "EQCR unclean\n"); + goto fail_eqcr_empty; + } + isdr &= ~(QM_PIRQ_DQRI | QM_PIRQ_MRI); + qm_out(p, QM_REG_ISDR, isdr); + if (qm_dqrr_current(p)) { + dev_err(c->dev, "DQRR unclean\n"); + qm_dqrr_cdc_consume_n(p, 0xffff); + } + if (qm_mr_current(p) && drain_mr_fqrni(p)) { + /* special handling, drain just in case it's a few FQRNIs */ + const union qm_mr_entry *e = qm_mr_current(p); + + dev_err(c->dev, "MR dirty, VB 0x%x, rc 0x%x\n, addr 0x%x", + e->verb, e->ern.rc, e->ern.fd.addr_lo); + goto fail_dqrr_mr_empty; + } + /* Success */ + portal->config = c; + qm_out(p, QM_REG_ISDR, 0); + qm_out(p, QM_REG_IIR, 0); + /* Write a sane SDQCR */ + qm_dqrr_sdqcr_set(p, portal->sdqcr); + return 0; + +fail_dqrr_mr_empty: +fail_eqcr_empty: +fail_affinity: + free_irq(c->irq, portal); +fail_irq: + platform_device_del(portal->pdev); +fail_devadd: + platform_device_put(portal->pdev); +fail_devalloc: + kfree(portal->cgrs); +fail_cgrs: + qm_mc_finish(p); +fail_mc: + qm_mr_finish(p); +fail_mr: + qm_dqrr_finish(p); +fail_dqrr: + qm_eqcr_finish(p); +fail_eqcr: + return -EIO; +} + +struct qman_portal *qman_create_affine_portal(const struct qm_portal_config *c, + const struct qman_cgrs *cgrs) +{ + struct qman_portal *portal; + int err; + + portal = &per_cpu(qman_affine_portal, c->cpu); + err = qman_create_portal(portal, c, cgrs); + if (err) + return NULL; + + spin_lock(&affine_mask_lock); + cpumask_set_cpu(c->cpu, &affine_mask); + affine_channels[c->cpu] = c->channel; + affine_portals[c->cpu] = portal; + spin_unlock(&affine_mask_lock); + + return portal; +} + +static void qman_destroy_portal(struct qman_portal *qm) +{ + const struct qm_portal_config *pcfg; + + /* Stop dequeues on the portal */ + qm_dqrr_sdqcr_set(&qm->p, 0); + + /* + * NB we do this to "quiesce" EQCR. If we add enqueue-completions or + * something related to QM_PIRQ_EQCI, this may need fixing. + * Also, due to the prefetching model used for CI updates in the enqueue + * path, this update will only invalidate the CI cacheline *after* + * working on it, so we need to call this twice to ensure a full update + * irrespective of where the enqueue processing was at when the teardown + * began. + */ + qm_eqcr_cce_update(&qm->p); + qm_eqcr_cce_update(&qm->p); + pcfg = qm->config; + + free_irq(pcfg->irq, qm); + + kfree(qm->cgrs); + qm_mc_finish(&qm->p); + qm_mr_finish(&qm->p); + qm_dqrr_finish(&qm->p); + qm_eqcr_finish(&qm->p); + + platform_device_del(qm->pdev); + platform_device_put(qm->pdev); + + qm->config = NULL; +} + +const struct qm_portal_config *qman_destroy_affine_portal(void) +{ + struct qman_portal *qm = get_affine_portal(); + const struct qm_portal_config *pcfg; + int cpu; + + pcfg = qm->config; + cpu = pcfg->cpu; + + qman_destroy_portal(qm); + + spin_lock(&affine_mask_lock); + cpumask_clear_cpu(cpu, &affine_mask); + spin_unlock(&affine_mask_lock); + put_affine_portal(); + return pcfg; +} + +/* Inline helper to reduce nesting in __poll_portal_slow() */ +static inline void fq_state_change(struct qman_portal *p, struct qman_fq *fq, + const union qm_mr_entry *msg, u8 verb) +{ + switch (verb) { + case QM_MR_VERB_FQRL: + DPAA_ASSERT(fq_isset(fq, QMAN_FQ_STATE_ORL)); + fq_clear(fq, QMAN_FQ_STATE_ORL); + break; + case QM_MR_VERB_FQRN: + DPAA_ASSERT(fq->state == qman_fq_state_parked || + fq->state == qman_fq_state_sched); + DPAA_ASSERT(fq_isset(fq, QMAN_FQ_STATE_CHANGING)); + fq_clear(fq, QMAN_FQ_STATE_CHANGING); + if (msg->fq.fqs & QM_MR_FQS_NOTEMPTY) + fq_set(fq, QMAN_FQ_STATE_NE); + if (msg->fq.fqs & QM_MR_FQS_ORLPRESENT) + fq_set(fq, QMAN_FQ_STATE_ORL); + fq->state = qman_fq_state_retired; + break; + case QM_MR_VERB_FQPN: + DPAA_ASSERT(fq->state == qman_fq_state_sched); + DPAA_ASSERT(fq_isclear(fq, QMAN_FQ_STATE_CHANGING)); + fq->state = qman_fq_state_parked; + } +} + +static void qm_congestion_task(struct work_struct *work) +{ + struct qman_portal *p = container_of(work, struct qman_portal, + congestion_work); + struct qman_cgrs rr, c; + union qm_mc_result *mcr; + struct qman_cgr *cgr; + + spin_lock(&p->cgr_lock); + qm_mc_start(&p->p); + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + spin_unlock(&p->cgr_lock); + dev_crit(p->config->dev, "QUERYCONGESTION timeout\n"); + return; + } + /* mask out the ones I'm not interested in */ + qman_cgrs_and(&rr, (struct qman_cgrs *)&mcr->querycongestion.state, + &p->cgrs[0]); + /* check previous snapshot for delta, enter/exit congestion */ + qman_cgrs_xor(&c, &rr, &p->cgrs[1]); + /* update snapshot */ + qman_cgrs_cp(&p->cgrs[1], &rr); + /* Invoke callback */ + list_for_each_entry(cgr, &p->cgr_cbs, node) + if (cgr->cb && qman_cgrs_get(&c, cgr->cgrid)) + cgr->cb(p, cgr, qman_cgrs_get(&rr, cgr->cgrid)); + spin_unlock(&p->cgr_lock); +} + +static void qm_mr_process_task(struct work_struct *work) +{ + struct qman_portal *p = container_of(work, struct qman_portal, + mr_work); + const union qm_mr_entry *msg; + struct qman_fq *fq; + u8 verb, num = 0; + + preempt_disable(); + + while (1) { + qm_mr_pvb_update(&p->p); + msg = qm_mr_current(&p->p); + if (!msg) + break; + + verb = msg->verb & QM_MR_VERB_TYPE_MASK; + /* The message is a software ERN iff the 0x20 bit is clear */ + if (verb & 0x20) { + switch (verb) { + case QM_MR_VERB_FQRNI: + /* nada, we drop FQRNIs on the floor */ + break; + case QM_MR_VERB_FQRN: + case QM_MR_VERB_FQRL: + /* Lookup in the retirement table */ + fq = fqid_to_fq(msg->fq.fqid); + if (WARN_ON(!fq)) + break; + fq_state_change(p, fq, msg, verb); + if (fq->cb.fqs) + fq->cb.fqs(p, fq, msg); + break; + case QM_MR_VERB_FQPN: + /* Parked */ + fq = tag_to_fq(msg->fq.contextB); + fq_state_change(p, fq, msg, verb); + if (fq->cb.fqs) + fq->cb.fqs(p, fq, msg); + break; + case QM_MR_VERB_DC_ERN: + /* DCP ERN */ + pr_crit_once("Leaking DCP ERNs!\n"); + break; + default: + pr_crit("Invalid MR verb 0x%02x\n", verb); + } + } else { + /* Its a software ERN */ + fq = tag_to_fq(msg->ern.tag); + fq->cb.ern(p, fq, msg); + } + num++; + qm_mr_next(&p->p); + } + + qm_mr_cci_consume(&p->p, num); + preempt_enable(); +} + +static u32 __poll_portal_slow(struct qman_portal *p, u32 is) +{ + if (is & QM_PIRQ_CSCI) { + queue_work_on(smp_processor_id(), qm_portal_wq, + &p->congestion_work); + } + + if (is & QM_PIRQ_EQRI) { + qm_eqcr_cce_update(&p->p); + qm_eqcr_set_ithresh(&p->p, 0); + wake_up(&affine_queue); + } + + if (is & QM_PIRQ_MRI) { + queue_work_on(smp_processor_id(), qm_portal_wq, + &p->mr_work); + } + + return is; +} + +/* + * remove some slowish-path stuff from the "fast path" and make sure it isn't + * inlined. + */ +static noinline void clear_vdqcr(struct qman_portal *p, struct qman_fq *fq) +{ + p->vdqcr_owned = NULL; + fq_clear(fq, QMAN_FQ_STATE_VDQCR); + wake_up(&affine_queue); +} + +/* + * The only states that would conflict with other things if they ran at the + * same time on the same cpu are: + * + * (i) setting/clearing vdqcr_owned, and + * (ii) clearing the NE (Not Empty) flag. + * + * Both are safe. Because; + * + * (i) this clearing can only occur after qman_volatile_dequeue() has set the + * vdqcr_owned field (which it does before setting VDQCR), and + * qman_volatile_dequeue() blocks interrupts and preemption while this is + * done so that we can't interfere. + * (ii) the NE flag is only cleared after qman_retire_fq() has set it, and as + * with (i) that API prevents us from interfering until it's safe. + * + * The good thing is that qman_volatile_dequeue() and qman_retire_fq() run far + * less frequently (ie. per-FQ) than __poll_portal_fast() does, so the nett + * advantage comes from this function not having to "lock" anything at all. + * + * Note also that the callbacks are invoked at points which are safe against the + * above potential conflicts, but that this function itself is not re-entrant + * (this is because the function tracks one end of each FIFO in the portal and + * we do *not* want to lock that). So the consequence is that it is safe for + * user callbacks to call into any QMan API. + */ +static inline unsigned int __poll_portal_fast(struct qman_portal *p, + unsigned int poll_limit) +{ + const struct qm_dqrr_entry *dq; + struct qman_fq *fq; + enum qman_cb_dqrr_result res; + unsigned int limit = 0; + + do { + qm_dqrr_pvb_update(&p->p); + dq = qm_dqrr_current(&p->p); + if (!dq) + break; + + if (dq->stat & QM_DQRR_STAT_UNSCHEDULED) { + /* + * VDQCR: don't trust contextB as the FQ may have + * been configured for h/w consumption and we're + * draining it post-retirement. + */ + fq = p->vdqcr_owned; + /* + * We only set QMAN_FQ_STATE_NE when retiring, so we + * only need to check for clearing it when doing + * volatile dequeues. It's one less thing to check + * in the critical path (SDQCR). + */ + if (dq->stat & QM_DQRR_STAT_FQ_EMPTY) + fq_clear(fq, QMAN_FQ_STATE_NE); + /* + * This is duplicated from the SDQCR code, but we + * have stuff to do before *and* after this callback, + * and we don't want multiple if()s in the critical + * path (SDQCR). + */ + res = fq->cb.dqrr(p, fq, dq); + if (res == qman_cb_dqrr_stop) + break; + /* Check for VDQCR completion */ + if (dq->stat & QM_DQRR_STAT_DQCR_EXPIRED) + clear_vdqcr(p, fq); + } else { + /* SDQCR: contextB points to the FQ */ + fq = tag_to_fq(dq->contextB); + /* Now let the callback do its stuff */ + res = fq->cb.dqrr(p, fq, dq); + /* + * The callback can request that we exit without + * consuming this entry nor advancing; + */ + if (res == qman_cb_dqrr_stop) + break; + } + /* Interpret 'dq' from a driver perspective. */ + /* + * Parking isn't possible unless HELDACTIVE was set. NB, + * FORCEELIGIBLE implies HELDACTIVE, so we only need to + * check for HELDACTIVE to cover both. + */ + DPAA_ASSERT((dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) || + (res != qman_cb_dqrr_park)); + /* just means "skip it, I'll consume it myself later on" */ + if (res != qman_cb_dqrr_defer) + qm_dqrr_cdc_consume_1ptr(&p->p, dq, + res == qman_cb_dqrr_park); + /* Move forward */ + qm_dqrr_next(&p->p); + /* + * Entry processed and consumed, increment our counter. The + * callback can request that we exit after consuming the + * entry, and we also exit if we reach our processing limit, + * so loop back only if neither of these conditions is met. + */ + } while (++limit < poll_limit && res != qman_cb_dqrr_consume_stop); + + return limit; +} + +void qman_p_irqsource_add(struct qman_portal *p, u32 bits) +{ + unsigned long irqflags; + + local_irq_save(irqflags); + set_bits(bits & QM_PIRQ_VISIBLE, &p->irq_sources); + qm_out(&p->p, QM_REG_IER, p->irq_sources); + local_irq_restore(irqflags); +} +EXPORT_SYMBOL(qman_p_irqsource_add); + +void qman_p_irqsource_remove(struct qman_portal *p, u32 bits) +{ + unsigned long irqflags; + u32 ier; + + /* + * Our interrupt handler only processes+clears status register bits that + * are in p->irq_sources. As we're trimming that mask, if one of them + * were to assert in the status register just before we remove it from + * the enable register, there would be an interrupt-storm when we + * release the IRQ lock. So we wait for the enable register update to + * take effect in h/w (by reading it back) and then clear all other bits + * in the status register. Ie. we clear them from ISR once it's certain + * IER won't allow them to reassert. + */ + local_irq_save(irqflags); + bits &= QM_PIRQ_VISIBLE; + clear_bits(bits, &p->irq_sources); + qm_out(&p->p, QM_REG_IER, p->irq_sources); + ier = qm_in(&p->p, QM_REG_IER); + /* + * Using "~ier" (rather than "bits" or "~p->irq_sources") creates a + * data-dependency, ie. to protect against re-ordering. + */ + qm_out(&p->p, QM_REG_ISR, ~ier); + local_irq_restore(irqflags); +} +EXPORT_SYMBOL(qman_p_irqsource_remove); + +const cpumask_t *qman_affine_cpus(void) +{ + return &affine_mask; +} +EXPORT_SYMBOL(qman_affine_cpus); + +u16 qman_affine_channel(int cpu) +{ + if (cpu < 0) { + struct qman_portal *portal = get_affine_portal(); + + cpu = portal->config->cpu; + put_affine_portal(); + } + WARN_ON(!cpumask_test_cpu(cpu, &affine_mask)); + return affine_channels[cpu]; +} +EXPORT_SYMBOL(qman_affine_channel); + +struct qman_portal *qman_get_affine_portal(int cpu) +{ + return affine_portals[cpu]; +} +EXPORT_SYMBOL(qman_get_affine_portal); + +int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit) +{ + return __poll_portal_fast(p, limit); +} +EXPORT_SYMBOL(qman_p_poll_dqrr); + +void qman_p_static_dequeue_add(struct qman_portal *p, u32 pools) +{ + unsigned long irqflags; + + local_irq_save(irqflags); + pools &= p->config->pools; + p->sdqcr |= pools; + qm_dqrr_sdqcr_set(&p->p, p->sdqcr); + local_irq_restore(irqflags); +} +EXPORT_SYMBOL(qman_p_static_dequeue_add); + +/* Frame queue API */ + +static const char *mcr_result_str(u8 result) +{ + switch (result) { + case QM_MCR_RESULT_NULL: + return "QM_MCR_RESULT_NULL"; + case QM_MCR_RESULT_OK: + return "QM_MCR_RESULT_OK"; + case QM_MCR_RESULT_ERR_FQID: + return "QM_MCR_RESULT_ERR_FQID"; + case QM_MCR_RESULT_ERR_FQSTATE: + return "QM_MCR_RESULT_ERR_FQSTATE"; + case QM_MCR_RESULT_ERR_NOTEMPTY: + return "QM_MCR_RESULT_ERR_NOTEMPTY"; + case QM_MCR_RESULT_PENDING: + return "QM_MCR_RESULT_PENDING"; + case QM_MCR_RESULT_ERR_BADCOMMAND: + return "QM_MCR_RESULT_ERR_BADCOMMAND"; + } + return ""; +} + +int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq) +{ + if (flags & QMAN_FQ_FLAG_DYNAMIC_FQID) { + int ret = qman_alloc_fqid(&fqid); + + if (ret) + return ret; + } + fq->fqid = fqid; + fq->flags = flags; + fq->state = qman_fq_state_oos; + fq->cgr_groupid = 0; + + /* A context_b of 0 is allegedly special, so don't use that fqid */ + if (fqid == 0 || fqid >= num_fqids) { + WARN(1, "bad fqid %d\n", fqid); + return -EINVAL; + } + + fq->idx = fqid * 2; + if (flags & QMAN_FQ_FLAG_NO_MODIFY) + fq->idx++; + + WARN_ON(fq_table[fq->idx]); + fq_table[fq->idx] = fq; + + return 0; +} +EXPORT_SYMBOL(qman_create_fq); + +void qman_destroy_fq(struct qman_fq *fq) +{ + /* + * We don't need to lock the FQ as it is a pre-condition that the FQ be + * quiesced. Instead, run some checks. + */ + switch (fq->state) { + case qman_fq_state_parked: + case qman_fq_state_oos: + if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID)) + qman_release_fqid(fq->fqid); + + DPAA_ASSERT(fq_table[fq->idx]); + fq_table[fq->idx] = NULL; + return; + default: + break; + } + DPAA_ASSERT(NULL == "qman_free_fq() on unquiesced FQ!"); +} +EXPORT_SYMBOL(qman_destroy_fq); + +u32 qman_fq_fqid(struct qman_fq *fq) +{ + return fq->fqid; +} +EXPORT_SYMBOL(qman_fq_fqid); + +int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) +{ + union qm_mc_command *mcc; + union qm_mc_result *mcr; + struct qman_portal *p; + u8 res, myverb; + int ret = 0; + + myverb = (flags & QMAN_INITFQ_FLAG_SCHED) + ? QM_MCC_VERB_INITFQ_SCHED : QM_MCC_VERB_INITFQ_PARKED; + + if (fq->state != qman_fq_state_oos && + fq->state != qman_fq_state_parked) + return -EINVAL; +#ifdef CONFIG_FSL_DPAA_CHECKING + if (fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)) + return -EINVAL; +#endif + if (opts && (opts->we_mask & QM_INITFQ_WE_OAC)) { + /* And can't be set at the same time as TDTHRESH */ + if (opts->we_mask & QM_INITFQ_WE_TDTHRESH) + return -EINVAL; + } + /* Issue an INITFQ_[PARKED|SCHED] management command */ + p = get_affine_portal(); + if (fq_isset(fq, QMAN_FQ_STATE_CHANGING) || + (fq->state != qman_fq_state_oos && + fq->state != qman_fq_state_parked)) { + ret = -EBUSY; + goto out; + } + mcc = qm_mc_start(&p->p); + if (opts) + mcc->initfq = *opts; + mcc->initfq.fqid = fq->fqid; + mcc->initfq.count = 0; + /* + * If the FQ does *not* have the TO_DCPORTAL flag, contextB is set as a + * demux pointer. Otherwise, the caller-provided value is allowed to + * stand, don't overwrite it. + */ + if (fq_isclear(fq, QMAN_FQ_FLAG_TO_DCPORTAL)) { + dma_addr_t phys_fq; + + mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTB; + mcc->initfq.fqd.context_b = fq_to_tag(fq); + /* + * and the physical address - NB, if the user wasn't trying to + * set CONTEXTA, clear the stashing settings. + */ + if (!(mcc->initfq.we_mask & QM_INITFQ_WE_CONTEXTA)) { + mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; + memset(&mcc->initfq.fqd.context_a, 0, + sizeof(mcc->initfq.fqd.context_a)); + } else { + phys_fq = dma_map_single(&p->pdev->dev, fq, sizeof(*fq), + DMA_TO_DEVICE); + qm_fqd_stashing_set64(&mcc->initfq.fqd, phys_fq); + } + } + if (flags & QMAN_INITFQ_FLAG_LOCAL) { + int wq = 0; + + if (!(mcc->initfq.we_mask & QM_INITFQ_WE_DESTWQ)) { + mcc->initfq.we_mask |= QM_INITFQ_WE_DESTWQ; + wq = 4; + } + qm_fqd_set_destwq(&mcc->initfq.fqd, p->config->channel, wq); + } + qm_mc_commit(&p->p, myverb); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + dev_err(p->config->dev, "MCR timeout\n"); + ret = -ETIMEDOUT; + goto out; + } + + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb); + res = mcr->result; + if (res != QM_MCR_RESULT_OK) { + ret = -EIO; + goto out; + } + if (opts) { + if (opts->we_mask & QM_INITFQ_WE_FQCTRL) { + if (opts->fqd.fq_ctrl & QM_FQCTRL_CGE) + fq_set(fq, QMAN_FQ_STATE_CGR_EN); + else + fq_clear(fq, QMAN_FQ_STATE_CGR_EN); + } + if (opts->we_mask & QM_INITFQ_WE_CGID) + fq->cgr_groupid = opts->fqd.cgid; + } + fq->state = (flags & QMAN_INITFQ_FLAG_SCHED) ? + qman_fq_state_sched : qman_fq_state_parked; + +out: + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_init_fq); + +int qman_schedule_fq(struct qman_fq *fq) +{ + union qm_mc_command *mcc; + union qm_mc_result *mcr; + struct qman_portal *p; + int ret = 0; + + if (fq->state != qman_fq_state_parked) + return -EINVAL; +#ifdef CONFIG_FSL_DPAA_CHECKING + if (fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)) + return -EINVAL; +#endif + /* Issue a ALTERFQ_SCHED management command */ + p = get_affine_portal(); + if (fq_isset(fq, QMAN_FQ_STATE_CHANGING) || + fq->state != qman_fq_state_parked) { + ret = -EBUSY; + goto out; + } + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fq->fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_SCHED); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + dev_err(p->config->dev, "ALTER_SCHED timeout\n"); + ret = -ETIMEDOUT; + goto out; + } + + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_SCHED); + if (mcr->result != QM_MCR_RESULT_OK) { + ret = -EIO; + goto out; + } + fq->state = qman_fq_state_sched; +out: + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_schedule_fq); + +int qman_retire_fq(struct qman_fq *fq, u32 *flags) +{ + union qm_mc_command *mcc; + union qm_mc_result *mcr; + struct qman_portal *p; + int ret; + u8 res; + + if (fq->state != qman_fq_state_parked && + fq->state != qman_fq_state_sched) + return -EINVAL; +#ifdef CONFIG_FSL_DPAA_CHECKING + if (fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)) + return -EINVAL; +#endif + p = get_affine_portal(); + if (fq_isset(fq, QMAN_FQ_STATE_CHANGING) || + fq->state == qman_fq_state_retired || + fq->state == qman_fq_state_oos) { + ret = -EBUSY; + goto out; + } + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fq->fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + dev_crit(p->config->dev, "ALTER_RETIRE timeout\n"); + ret = -ETIMEDOUT; + goto out; + } + + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_RETIRE); + res = mcr->result; + /* + * "Elegant" would be to treat OK/PENDING the same way; set CHANGING, + * and defer the flags until FQRNI or FQRN (respectively) show up. But + * "Friendly" is to process OK immediately, and not set CHANGING. We do + * friendly, otherwise the caller doesn't necessarily have a fully + * "retired" FQ on return even if the retirement was immediate. However + * this does mean some code duplication between here and + * fq_state_change(). + */ + if (res == QM_MCR_RESULT_OK) { + ret = 0; + /* Process 'fq' right away, we'll ignore FQRNI */ + if (mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY) + fq_set(fq, QMAN_FQ_STATE_NE); + if (mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT) + fq_set(fq, QMAN_FQ_STATE_ORL); + if (flags) + *flags = fq->flags; + fq->state = qman_fq_state_retired; + if (fq->cb.fqs) { + /* + * Another issue with supporting "immediate" retirement + * is that we're forced to drop FQRNIs, because by the + * time they're seen it may already be "too late" (the + * fq may have been OOS'd and free()'d already). But if + * the upper layer wants a callback whether it's + * immediate or not, we have to fake a "MR" entry to + * look like an FQRNI... + */ + union qm_mr_entry msg; + + msg.verb = QM_MR_VERB_FQRNI; + msg.fq.fqs = mcr->alterfq.fqs; + msg.fq.fqid = fq->fqid; + msg.fq.contextB = fq_to_tag(fq); + fq->cb.fqs(p, fq, &msg); + } + } else if (res == QM_MCR_RESULT_PENDING) { + ret = 1; + fq_set(fq, QMAN_FQ_STATE_CHANGING); + } else { + ret = -EIO; + } +out: + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_retire_fq); + +int qman_oos_fq(struct qman_fq *fq) +{ + union qm_mc_command *mcc; + union qm_mc_result *mcr; + struct qman_portal *p; + int ret = 0; + + if (fq->state != qman_fq_state_retired) + return -EINVAL; +#ifdef CONFIG_FSL_DPAA_CHECKING + if (fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)) + return -EINVAL; +#endif + p = get_affine_portal(); + if (fq_isset(fq, QMAN_FQ_STATE_BLOCKOOS) || + fq->state != qman_fq_state_retired) { + ret = -EBUSY; + goto out; + } + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fq->fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + ret = -ETIMEDOUT; + goto out; + } + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_OOS); + if (mcr->result != QM_MCR_RESULT_OK) { + ret = -EIO; + goto out; + } + fq->state = qman_fq_state_oos; +out: + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_oos_fq); + +int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd) +{ + union qm_mc_command *mcc; + union qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + int ret = 0; + + mcc = qm_mc_start(&p->p); + mcc->queryfq.fqid = fq->fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + ret = -ETIMEDOUT; + goto out; + } + + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ); + if (mcr->result == QM_MCR_RESULT_OK) + *fqd = mcr->queryfq.fqd; + else + ret = -EIO; +out: + put_affine_portal(); + return ret; +} + +static int qman_query_fq_np(struct qman_fq *fq, + struct qm_mcr_queryfq_np *np) +{ + union qm_mc_command *mcc; + union qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + int ret = 0; + + mcc = qm_mc_start(&p->p); + mcc->queryfq.fqid = fq->fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + ret = -ETIMEDOUT; + goto out; + } + + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP); + if (mcr->result == QM_MCR_RESULT_OK) + *np = mcr->queryfq_np; + else if (mcr->result == QM_MCR_RESULT_ERR_FQID) + ret = -ERANGE; + else + ret = -EIO; +out: + put_affine_portal(); + return ret; +} + +static int qman_query_cgr(struct qman_cgr *cgr, + struct qm_mcr_querycgr *cgrd) +{ + union qm_mc_command *mcc; + union qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + int ret = 0; + + mcc = qm_mc_start(&p->p); + mcc->querycgr.cgid = cgr->cgrid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCGR); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + ret = -ETIMEDOUT; + goto out; + } + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYCGR); + if (mcr->result == QM_MCR_RESULT_OK) + *cgrd = mcr->querycgr; + else { + dev_err(p->config->dev, "QUERY_CGR failed: %s\n", + mcr_result_str(mcr->result)); + ret = -EIO; + } +out: + put_affine_portal(); + return ret; +} + +int qman_query_cgr_congested(struct qman_cgr *cgr, bool *result) +{ + struct qm_mcr_querycgr query_cgr; + int err; + + err = qman_query_cgr(cgr, &query_cgr); + if (err) + return err; + + *result = !!query_cgr.cgr.cs; + return 0; +} +EXPORT_SYMBOL(qman_query_cgr_congested); + +/* internal function used as a wait_event() expression */ +static int set_p_vdqcr(struct qman_portal *p, struct qman_fq *fq, u32 vdqcr) +{ + unsigned long irqflags; + int ret = -EBUSY; + + local_irq_save(irqflags); + if (p->vdqcr_owned) + goto out; + if (fq_isset(fq, QMAN_FQ_STATE_VDQCR)) + goto out; + + fq_set(fq, QMAN_FQ_STATE_VDQCR); + p->vdqcr_owned = fq; + qm_dqrr_vdqcr_set(&p->p, vdqcr); + ret = 0; +out: + local_irq_restore(irqflags); + return ret; +} + +static int set_vdqcr(struct qman_portal **p, struct qman_fq *fq, u32 vdqcr) +{ + int ret; + + *p = get_affine_portal(); + ret = set_p_vdqcr(*p, fq, vdqcr); + put_affine_portal(); + return ret; +} + +static int wait_vdqcr_start(struct qman_portal **p, struct qman_fq *fq, + u32 vdqcr, u32 flags) +{ + int ret = 0; + + if (flags & QMAN_VOLATILE_FLAG_WAIT_INT) + ret = wait_event_interruptible(affine_queue, + !set_vdqcr(p, fq, vdqcr)); + else + wait_event(affine_queue, !set_vdqcr(p, fq, vdqcr)); + return ret; +} + +int qman_volatile_dequeue(struct qman_fq *fq, u32 flags, u32 vdqcr) +{ + struct qman_portal *p; + int ret; + + if (fq->state != qman_fq_state_parked && + fq->state != qman_fq_state_retired) + return -EINVAL; + if (vdqcr & QM_VDQCR_FQID_MASK) + return -EINVAL; + if (fq_isset(fq, QMAN_FQ_STATE_VDQCR)) + return -EBUSY; + vdqcr = (vdqcr & ~QM_VDQCR_FQID_MASK) | fq->fqid; + if (flags & QMAN_VOLATILE_FLAG_WAIT) + ret = wait_vdqcr_start(&p, fq, vdqcr, flags); + else + ret = set_vdqcr(&p, fq, vdqcr); + if (ret) + return ret; + /* VDQCR is set */ + if (flags & QMAN_VOLATILE_FLAG_FINISH) { + if (flags & QMAN_VOLATILE_FLAG_WAIT_INT) + /* + * NB: don't propagate any error - the caller wouldn't + * know whether the VDQCR was issued or not. A signal + * could arrive after returning anyway, so the caller + * can check signal_pending() if that's an issue. + */ + wait_event_interruptible(affine_queue, + !fq_isset(fq, QMAN_FQ_STATE_VDQCR)); + else + wait_event(affine_queue, + !fq_isset(fq, QMAN_FQ_STATE_VDQCR)); + } + return 0; +} +EXPORT_SYMBOL(qman_volatile_dequeue); + +static void update_eqcr_ci(struct qman_portal *p, u8 avail) +{ + if (avail) + qm_eqcr_cce_prefetch(&p->p); + else + qm_eqcr_cce_update(&p->p); +} + +int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd) +{ + struct qman_portal *p; + struct qm_eqcr_entry *eq; + unsigned long irqflags; + u8 avail; + + p = get_affine_portal(); + local_irq_save(irqflags); + + if (p->use_eqcr_ci_stashing) { + /* + * The stashing case is easy, only update if we need to in + * order to try and liberate ring entries. + */ + eq = qm_eqcr_start_stash(&p->p); + } else { + /* + * The non-stashing case is harder, need to prefetch ahead of + * time. + */ + avail = qm_eqcr_get_avail(&p->p); + if (avail < 2) + update_eqcr_ci(p, avail); + eq = qm_eqcr_start_no_stash(&p->p); + } + + if (unlikely(!eq)) + goto out; + + eq->fqid = fq->fqid; + eq->tag = fq_to_tag(fq); + eq->fd = *fd; + + qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE); +out: + local_irq_restore(irqflags); + put_affine_portal(); + return 0; +} +EXPORT_SYMBOL(qman_enqueue); + +static int qm_modify_cgr(struct qman_cgr *cgr, u32 flags, + struct qm_mcc_initcgr *opts) +{ + union qm_mc_command *mcc; + union qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + u8 verb = QM_MCC_VERB_MODIFYCGR; + int ret = 0; + + mcc = qm_mc_start(&p->p); + if (opts) + mcc->initcgr = *opts; + mcc->initcgr.cgid = cgr->cgrid; + if (flags & QMAN_CGR_FLAG_USE_INIT) + verb = QM_MCC_VERB_INITCGR; + qm_mc_commit(&p->p, verb); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + ret = -ETIMEDOUT; + goto out; + } + + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == verb); + if (mcr->result != QM_MCR_RESULT_OK) + ret = -EIO; + +out: + put_affine_portal(); + return ret; +} + +#define PORTAL_IDX(n) (n->config->channel - QM_CHANNEL_SWPORTAL0) +#define TARG_MASK(n) (BIT(31) >> PORTAL_IDX(n)) + +static u8 qman_cgr_cpus[CGR_NUM]; + +void qman_init_cgr_all(void) +{ + struct qman_cgr cgr; + int err_cnt = 0; + + for (cgr.cgrid = 0; cgr.cgrid < CGR_NUM; cgr.cgrid++) { + if (qm_modify_cgr(&cgr, QMAN_CGR_FLAG_USE_INIT, NULL)) + err_cnt++; + } + + if (err_cnt) + pr_err("Warning: %d error%s while initialising CGR h/w\n", + err_cnt, (err_cnt > 1) ? "s" : ""); +} + +int qman_create_cgr(struct qman_cgr *cgr, u32 flags, + struct qm_mcc_initcgr *opts) +{ + struct qm_mcr_querycgr cgr_state; + struct qm_mcc_initcgr local_opts = {}; + int ret; + struct qman_portal *p; + + /* + * We have to check that the provided CGRID is within the limits of the + * data-structures, for obvious reasons. However we'll let h/w take + * care of determining whether it's within the limits of what exists on + * the SoC. + */ + if (cgr->cgrid >= CGR_NUM) + return -EINVAL; + + preempt_disable(); + p = get_affine_portal(); + qman_cgr_cpus[cgr->cgrid] = smp_processor_id(); + preempt_enable(); + + cgr->chan = p->config->channel; + spin_lock(&p->cgr_lock); + + if (opts) { + ret = qman_query_cgr(cgr, &cgr_state); + if (ret) + goto out; + if (opts) + local_opts = *opts; + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) + local_opts.cgr.cscn_targ_upd_ctrl = + QM_CGR_TARG_UDP_CTRL_WRITE_BIT | PORTAL_IDX(p); + else + /* Overwrite TARG */ + local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ | + TARG_MASK(p); + local_opts.we_mask |= QM_CGR_WE_CSCN_TARG; + + /* send init if flags indicate so */ + if (opts && (flags & QMAN_CGR_FLAG_USE_INIT)) + ret = qm_modify_cgr(cgr, QMAN_CGR_FLAG_USE_INIT, + &local_opts); + else + ret = qm_modify_cgr(cgr, 0, &local_opts); + if (ret) + goto out; + } + + list_add(&cgr->node, &p->cgr_cbs); + + /* Determine if newly added object requires its callback to be called */ + ret = qman_query_cgr(cgr, &cgr_state); + if (ret) { + /* we can't go back, so proceed and return success */ + dev_err(p->config->dev, "CGR HW state partially modified\n"); + ret = 0; + goto out; + } + if (cgr->cb && cgr_state.cgr.cscn_en && + qman_cgrs_get(&p->cgrs[1], cgr->cgrid)) + cgr->cb(p, cgr, 1); +out: + spin_unlock(&p->cgr_lock); + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_create_cgr); + +int qman_delete_cgr(struct qman_cgr *cgr) +{ + unsigned long irqflags; + struct qm_mcr_querycgr cgr_state; + struct qm_mcc_initcgr local_opts; + int ret = 0; + struct qman_cgr *i; + struct qman_portal *p = get_affine_portal(); + + if (cgr->chan != p->config->channel) { + /* attempt to delete from other portal than creator */ + dev_err(p->config->dev, "CGR not owned by current portal"); + dev_dbg(p->config->dev, " create 0x%x, delete 0x%x\n", + cgr->chan, p->config->channel); + + ret = -EINVAL; + goto put_portal; + } + memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr)); + spin_lock_irqsave(&p->cgr_lock, irqflags); + list_del(&cgr->node); + /* + * If there are no other CGR objects for this CGRID in the list, + * update CSCN_TARG accordingly + */ + list_for_each_entry(i, &p->cgr_cbs, node) + if (i->cgrid == cgr->cgrid && i->cb) + goto release_lock; + ret = qman_query_cgr(cgr, &cgr_state); + if (ret) { + /* add back to the list */ + list_add(&cgr->node, &p->cgr_cbs); + goto release_lock; + } + /* Overwrite TARG */ + local_opts.we_mask = QM_CGR_WE_CSCN_TARG; + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) + local_opts.cgr.cscn_targ_upd_ctrl = PORTAL_IDX(p); + else + local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ & + ~(TARG_MASK(p)); + ret = qm_modify_cgr(cgr, 0, &local_opts); + if (ret) + /* add back to the list */ + list_add(&cgr->node, &p->cgr_cbs); +release_lock: + spin_unlock_irqrestore(&p->cgr_lock, irqflags); +put_portal: + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_delete_cgr); + +struct cgr_comp { + struct qman_cgr *cgr; + struct completion completion; +}; + +static int qman_delete_cgr_thread(void *p) +{ + struct cgr_comp *cgr_comp = (struct cgr_comp *)p; + int ret; + + ret = qman_delete_cgr(cgr_comp->cgr); + complete(&cgr_comp->completion); + + return ret; +} + +void qman_delete_cgr_safe(struct qman_cgr *cgr) +{ + struct task_struct *thread; + struct cgr_comp cgr_comp; + + preempt_disable(); + if (qman_cgr_cpus[cgr->cgrid] != smp_processor_id()) { + init_completion(&cgr_comp.completion); + cgr_comp.cgr = cgr; + thread = kthread_create(qman_delete_cgr_thread, &cgr_comp, + "cgr_del"); + + if (IS_ERR(thread)) + goto out; + + kthread_bind(thread, qman_cgr_cpus[cgr->cgrid]); + wake_up_process(thread); + wait_for_completion(&cgr_comp.completion); + preempt_enable(); + return; + } +out: + qman_delete_cgr(cgr); + preempt_enable(); +} +EXPORT_SYMBOL(qman_delete_cgr_safe); + +/* Cleanup FQs */ + +static int _qm_mr_consume_and_match_verb(struct qm_portal *p, int v) +{ + const union qm_mr_entry *msg; + int found = 0; + + qm_mr_pvb_update(p); + msg = qm_mr_current(p); + while (msg) { + if ((msg->verb & QM_MR_VERB_TYPE_MASK) == v) + found = 1; + qm_mr_next(p); + qm_mr_cci_consume_to_current(p); + qm_mr_pvb_update(p); + msg = qm_mr_current(p); + } + return found; +} + +static int _qm_dqrr_consume_and_match(struct qm_portal *p, u32 fqid, int s, + bool wait) +{ + const struct qm_dqrr_entry *dqrr; + int found = 0; + + do { + qm_dqrr_pvb_update(p); + dqrr = qm_dqrr_current(p); + if (!dqrr) + cpu_relax(); + } while (wait && !dqrr); + + while (dqrr) { + if (dqrr->fqid == fqid && (dqrr->stat & s)) + found = 1; + qm_dqrr_cdc_consume_1ptr(p, dqrr, 0); + qm_dqrr_pvb_update(p); + qm_dqrr_next(p); + dqrr = qm_dqrr_current(p); + } + return found; +} + +#define qm_mr_drain(p, V) \ + _qm_mr_consume_and_match_verb(p, QM_MR_VERB_##V) + +#define qm_dqrr_drain(p, f, S) \ + _qm_dqrr_consume_and_match(p, f, QM_DQRR_STAT_##S, false) + +#define qm_dqrr_drain_wait(p, f, S) \ + _qm_dqrr_consume_and_match(p, f, QM_DQRR_STAT_##S, true) + +#define qm_dqrr_drain_nomatch(p) \ + _qm_dqrr_consume_and_match(p, 0, 0, false) + +static int qman_shutdown_fq(u32 fqid) +{ + struct qman_portal *p; + struct device *dev; + union qm_mc_command *mcc; + union qm_mc_result *mcr; + int orl_empty, drain = 0, ret = 0; + u32 channel, wq, res; + u8 state; + + p = get_affine_portal(); + dev = p->config->dev; + /* Determine the state of the FQID */ + mcc = qm_mc_start(&p->p); + mcc->queryfq_np.fqid = fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + dev_err(dev, "QUERYFQ_NP timeout\n"); + ret = -ETIMEDOUT; + goto out; + } + + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP); + state = mcr->queryfq_np.state & QM_MCR_NP_STATE_MASK; + if (state == QM_MCR_NP_STATE_OOS) + goto out; /* Already OOS, no need to do anymore checks */ + + /* Query which channel the FQ is using */ + mcc = qm_mc_start(&p->p); + mcc->queryfq.fqid = fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + dev_err(dev, "QUERYFQ timeout\n"); + ret = -ETIMEDOUT; + goto out; + } + + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ); + /* Need to store these since the MCR gets reused */ + channel = qm_fqd_get_chan(&mcr->queryfq.fqd); + wq = qm_fqd_get_wq(&mcr->queryfq.fqd); + + switch (state) { + case QM_MCR_NP_STATE_TEN_SCHED: + case QM_MCR_NP_STATE_TRU_SCHED: + case QM_MCR_NP_STATE_ACTIVE: + case QM_MCR_NP_STATE_PARKED: + orl_empty = 0; + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + dev_err(dev, "QUERYFQ_NP timeout\n"); + ret = -ETIMEDOUT; + goto out; + } + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == + QM_MCR_VERB_ALTER_RETIRE); + res = mcr->result; /* Make a copy as we reuse MCR below */ + + if (res == QM_MCR_RESULT_PENDING) { + /* + * Need to wait for the FQRN in the message ring, which + * will only occur once the FQ has been drained. In + * order for the FQ to drain the portal needs to be set + * to dequeue from the channel the FQ is scheduled on + */ + int found_fqrn = 0; + u16 dequeue_wq = 0; + + /* Flag that we need to drain FQ */ + drain = 1; + + if (channel >= qm_channel_pool1 && + channel < qm_channel_pool1 + 15) { + /* Pool channel, enable the bit in the portal */ + dequeue_wq = (channel - + qm_channel_pool1 + 1)<<4 | wq; + } else if (channel < qm_channel_pool1) { + /* Dedicated channel */ + dequeue_wq = wq; + } else { + dev_err(dev, "Can't recover FQ 0x%x, ch: 0x%x", + fqid, channel); + ret = -EBUSY; + goto out; + } + /* Set the sdqcr to drain this channel */ + if (channel < qm_channel_pool1) + qm_dqrr_sdqcr_set(&p->p, + QM_SDQCR_TYPE_ACTIVE | + QM_SDQCR_CHANNELS_DEDICATED); + else + qm_dqrr_sdqcr_set(&p->p, + QM_SDQCR_TYPE_ACTIVE | + QM_SDQCR_CHANNELS_POOL_CONV + (channel)); + do { + /* Keep draining DQRR while checking the MR*/ + qm_dqrr_drain_nomatch(&p->p); + /* Process message ring too */ + found_fqrn = qm_mr_drain(&p->p, FQRN); + cpu_relax(); + } while (!found_fqrn); + + } + if (res != QM_MCR_RESULT_OK && + res != QM_MCR_RESULT_PENDING) { + dev_err(dev, "retire_fq failed: FQ 0x%x, res=0x%x\n", + fqid, res); + ret = -EIO; + goto out; + } + if (!(mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT)) { + /* + * ORL had no entries, no need to wait until the + * ERNs come in + */ + orl_empty = 1; + } + /* + * Retirement succeeded, check to see if FQ needs + * to be drained + */ + if (drain || mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY) { + /* FQ is Not Empty, drain using volatile DQ commands */ + do { + u32 vdqcr = fqid | QM_VDQCR_NUMFRAMES_SET(3); + + qm_dqrr_vdqcr_set(&p->p, vdqcr); + /* + * Wait for a dequeue and process the dequeues, + * making sure to empty the ring completely + */ + } while (qm_dqrr_drain_wait(&p->p, fqid, FQ_EMPTY)); + } + qm_dqrr_sdqcr_set(&p->p, 0); + + while (!orl_empty) { + /* Wait for the ORL to have been completely drained */ + orl_empty = qm_mr_drain(&p->p, FQRL); + cpu_relax(); + } + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + ret = -ETIMEDOUT; + goto out; + } + + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == + QM_MCR_VERB_ALTER_OOS); + if (mcr->result != QM_MCR_RESULT_OK) { + dev_err(dev, "OOS after drain fail: FQ 0x%x (0x%x)\n", + fqid, mcr->result); + ret = -EIO; + goto out; + } + break; + + case QM_MCR_NP_STATE_RETIRED: + /* Send OOS Command */ + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); + if (!qm_mc_result_timeout(&p->p, &mcr)) { + ret = -ETIMEDOUT; + goto out; + } + + DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == + QM_MCR_VERB_ALTER_OOS); + if (mcr->result) { + dev_err(dev, "OOS fail: FQ 0x%x (0x%x)\n", + fqid, mcr->result); + ret = -EIO; + goto out; + } + break; + + case QM_MCR_NP_STATE_OOS: + /* Done */ + break; + + default: + ret = -EIO; + } + +out: + put_affine_portal(); + return ret; +} + +const struct qm_portal_config *qman_get_qm_portal_config( + struct qman_portal *portal) +{ + return portal->config; +} + +struct gen_pool *qm_fqalloc; /* FQID allocator */ +struct gen_pool *qm_qpalloc; /* pool-channel allocator */ +struct gen_pool *qm_cgralloc; /* CGR ID allocator */ + +static int qman_alloc_range(struct gen_pool *p, u32 *result, u32 cnt) +{ + unsigned long addr; + + addr = gen_pool_alloc(p, cnt); + if (!addr) + return -ENOMEM; + + *result = addr & ~DPAA_GENALLOC_OFF; + + return 0; +} + +int qman_alloc_fqid_range(u32 *result, u32 count) +{ + return qman_alloc_range(qm_fqalloc, result, count); +} +EXPORT_SYMBOL(qman_alloc_fqid_range); + +int qman_alloc_pool_range(u32 *result, u32 count) +{ + return qman_alloc_range(qm_qpalloc, result, count); +} +EXPORT_SYMBOL(qman_alloc_pool_range); + +int qman_alloc_cgrid_range(u32 *result, u32 count) +{ + return qman_alloc_range(qm_cgralloc, result, count); +} +EXPORT_SYMBOL(qman_alloc_cgrid_range); + +int qman_release_fqid(u32 fqid) +{ + int ret = qman_shutdown_fq(fqid); + + if (ret) { + pr_debug("FQID %d leaked\n", fqid); + return ret; + } + + gen_pool_free(qm_fqalloc, fqid | DPAA_GENALLOC_OFF, 1); + return 0; +} +EXPORT_SYMBOL(qman_release_fqid); + +static int qpool_cleanup(u32 qp) +{ + /* + * We query all FQDs starting from + * FQID 1 until we get an "invalid FQID" error, looking for non-OOS FQDs + * whose destination channel is the pool-channel being released. + * When a non-OOS FQD is found we attempt to clean it up + */ + struct qman_fq fq = { + .fqid = QM_FQID_RANGE_START + }; + int err; + + do { + struct qm_mcr_queryfq_np np; + + err = qman_query_fq_np(&fq, &np); + if (err) + /* FQID range exceeded, found no problems */ + return 0; + if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) { + struct qm_fqd fqd; + + err = qman_query_fq(&fq, &fqd); + if (WARN_ON(err)) + return 0; + if (qm_fqd_get_chan(&fqd) == qp) { + /* The channel is the FQ's target, clean it */ + err = qman_shutdown_fq(fq.fqid); + if (err) + /* + * Couldn't shut down the FQ + * so the pool must be leaked + */ + return err; + } + } + /* Move to the next FQID */ + fq.fqid++; + } while (1); +} + +int qman_release_pool(u32 qp) +{ + int ret; + + ret = qpool_cleanup(qp); + if (ret) { + pr_debug("CHID %d leaked\n", qp); + return ret; + } + + gen_pool_free(qm_qpalloc, qp | DPAA_GENALLOC_OFF, 1); + return 0; +} +EXPORT_SYMBOL(qman_release_pool); + +static int cgr_cleanup(u32 cgrid) +{ + /* + * query all FQDs starting from FQID 1 until we get an "invalid FQID" + * error, looking for non-OOS FQDs whose CGR is the CGR being released + */ + struct qman_fq fq = { + .fqid = 1 + }; + int err; + + do { + struct qm_mcr_queryfq_np np; + + err = qman_query_fq_np(&fq, &np); + if (err) + /* FQID range exceeded, found no problems */ + return 0; + if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) { + struct qm_fqd fqd; + + err = qman_query_fq(&fq, &fqd); + if (WARN_ON(err)) + return 0; + if ((fqd.fq_ctrl & QM_FQCTRL_CGE) && + fqd.cgid == cgrid) { + pr_err("CRGID 0x%x is being used by FQID 0x%x, CGR will be leaked\n", + cgrid, fq.fqid); + return -EIO; + } + } + /* Move to the next FQID */ + fq.fqid++; + } while (1); +} + +int qman_release_cgrid(u32 cgrid) +{ + int ret; + + ret = cgr_cleanup(cgrid); + if (ret) { + pr_debug("CGRID %d leaked\n", cgrid); + return ret; + } + + gen_pool_free(qm_cgralloc, cgrid | DPAA_GENALLOC_OFF, 1); + return 0; +} +EXPORT_SYMBOL(qman_release_cgrid); diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c new file mode 100644 index 0000000000000..0cace9e0077e0 --- /dev/null +++ b/drivers/soc/fsl/qbman/qman_ccsr.c @@ -0,0 +1,808 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_priv.h" + +u16 qman_ip_rev; +EXPORT_SYMBOL(qman_ip_rev); +u16 qm_channel_pool1 = QMAN_CHANNEL_POOL1; +EXPORT_SYMBOL(qm_channel_pool1); + +/* Register offsets */ +#define REG_QCSP_LIO_CFG(n) (0x0000 + ((n) * 0x10)) +#define REG_QCSP_IO_CFG(n) (0x0004 + ((n) * 0x10)) +#define REG_QCSP_DD_CFG(n) (0x000c + ((n) * 0x10)) +#define REG_DD_CFG 0x0200 +#define REG_DCP_CFG(n) (0x0300 + ((n) * 0x10)) +#define REG_DCP_DD_CFG(n) (0x0304 + ((n) * 0x10)) +#define REG_DCP_DLM_AVG(n) (0x030c + ((n) * 0x10)) +#define REG_PFDR_FPC 0x0400 +#define REG_PFDR_FP_HEAD 0x0404 +#define REG_PFDR_FP_TAIL 0x0408 +#define REG_PFDR_FP_LWIT 0x0410 +#define REG_PFDR_CFG 0x0414 +#define REG_SFDR_CFG 0x0500 +#define REG_SFDR_IN_USE 0x0504 +#define REG_WQ_CS_CFG(n) (0x0600 + ((n) * 0x04)) +#define REG_WQ_DEF_ENC_WQID 0x0630 +#define REG_WQ_SC_DD_CFG(n) (0x640 + ((n) * 0x04)) +#define REG_WQ_PC_DD_CFG(n) (0x680 + ((n) * 0x04)) +#define REG_WQ_DC0_DD_CFG(n) (0x6c0 + ((n) * 0x04)) +#define REG_WQ_DC1_DD_CFG(n) (0x700 + ((n) * 0x04)) +#define REG_WQ_DCn_DD_CFG(n) (0x6c0 + ((n) * 0x40)) /* n=2,3 */ +#define REG_CM_CFG 0x0800 +#define REG_ECSR 0x0a00 +#define REG_ECIR 0x0a04 +#define REG_EADR 0x0a08 +#define REG_ECIR2 0x0a0c +#define REG_EDATA(n) (0x0a10 + ((n) * 0x04)) +#define REG_SBEC(n) (0x0a80 + ((n) * 0x04)) +#define REG_MCR 0x0b00 +#define REG_MCP(n) (0x0b04 + ((n) * 0x04)) +#define REG_MISC_CFG 0x0be0 +#define REG_HID_CFG 0x0bf0 +#define REG_IDLE_STAT 0x0bf4 +#define REG_IP_REV_1 0x0bf8 +#define REG_IP_REV_2 0x0bfc +#define REG_FQD_BARE 0x0c00 +#define REG_PFDR_BARE 0x0c20 +#define REG_offset_BAR 0x0004 /* relative to REG_[FQD|PFDR]_BARE */ +#define REG_offset_AR 0x0010 /* relative to REG_[FQD|PFDR]_BARE */ +#define REG_QCSP_BARE 0x0c80 +#define REG_QCSP_BAR 0x0c84 +#define REG_CI_SCHED_CFG 0x0d00 +#define REG_SRCIDR 0x0d04 +#define REG_LIODNR 0x0d08 +#define REG_CI_RLM_AVG 0x0d14 +#define REG_ERR_ISR 0x0e00 +#define REG_ERR_IER 0x0e04 +#define REG_REV3_QCSP_LIO_CFG(n) (0x1000 + ((n) * 0x10)) +#define REG_REV3_QCSP_IO_CFG(n) (0x1004 + ((n) * 0x10)) +#define REG_REV3_QCSP_DD_CFG(n) (0x100c + ((n) * 0x10)) + +/* Assists for QMAN_MCR */ +#define MCR_INIT_PFDR 0x01000000 +#define MCR_get_rslt(v) (u8)((v) >> 24) +#define MCR_rslt_idle(r) (!(r) || ((r) >= 0xf0)) +#define MCR_rslt_ok(r) ((r) == 0xf0) +#define MCR_rslt_eaccess(r) ((r) == 0xf8) +#define MCR_rslt_inval(r) ((r) == 0xff) + +/* + * Corenet initiator settings. Stash request queues are 4-deep to match cores + * ability to snarf. Stash priority is 3, other priorities are 2. + */ +#define QM_CI_SCHED_CFG_SRCCIV 4 +#define QM_CI_SCHED_CFG_SRQ_W 3 +#define QM_CI_SCHED_CFG_RW_W 2 +#define QM_CI_SCHED_CFG_BMAN_W 2 +/* write SRCCIV enable */ +#define QM_CI_SCHED_CFG_SRCCIV_EN BIT(31) + +/* Follows WQ_CS_CFG0-5 */ +enum qm_wq_class { + qm_wq_portal = 0, + qm_wq_pool = 1, + qm_wq_fman0 = 2, + qm_wq_fman1 = 3, + qm_wq_caam = 4, + qm_wq_pme = 5, + qm_wq_first = qm_wq_portal, + qm_wq_last = qm_wq_pme +}; + +/* Follows FQD_[BARE|BAR|AR] and PFDR_[BARE|BAR|AR] */ +enum qm_memory { + qm_memory_fqd, + qm_memory_pfdr +}; + +/* Used by all error interrupt registers except 'inhibit' */ +#define QM_EIRQ_CIDE 0x20000000 /* Corenet Initiator Data Error */ +#define QM_EIRQ_CTDE 0x10000000 /* Corenet Target Data Error */ +#define QM_EIRQ_CITT 0x08000000 /* Corenet Invalid Target Transaction */ +#define QM_EIRQ_PLWI 0x04000000 /* PFDR Low Watermark */ +#define QM_EIRQ_MBEI 0x02000000 /* Multi-bit ECC Error */ +#define QM_EIRQ_SBEI 0x01000000 /* Single-bit ECC Error */ +#define QM_EIRQ_PEBI 0x00800000 /* PFDR Enqueues Blocked Interrupt */ +#define QM_EIRQ_IFSI 0x00020000 /* Invalid FQ Flow Control State */ +#define QM_EIRQ_ICVI 0x00010000 /* Invalid Command Verb */ +#define QM_EIRQ_IDDI 0x00000800 /* Invalid Dequeue (Direct-connect) */ +#define QM_EIRQ_IDFI 0x00000400 /* Invalid Dequeue FQ */ +#define QM_EIRQ_IDSI 0x00000200 /* Invalid Dequeue Source */ +#define QM_EIRQ_IDQI 0x00000100 /* Invalid Dequeue Queue */ +#define QM_EIRQ_IECE 0x00000010 /* Invalid Enqueue Configuration */ +#define QM_EIRQ_IEOI 0x00000008 /* Invalid Enqueue Overflow */ +#define QM_EIRQ_IESI 0x00000004 /* Invalid Enqueue State */ +#define QM_EIRQ_IECI 0x00000002 /* Invalid Enqueue Channel */ +#define QM_EIRQ_IEQI 0x00000001 /* Invalid Enqueue Queue */ + +/* QMAN_ECIR valid error bit */ +#define PORTAL_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IESI | QM_EIRQ_IEOI | \ + QM_EIRQ_IDQI | QM_EIRQ_IDSI | QM_EIRQ_IDFI | \ + QM_EIRQ_IDDI | QM_EIRQ_ICVI | QM_EIRQ_IFSI) +#define FQID_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IECI | QM_EIRQ_IESI | \ + QM_EIRQ_IEOI | QM_EIRQ_IDQI | QM_EIRQ_IDFI | \ + QM_EIRQ_IFSI) + +struct qm_ecir { + u32 info; /* res[30-31], ptyp[29], pnum[24-28], fqid[0-23] */ +}; + +static bool qm_ecir_is_dcp(const struct qm_ecir *p) +{ + return p->info & BIT(29); +} + +static int qm_ecir_get_pnum(const struct qm_ecir *p) +{ + return (p->info >> 24) & 0x1f; +} + +static int qm_ecir_get_fqid(const struct qm_ecir *p) +{ + return p->info & (BIT(24) - 1); +} + +struct qm_ecir2 { + u32 info; /* ptyp[31], res[10-30], pnum[0-9] */ +}; + +static bool qm_ecir2_is_dcp(const struct qm_ecir2 *p) +{ + return p->info & BIT(31); +} + +static int qm_ecir2_get_pnum(const struct qm_ecir2 *p) +{ + return p->info & (BIT(10) - 1); +} + +struct qm_eadr { + u32 info; /* memid[24-27], eadr[0-11] */ + /* v3: memid[24-28], eadr[0-15] */ +}; + +static int qm_eadr_get_memid(const struct qm_eadr *p) +{ + return (p->info >> 24) & 0xf; +} + +static int qm_eadr_get_eadr(const struct qm_eadr *p) +{ + return p->info & (BIT(12) - 1); +} + +static int qm_eadr_v3_get_memid(const struct qm_eadr *p) +{ + return (p->info >> 24) & 0x1f; +} + +static int qm_eadr_v3_get_eadr(const struct qm_eadr *p) +{ + return p->info & (BIT(16) - 1); +} + +struct qman_hwerr_txt { + u32 mask; + const char *txt; +}; + + +static const struct qman_hwerr_txt qman_hwerr_txts[] = { + { QM_EIRQ_CIDE, "Corenet Initiator Data Error" }, + { QM_EIRQ_CTDE, "Corenet Target Data Error" }, + { QM_EIRQ_CITT, "Corenet Invalid Target Transaction" }, + { QM_EIRQ_PLWI, "PFDR Low Watermark" }, + { QM_EIRQ_MBEI, "Multi-bit ECC Error" }, + { QM_EIRQ_SBEI, "Single-bit ECC Error" }, + { QM_EIRQ_PEBI, "PFDR Enqueues Blocked Interrupt" }, + { QM_EIRQ_ICVI, "Invalid Command Verb" }, + { QM_EIRQ_IFSI, "Invalid Flow Control State" }, + { QM_EIRQ_IDDI, "Invalid Dequeue (Direct-connect)" }, + { QM_EIRQ_IDFI, "Invalid Dequeue FQ" }, + { QM_EIRQ_IDSI, "Invalid Dequeue Source" }, + { QM_EIRQ_IDQI, "Invalid Dequeue Queue" }, + { QM_EIRQ_IECE, "Invalid Enqueue Configuration" }, + { QM_EIRQ_IEOI, "Invalid Enqueue Overflow" }, + { QM_EIRQ_IESI, "Invalid Enqueue State" }, + { QM_EIRQ_IECI, "Invalid Enqueue Channel" }, + { QM_EIRQ_IEQI, "Invalid Enqueue Queue" }, +}; + +struct qman_error_info_mdata { + u16 addr_mask; + u16 bits; + const char *txt; +}; + +static const struct qman_error_info_mdata error_mdata[] = { + { 0x01FF, 24, "FQD cache tag memory 0" }, + { 0x01FF, 24, "FQD cache tag memory 1" }, + { 0x01FF, 24, "FQD cache tag memory 2" }, + { 0x01FF, 24, "FQD cache tag memory 3" }, + { 0x0FFF, 512, "FQD cache memory" }, + { 0x07FF, 128, "SFDR memory" }, + { 0x01FF, 72, "WQ context memory" }, + { 0x00FF, 240, "CGR memory" }, + { 0x00FF, 302, "Internal Order Restoration List memory" }, + { 0x01FF, 256, "SW portal ring memory" }, +}; + +#define QMAN_ERRS_TO_DISABLE (QM_EIRQ_PLWI | QM_EIRQ_PEBI) + +/* + * TODO: unimplemented registers + * + * Keeping a list here of QMan registers I have not yet covered; + * QCSP_DD_IHRSR, QCSP_DD_IHRFR, QCSP_DD_HASR, + * DCP_DD_IHRSR, DCP_DD_IHRFR, DCP_DD_HASR, CM_CFG, + * QMAN_EECC, QMAN_SBET, QMAN_EINJ, QMAN_SBEC0-12 + */ + +/* Pointer to the start of the QMan's CCSR space */ +static u32 __iomem *qm_ccsr_start; +/* A SDQCR mask comprising all the available/visible pool channels */ +static u32 qm_pools_sdqcr; + +static inline u32 qm_ccsr_in(u32 offset) +{ + return ioread32be(qm_ccsr_start + offset/4); +} + +static inline void qm_ccsr_out(u32 offset, u32 val) +{ + iowrite32be(val, qm_ccsr_start + offset/4); +} + +u32 qm_get_pools_sdqcr(void) +{ + return qm_pools_sdqcr; +} + +enum qm_dc_portal { + qm_dc_portal_fman0 = 0, + qm_dc_portal_fman1 = 1 +}; + +static void qm_set_dc(enum qm_dc_portal portal, int ed, u8 sernd) +{ + DPAA_ASSERT(!ed || portal == qm_dc_portal_fman0 || + portal == qm_dc_portal_fman1); + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) + qm_ccsr_out(REG_DCP_CFG(portal), + (ed ? 0x1000 : 0) | (sernd & 0x3ff)); + else + qm_ccsr_out(REG_DCP_CFG(portal), + (ed ? 0x100 : 0) | (sernd & 0x1f)); +} + +static void qm_set_wq_scheduling(enum qm_wq_class wq_class, + u8 cs_elev, u8 csw2, u8 csw3, u8 csw4, + u8 csw5, u8 csw6, u8 csw7) +{ + qm_ccsr_out(REG_WQ_CS_CFG(wq_class), ((cs_elev & 0xff) << 24) | + ((csw2 & 0x7) << 20) | ((csw3 & 0x7) << 16) | + ((csw4 & 0x7) << 12) | ((csw5 & 0x7) << 8) | + ((csw6 & 0x7) << 4) | (csw7 & 0x7)); +} + +static void qm_set_hid(void) +{ + qm_ccsr_out(REG_HID_CFG, 0); +} + +static void qm_set_corenet_initiator(void) +{ + qm_ccsr_out(REG_CI_SCHED_CFG, QM_CI_SCHED_CFG_SRCCIV_EN | + (QM_CI_SCHED_CFG_SRCCIV << 24) | + (QM_CI_SCHED_CFG_SRQ_W << 8) | + (QM_CI_SCHED_CFG_RW_W << 4) | + QM_CI_SCHED_CFG_BMAN_W); +} + +static void qm_get_version(u16 *id, u8 *major, u8 *minor) +{ + u32 v = qm_ccsr_in(REG_IP_REV_1); + *id = (v >> 16); + *major = (v >> 8) & 0xff; + *minor = v & 0xff; +} + +#define PFDR_AR_EN BIT(31) +static void qm_set_memory(enum qm_memory memory, u64 ba, u32 size) +{ + u32 offset = (memory == qm_memory_fqd) ? REG_FQD_BARE : REG_PFDR_BARE; + u32 exp = ilog2(size); + + /* choke if size isn't within range */ + DPAA_ASSERT((size >= 4096) && (size <= 1024*1024*1024) && + is_power_of_2(size)); + /* choke if 'ba' has lower-alignment than 'size' */ + DPAA_ASSERT(!(ba & (size - 1))); + qm_ccsr_out(offset, upper_32_bits(ba)); + qm_ccsr_out(offset + REG_offset_BAR, lower_32_bits(ba)); + qm_ccsr_out(offset + REG_offset_AR, PFDR_AR_EN | (exp - 1)); +} + +static void qm_set_pfdr_threshold(u32 th, u8 k) +{ + qm_ccsr_out(REG_PFDR_FP_LWIT, th & 0xffffff); + qm_ccsr_out(REG_PFDR_CFG, k); +} + +static void qm_set_sfdr_threshold(u16 th) +{ + qm_ccsr_out(REG_SFDR_CFG, th & 0x3ff); +} + +static int qm_init_pfdr(struct device *dev, u32 pfdr_start, u32 num) +{ + u8 rslt = MCR_get_rslt(qm_ccsr_in(REG_MCR)); + + DPAA_ASSERT(pfdr_start && !(pfdr_start & 7) && !(num & 7) && num); + /* Make sure the command interface is 'idle' */ + if (!MCR_rslt_idle(rslt)) { + dev_crit(dev, "QMAN_MCR isn't idle"); + WARN_ON(1); + } + + /* Write the MCR command params then the verb */ + qm_ccsr_out(REG_MCP(0), pfdr_start); + /* + * TODO: remove this - it's a workaround for a model bug that is + * corrected in more recent versions. We use the workaround until + * everyone has upgraded. + */ + qm_ccsr_out(REG_MCP(1), pfdr_start + num - 16); + dma_wmb(); + qm_ccsr_out(REG_MCR, MCR_INIT_PFDR); + /* Poll for the result */ + do { + rslt = MCR_get_rslt(qm_ccsr_in(REG_MCR)); + } while (!MCR_rslt_idle(rslt)); + if (MCR_rslt_ok(rslt)) + return 0; + if (MCR_rslt_eaccess(rslt)) + return -EACCES; + if (MCR_rslt_inval(rslt)) + return -EINVAL; + dev_crit(dev, "Unexpected result from MCR_INIT_PFDR: %02x\n", rslt); + return -ENODEV; +} + +/* + * Ideally we would use the DMA API to turn rmem->base into a DMA address + * (especially if iommu translations ever get involved). Unfortunately, the + * DMA API currently does not allow mapping anything that is not backed with + * a struct page. + */ +static dma_addr_t fqd_a, pfdr_a; +static size_t fqd_sz, pfdr_sz; + +static int qman_fqd(struct reserved_mem *rmem) +{ + fqd_a = rmem->base; + fqd_sz = rmem->size; + + WARN_ON(!(fqd_a && fqd_sz)); + + return 0; +} +RESERVEDMEM_OF_DECLARE(qman_fqd, "fsl,qman-fqd", qman_fqd); + +static int qman_pfdr(struct reserved_mem *rmem) +{ + pfdr_a = rmem->base; + pfdr_sz = rmem->size; + + WARN_ON(!(pfdr_a && pfdr_sz)); + + return 0; +} +RESERVEDMEM_OF_DECLARE(qman_pfdr, "fsl,qman-pfdr", qman_pfdr); + +static unsigned int qm_get_fqid_maxcnt(void) +{ + return fqd_sz / 64; +} + +/* + * Flush this memory range from data cache so that QMAN originated + * transactions for this memory region could be marked non-coherent. + */ +static int zero_priv_mem(struct device *dev, struct device_node *node, + phys_addr_t addr, size_t sz) +{ + /* map as cacheable, non-guarded */ + void __iomem *tmpp = ioremap_prot(addr, sz, 0); + + memset_io(tmpp, 0, sz); + flush_dcache_range((unsigned long)tmpp, + (unsigned long)tmpp + sz); + iounmap(tmpp); + + return 0; +} + +static void log_edata_bits(struct device *dev, u32 bit_count) +{ + u32 i, j, mask = 0xffffffff; + + dev_warn(dev, "ErrInt, EDATA:\n"); + i = bit_count / 32; + if (bit_count % 32) { + i++; + mask = ~(mask << bit_count % 32); + } + j = 16 - i; + dev_warn(dev, " 0x%08x\n", qm_ccsr_in(REG_EDATA(j)) & mask); + j++; + for (; j < 16; j++) + dev_warn(dev, " 0x%08x\n", qm_ccsr_in(REG_EDATA(j))); +} + +static void log_additional_error_info(struct device *dev, u32 isr_val, + u32 ecsr_val) +{ + struct qm_ecir ecir_val; + struct qm_eadr eadr_val; + int memid; + + ecir_val.info = qm_ccsr_in(REG_ECIR); + /* Is portal info valid */ + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) { + struct qm_ecir2 ecir2_val; + + ecir2_val.info = qm_ccsr_in(REG_ECIR2); + if (ecsr_val & PORTAL_ECSR_ERR) { + dev_warn(dev, "ErrInt: %s id %d\n", + qm_ecir2_is_dcp(&ecir2_val) ? "DCP" : "SWP", + qm_ecir2_get_pnum(&ecir2_val)); + } + if (ecsr_val & (FQID_ECSR_ERR | QM_EIRQ_IECE)) + dev_warn(dev, "ErrInt: ecir.fqid 0x%x\n", + qm_ecir_get_fqid(&ecir_val)); + + if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) { + eadr_val.info = qm_ccsr_in(REG_EADR); + memid = qm_eadr_v3_get_memid(&eadr_val); + dev_warn(dev, "ErrInt: EADR Memory: %s, 0x%x\n", + error_mdata[memid].txt, + error_mdata[memid].addr_mask + & qm_eadr_v3_get_eadr(&eadr_val)); + log_edata_bits(dev, error_mdata[memid].bits); + } + } else { + if (ecsr_val & PORTAL_ECSR_ERR) { + dev_warn(dev, "ErrInt: %s id %d\n", + qm_ecir_is_dcp(&ecir_val) ? "DCP" : "SWP", + qm_ecir_get_pnum(&ecir_val)); + } + if (ecsr_val & FQID_ECSR_ERR) + dev_warn(dev, "ErrInt: ecir.fqid 0x%x\n", + qm_ecir_get_fqid(&ecir_val)); + + if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) { + eadr_val.info = qm_ccsr_in(REG_EADR); + memid = qm_eadr_get_memid(&eadr_val); + dev_warn(dev, "ErrInt: EADR Memory: %s, 0x%x\n", + error_mdata[memid].txt, + error_mdata[memid].addr_mask + & qm_eadr_get_eadr(&eadr_val)); + log_edata_bits(dev, error_mdata[memid].bits); + } + } +} + +static irqreturn_t qman_isr(int irq, void *ptr) +{ + u32 isr_val, ier_val, ecsr_val, isr_mask, i; + struct device *dev = ptr; + + ier_val = qm_ccsr_in(REG_ERR_IER); + isr_val = qm_ccsr_in(REG_ERR_ISR); + ecsr_val = qm_ccsr_in(REG_ECSR); + isr_mask = isr_val & ier_val; + + if (!isr_mask) + return IRQ_NONE; + + for (i = 0; i < ARRAY_SIZE(qman_hwerr_txts); i++) { + if (qman_hwerr_txts[i].mask & isr_mask) { + dev_err_ratelimited(dev, "ErrInt: %s\n", + qman_hwerr_txts[i].txt); + if (qman_hwerr_txts[i].mask & ecsr_val) { + log_additional_error_info(dev, isr_mask, + ecsr_val); + /* Re-arm error capture registers */ + qm_ccsr_out(REG_ECSR, ecsr_val); + } + if (qman_hwerr_txts[i].mask & QMAN_ERRS_TO_DISABLE) { + dev_dbg(dev, "Disabling error 0x%x\n", + qman_hwerr_txts[i].mask); + ier_val &= ~qman_hwerr_txts[i].mask; + qm_ccsr_out(REG_ERR_IER, ier_val); + } + } + } + qm_ccsr_out(REG_ERR_ISR, isr_val); + + return IRQ_HANDLED; +} + +static int qman_init_ccsr(struct device *dev) +{ + int i, err; + + /* FQD memory */ + qm_set_memory(qm_memory_fqd, fqd_a, fqd_sz); + /* PFDR memory */ + qm_set_memory(qm_memory_pfdr, pfdr_a, pfdr_sz); + err = qm_init_pfdr(dev, 8, pfdr_sz / 64 - 8); + if (err) + return err; + /* thresholds */ + qm_set_pfdr_threshold(512, 64); + qm_set_sfdr_threshold(128); + /* clear stale PEBI bit from interrupt status register */ + qm_ccsr_out(REG_ERR_ISR, QM_EIRQ_PEBI); + /* corenet initiator settings */ + qm_set_corenet_initiator(); + /* HID settings */ + qm_set_hid(); + /* Set scheduling weights to defaults */ + for (i = qm_wq_first; i <= qm_wq_last; i++) + qm_set_wq_scheduling(i, 0, 0, 0, 0, 0, 0, 0); + /* We are not prepared to accept ERNs for hardware enqueues */ + qm_set_dc(qm_dc_portal_fman0, 1, 0); + qm_set_dc(qm_dc_portal_fman1, 1, 0); + return 0; +} + +#define LIO_CFG_LIODN_MASK 0x0fff0000 +void qman_liodn_fixup(u16 channel) +{ + static int done; + static u32 liodn_offset; + u32 before, after; + int idx = channel - QM_CHANNEL_SWPORTAL0; + + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) + before = qm_ccsr_in(REG_REV3_QCSP_LIO_CFG(idx)); + else + before = qm_ccsr_in(REG_QCSP_LIO_CFG(idx)); + if (!done) { + liodn_offset = before & LIO_CFG_LIODN_MASK; + done = 1; + return; + } + after = (before & (~LIO_CFG_LIODN_MASK)) | liodn_offset; + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) + qm_ccsr_out(REG_REV3_QCSP_LIO_CFG(idx), after); + else + qm_ccsr_out(REG_QCSP_LIO_CFG(idx), after); +} + +#define IO_CFG_SDEST_MASK 0x00ff0000 +void qman_set_sdest(u16 channel, unsigned int cpu_idx) +{ + int idx = channel - QM_CHANNEL_SWPORTAL0; + u32 before, after; + + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) { + before = qm_ccsr_in(REG_REV3_QCSP_IO_CFG(idx)); + /* Each pair of vcpu share the same SRQ(SDEST) */ + cpu_idx /= 2; + after = (before & (~IO_CFG_SDEST_MASK)) | (cpu_idx << 16); + qm_ccsr_out(REG_REV3_QCSP_IO_CFG(idx), after); + } else { + before = qm_ccsr_in(REG_QCSP_IO_CFG(idx)); + after = (before & (~IO_CFG_SDEST_MASK)) | (cpu_idx << 16); + qm_ccsr_out(REG_QCSP_IO_CFG(idx), after); + } +} + +static int qman_resource_init(struct device *dev) +{ + int pool_chan_num, cgrid_num; + int ret, i; + + switch (qman_ip_rev >> 8) { + case 1: + pool_chan_num = 15; + cgrid_num = 256; + break; + case 2: + pool_chan_num = 3; + cgrid_num = 64; + break; + case 3: + pool_chan_num = 15; + cgrid_num = 256; + break; + default: + return -ENODEV; + } + + ret = gen_pool_add(qm_qpalloc, qm_channel_pool1 | DPAA_GENALLOC_OFF, + pool_chan_num, -1); + if (ret) { + dev_err(dev, "Failed to seed pool channels (%d)\n", ret); + return ret; + } + + ret = gen_pool_add(qm_cgralloc, DPAA_GENALLOC_OFF, cgrid_num, -1); + if (ret) { + dev_err(dev, "Failed to seed CGRID range (%d)\n", ret); + return ret; + } + + /* parse pool channels into the SDQCR mask */ + for (i = 0; i < cgrid_num; i++) + qm_pools_sdqcr |= QM_SDQCR_CHANNELS_POOL_CONV(i); + + ret = gen_pool_add(qm_fqalloc, QM_FQID_RANGE_START | DPAA_GENALLOC_OFF, + qm_get_fqid_maxcnt() - QM_FQID_RANGE_START, -1); + if (ret) { + dev_err(dev, "Failed to seed FQID range (%d)\n", ret); + return ret; + } + + return 0; +} + +static int fsl_qman_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct resource *res; + int ret, err_irq; + u16 id; + u8 major, minor; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "Can't get %s property 'IORESOURCE_MEM'\n", + node->full_name); + return -ENXIO; + } + qm_ccsr_start = devm_ioremap(dev, res->start, resource_size(res)); + if (!qm_ccsr_start) + return -ENXIO; + + qm_get_version(&id, &major, &minor); + if (major == 1 && minor == 0) { + dev_err(dev, "Rev1.0 on P4080 rev1 is not supported!\n"); + return -ENODEV; + } else if (major == 1 && minor == 1) + qman_ip_rev = QMAN_REV11; + else if (major == 1 && minor == 2) + qman_ip_rev = QMAN_REV12; + else if (major == 2 && minor == 0) + qman_ip_rev = QMAN_REV20; + else if (major == 3 && minor == 0) + qman_ip_rev = QMAN_REV30; + else if (major == 3 && minor == 1) + qman_ip_rev = QMAN_REV31; + else { + dev_err(dev, "Unknown QMan version\n"); + return -ENODEV; + } + + if ((qman_ip_rev & 0xff00) >= QMAN_REV30) + qm_channel_pool1 = QMAN_CHANNEL_POOL1_REV3; + + ret = zero_priv_mem(dev, node, fqd_a, fqd_sz); + WARN_ON(ret); + if (ret) + return -ENODEV; + + ret = qman_init_ccsr(dev); + if (ret) { + dev_err(dev, "CCSR setup failed\n"); + return ret; + } + + err_irq = platform_get_irq(pdev, 0); + if (err_irq <= 0) { + dev_info(dev, "Can't get %s property 'interrupts'\n", + node->full_name); + return -ENODEV; + } + ret = devm_request_irq(dev, err_irq, qman_isr, IRQF_SHARED, "qman-err", + dev); + if (ret) { + dev_err(dev, "devm_request_irq() failed %d for '%s'\n", + ret, node->full_name); + return ret; + } + + /* + * Write-to-clear any stale bits, (eg. starvation being asserted prior + * to resource allocation during driver init). + */ + qm_ccsr_out(REG_ERR_ISR, 0xffffffff); + /* Enable Error Interrupts */ + qm_ccsr_out(REG_ERR_IER, 0xffffffff); + + qm_fqalloc = devm_gen_pool_create(dev, 0, -1, "qman-fqalloc"); + if (IS_ERR(qm_fqalloc)) { + ret = PTR_ERR(qm_fqalloc); + dev_err(dev, "qman-fqalloc pool init failed (%d)\n", ret); + return ret; + } + + qm_qpalloc = devm_gen_pool_create(dev, 0, -1, "qman-qpalloc"); + if (IS_ERR(qm_qpalloc)) { + ret = PTR_ERR(qm_qpalloc); + dev_err(dev, "qman-qpalloc pool init failed (%d)\n", ret); + return ret; + } + + qm_cgralloc = devm_gen_pool_create(dev, 0, -1, "qman-cgralloc"); + if (IS_ERR(qm_cgralloc)) { + ret = PTR_ERR(qm_cgralloc); + dev_err(dev, "qman-cgralloc pool init failed (%d)\n", ret); + return ret; + } + + ret = qman_resource_init(dev); + if (ret) + return ret; + + ret = qman_alloc_fq_table(qm_get_fqid_maxcnt()); + if (ret) + return ret; + + ret = qman_wq_alloc(); + if (ret) + return ret; + + return 0; +} + +static const struct of_device_id fsl_qman_ids[] = { + { + .compatible = "fsl,qman", + }, + {} +}; + +static struct platform_driver fsl_qman_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = fsl_qman_ids, + .suppress_bind_attrs = true, + }, + .probe = fsl_qman_probe, +}; + +builtin_platform_driver(fsl_qman_driver); diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c new file mode 100644 index 0000000000000..148614388fcab --- /dev/null +++ b/drivers/soc/fsl/qbman/qman_portal.c @@ -0,0 +1,355 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_priv.h" + +/* Enable portal interupts (as opposed to polling mode) */ +#define CONFIG_FSL_DPA_PIRQ_SLOW 1 +#define CONFIG_FSL_DPA_PIRQ_FAST 1 + +static struct cpumask portal_cpus; +/* protect qman global registers and global data shared among portals */ +static DEFINE_SPINLOCK(qman_lock); + +static void portal_set_cpu(struct qm_portal_config *pcfg, int cpu) +{ +#ifdef CONFIG_FSL_PAMU + struct device *dev = pcfg->dev; + int window_count = 1; + struct iommu_domain_geometry geom_attr; + struct pamu_stash_attribute stash_attr; + int ret; + + pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type); + if (!pcfg->iommu_domain) { + dev_err(dev, "%s(): iommu_domain_alloc() failed", __func__); + goto no_iommu; + } + geom_attr.aperture_start = 0; + geom_attr.aperture_end = + ((dma_addr_t)1 << min(8 * sizeof(dma_addr_t), (size_t)36)) - 1; + geom_attr.force_aperture = true; + ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY, + &geom_attr); + if (ret < 0) { + dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__, + ret); + goto out_domain_free; + } + ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS, + &window_count); + if (ret < 0) { + dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__, + ret); + goto out_domain_free; + } + stash_attr.cpu = cpu; + stash_attr.cache = PAMU_ATTR_CACHE_L1; + ret = iommu_domain_set_attr(pcfg->iommu_domain, + DOMAIN_ATTR_FSL_PAMU_STASH, + &stash_attr); + if (ret < 0) { + dev_err(dev, "%s(): iommu_domain_set_attr() = %d", + __func__, ret); + goto out_domain_free; + } + ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36, + IOMMU_READ | IOMMU_WRITE); + if (ret < 0) { + dev_err(dev, "%s(): iommu_domain_window_enable() = %d", + __func__, ret); + goto out_domain_free; + } + ret = iommu_attach_device(pcfg->iommu_domain, dev); + if (ret < 0) { + dev_err(dev, "%s(): iommu_device_attach() = %d", __func__, + ret); + goto out_domain_free; + } + ret = iommu_domain_set_attr(pcfg->iommu_domain, + DOMAIN_ATTR_FSL_PAMU_ENABLE, + &window_count); + if (ret < 0) { + dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__, + ret); + goto out_detach_device; + } + +no_iommu: +#endif + qman_set_sdest(pcfg->channel, cpu); + + return; + +#ifdef CONFIG_FSL_PAMU +out_detach_device: + iommu_detach_device(pcfg->iommu_domain, NULL); +out_domain_free: + iommu_domain_free(pcfg->iommu_domain); + pcfg->iommu_domain = NULL; +#endif +} + +static struct qman_portal *init_pcfg(struct qm_portal_config *pcfg) +{ + struct qman_portal *p; + u32 irq_sources = 0; + + /* We need the same LIODN offset for all portals */ + qman_liodn_fixup(pcfg->channel); + + pcfg->iommu_domain = NULL; + portal_set_cpu(pcfg, pcfg->cpu); + + p = qman_create_affine_portal(pcfg, NULL); + if (!p) { + dev_crit(pcfg->dev, "%s: Portal failure on cpu %d\n", + __func__, pcfg->cpu); + return NULL; + } + + /* Determine what should be interrupt-vs-poll driven */ +#ifdef CONFIG_FSL_DPA_PIRQ_SLOW + irq_sources |= QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI | + QM_PIRQ_CSCI; +#endif +#ifdef CONFIG_FSL_DPA_PIRQ_FAST + irq_sources |= QM_PIRQ_DQRI; +#endif + qman_p_irqsource_add(p, irq_sources); + + spin_lock(&qman_lock); + if (cpumask_equal(&portal_cpus, cpu_possible_mask)) { + /* all assigned portals are initialized now */ + qman_init_cgr_all(); + } + spin_unlock(&qman_lock); + + dev_info(pcfg->dev, "Portal initialised, cpu %d\n", pcfg->cpu); + + return p; +} + +static void qman_portal_update_sdest(const struct qm_portal_config *pcfg, + unsigned int cpu) +{ +#ifdef CONFIG_FSL_PAMU /* TODO */ + struct pamu_stash_attribute stash_attr; + int ret; + + if (pcfg->iommu_domain) { + stash_attr.cpu = cpu; + stash_attr.cache = PAMU_ATTR_CACHE_L1; + ret = iommu_domain_set_attr(pcfg->iommu_domain, + DOMAIN_ATTR_FSL_PAMU_STASH, &stash_attr); + if (ret < 0) { + dev_err(pcfg->dev, + "Failed to update pamu stash setting\n"); + return; + } + } +#endif + qman_set_sdest(pcfg->channel, cpu); +} + +static void qman_offline_cpu(unsigned int cpu) +{ + struct qman_portal *p; + const struct qm_portal_config *pcfg; + + p = affine_portals[cpu]; + if (p) { + pcfg = qman_get_qm_portal_config(p); + if (pcfg) { + irq_set_affinity(pcfg->irq, cpumask_of(0)); + qman_portal_update_sdest(pcfg, 0); + } + } +} + +static void qman_online_cpu(unsigned int cpu) +{ + struct qman_portal *p; + const struct qm_portal_config *pcfg; + + p = affine_portals[cpu]; + if (p) { + pcfg = qman_get_qm_portal_config(p); + if (pcfg) { + irq_set_affinity(pcfg->irq, cpumask_of(cpu)); + qman_portal_update_sdest(pcfg, cpu); + } + } +} + +static int qman_hotplug_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + qman_online_cpu(cpu); + break; + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + qman_offline_cpu(cpu); + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block qman_hotplug_cpu_notifier = { + .notifier_call = qman_hotplug_cpu_callback, +}; + +static int qman_portal_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct qm_portal_config *pcfg; + struct resource *addr_phys[2]; + const u32 *channel; + void __iomem *va; + int irq, len, cpu; + + pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL); + if (!pcfg) + return -ENOMEM; + + pcfg->dev = dev; + + addr_phys[0] = platform_get_resource(pdev, IORESOURCE_MEM, + DPAA_PORTAL_CE); + if (!addr_phys[0]) { + dev_err(dev, "Can't get %s property 'reg::CE'\n", + node->full_name); + return -ENXIO; + } + + addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM, + DPAA_PORTAL_CI); + if (!addr_phys[1]) { + dev_err(dev, "Can't get %s property 'reg::CI'\n", + node->full_name); + return -ENXIO; + } + + channel = of_get_property(node, "cell-index", &len); + if (!channel || (len != 4)) { + dev_err(dev, "Can't get %s property 'cell-index'\n", + node->full_name); + return -ENXIO; + } + pcfg->channel = *channel; + pcfg->cpu = -1; + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(dev, "Can't get %s IRQ\n", node->full_name); + return -ENXIO; + } + pcfg->irq = irq; + + va = ioremap_prot(addr_phys[0]->start, resource_size(addr_phys[0]), 0); + if (!va) + goto err_ioremap1; + + pcfg->addr_virt[DPAA_PORTAL_CE] = va; + + va = ioremap_prot(addr_phys[1]->start, resource_size(addr_phys[1]), + _PAGE_GUARDED | _PAGE_NO_CACHE); + if (!va) + goto err_ioremap2; + + pcfg->addr_virt[DPAA_PORTAL_CI] = va; + + pcfg->pools = qm_get_pools_sdqcr(); + + spin_lock(&qman_lock); + cpu = cpumask_next_zero(-1, &portal_cpus); + if (cpu >= nr_cpu_ids) { + /* unassigned portal, skip init */ + spin_unlock(&qman_lock); + return 0; + } + + cpumask_set_cpu(cpu, &portal_cpus); + spin_unlock(&qman_lock); + pcfg->cpu = cpu; + + if (!init_pcfg(pcfg)) + goto err_ioremap2; + + /* clear irq affinity if assigned cpu is offline */ + if (!cpu_online(cpu)) + qman_offline_cpu(cpu); + + return 0; + +err_ioremap2: + iounmap(pcfg->addr_virt[DPAA_PORTAL_CE]); +err_ioremap1: + dev_err(dev, "ioremap failed\n"); + return -ENXIO; +} + +static const struct of_device_id qman_portal_ids[] = { + { + .compatible = "fsl,qman-portal", + }, + {} +}; +MODULE_DEVICE_TABLE(of, qman_portal_ids); + +static struct platform_driver qman_portal_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = qman_portal_ids, + }, + .probe = qman_portal_probe, +}; + +static int __init qman_portal_driver_register(struct platform_driver *drv) +{ + int ret; + + ret = platform_driver_register(drv); + if (ret < 0) + return ret; + + register_hotcpu_notifier(&qman_hotplug_cpu_notifier); + + return 0; +} + +module_driver(qman_portal_driver, + qman_portal_driver_register, platform_driver_unregister); diff --git a/drivers/soc/fsl/qbman/qman_priv.h b/drivers/soc/fsl/qbman/qman_priv.h new file mode 100644 index 0000000000000..5cf821e623a9c --- /dev/null +++ b/drivers/soc/fsl/qbman/qman_priv.h @@ -0,0 +1,371 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "dpaa_sys.h" + +#include +#include + +#if defined(CONFIG_FSL_PAMU) +#include +#endif + +struct qm_mcr_querywq { + u8 verb; + u8 result; + u16 channel_wq; /* ignores wq (3 lsbits): _res[0-2] */ + u8 __reserved[28]; + u32 wq_len[8]; +} __packed; + +static inline u16 qm_mcr_querywq_get_chan(const struct qm_mcr_querywq *wq) +{ + return wq->channel_wq >> 3; +} + +struct __qm_mcr_querycongestion { + u32 state[8]; +}; + +/* "Query Congestion Group State" */ +struct qm_mcr_querycongestion { + u8 verb; + u8 result; + u8 __reserved[30]; + /* Access this struct using qman_cgrs_get() */ + struct __qm_mcr_querycongestion state; +} __packed; + +/* "Query CGR" */ +struct qm_mcr_querycgr { + u8 verb; + u8 result; + u16 __reserved1; + struct __qm_mc_cgr cgr; /* CGR fields */ + u8 __reserved2[6]; + u8 i_bcnt_hi; /* high 8-bits of 40-bit "Instant" */ + u32 i_bcnt_lo; /* low 32-bits of 40-bit */ + u8 __reserved3[3]; + u8 a_bcnt_hi; /* high 8-bits of 40-bit "Average" */ + u32 a_bcnt_lo; /* low 32-bits of 40-bit */ + u32 cscn_targ_swp[4]; +} __packed; + +static inline u64 qm_mcr_querycgr_i_get64(const struct qm_mcr_querycgr *q) +{ + return ((u64)q->i_bcnt_hi << 32) | (u64)q->i_bcnt_lo; +} +static inline u64 qm_mcr_querycgr_a_get64(const struct qm_mcr_querycgr *q) +{ + return ((u64)q->a_bcnt_hi << 32) | (u64)q->a_bcnt_lo; +} + +/* "Query FQ Non-Programmable Fields" */ +struct qm_mcc_queryfq_np { + u8 _ncw_verb; + u8 __reserved1[3]; + u32 fqid; /* 24-bit */ + u8 __reserved2[56]; +} __packed; + +struct qm_mcr_queryfq_np { + u8 verb; + u8 result; + u8 __reserved1; + u8 state; /* QM_MCR_NP_STATE_*** */ + u32 fqd_link; /* 24-bit, _res2[24-31] */ + u16 odp_seq; /* 14-bit, _res3[14-15] */ + u16 orp_nesn; /* 14-bit, _res4[14-15] */ + u16 orp_ea_hseq; /* 15-bit, _res5[15] */ + u16 orp_ea_tseq; /* 15-bit, _res6[15] */ + u32 orp_ea_hptr; /* 24-bit, _res7[24-31] */ + u32 orp_ea_tptr; /* 24-bit, _res8[24-31] */ + u32 pfdr_hptr; /* 24-bit, _res9[24-31] */ + u32 pfdr_tptr; /* 24-bit, _res10[24-31] */ + u8 __reserved2[5]; + u8 is; /* 1-bit, _res12[1-7] */ + u16 ics_surp; + u32 byte_cnt; + u32 frm_cnt; /* 24-bit, _res13[24-31] */ + u32 __reserved3; + u16 ra1_sfdr; /* QM_MCR_NP_RA1_*** */ + u16 ra2_sfdr; /* QM_MCR_NP_RA2_*** */ + u16 __reserved4; + u16 od1_sfdr; /* QM_MCR_NP_OD1_*** */ + u16 od2_sfdr; /* QM_MCR_NP_OD2_*** */ + u16 od3_sfdr; /* QM_MCR_NP_OD3_*** */ +} __packed; + +#define QM_MCR_NP_STATE_FE 0x10 +#define QM_MCR_NP_STATE_R 0x08 +#define QM_MCR_NP_STATE_MASK 0x07 /* Reads FQD::STATE; */ +#define QM_MCR_NP_STATE_OOS 0x00 +#define QM_MCR_NP_STATE_RETIRED 0x01 +#define QM_MCR_NP_STATE_TEN_SCHED 0x02 +#define QM_MCR_NP_STATE_TRU_SCHED 0x03 +#define QM_MCR_NP_STATE_PARKED 0x04 +#define QM_MCR_NP_STATE_ACTIVE 0x05 +#define QM_MCR_NP_PTR_MASK 0x07ff /* for RA[12] & OD[123] */ +#define QM_MCR_NP_RA1_NRA(v) (((v) >> 14) & 0x3) /* FQD::NRA */ +#define QM_MCR_NP_RA2_IT(v) (((v) >> 14) & 0x1) /* FQD::IT */ +#define QM_MCR_NP_OD1_NOD(v) (((v) >> 14) & 0x3) /* FQD::NOD */ +#define QM_MCR_NP_OD3_NPC(v) (((v) >> 14) & 0x3) /* FQD::NPC */ + +enum qm_mcr_queryfq_np_masks { + qm_mcr_fqd_link_mask = BIT(24)-1, + qm_mcr_odp_seq_mask = BIT(14)-1, + qm_mcr_orp_nesn_mask = BIT(14)-1, + qm_mcr_orp_ea_hseq_mask = BIT(15)-1, + qm_mcr_orp_ea_tseq_mask = BIT(15)-1, + qm_mcr_orp_ea_hptr_mask = BIT(24)-1, + qm_mcr_orp_ea_tptr_mask = BIT(24)-1, + qm_mcr_pfdr_hptr_mask = BIT(24)-1, + qm_mcr_pfdr_tptr_mask = BIT(24)-1, + qm_mcr_is_mask = BIT(1)-1, + qm_mcr_frm_cnt_mask = BIT(24)-1, +}; +#define qm_mcr_np_get(np, field) \ + ((np)->field & (qm_mcr_##field##_mask)) + +/* Congestion Groups */ + +/* + * This wrapper represents a bit-array for the state of the 256 QMan congestion + * groups. Is also used as a *mask* for congestion groups, eg. so we ignore + * those that don't concern us. We harness the structure and accessor details + * already used in the management command to query congestion groups. + */ +#define CGR_BITS_PER_WORD 5 +#define CGR_WORD(x) ((x) >> CGR_BITS_PER_WORD) +#define CGR_BIT(x) (BIT(31) >> ((x) & 0x1f)) +#define CGR_NUM (sizeof(struct __qm_mcr_querycongestion) << 3) + +struct qman_cgrs { + struct __qm_mcr_querycongestion q; +}; + +static inline void qman_cgrs_init(struct qman_cgrs *c) +{ + memset(c, 0, sizeof(*c)); +} + +static inline void qman_cgrs_fill(struct qman_cgrs *c) +{ + memset(c, 0xff, sizeof(*c)); +} + +static inline int qman_cgrs_get(struct qman_cgrs *c, u8 cgr) +{ + return c->q.state[CGR_WORD(cgr)] & CGR_BIT(cgr); +} + +static inline void qman_cgrs_cp(struct qman_cgrs *dest, + const struct qman_cgrs *src) +{ + *dest = *src; +} + +static inline void qman_cgrs_and(struct qman_cgrs *dest, + const struct qman_cgrs *a, const struct qman_cgrs *b) +{ + int ret; + u32 *_d = dest->q.state; + const u32 *_a = a->q.state; + const u32 *_b = b->q.state; + + for (ret = 0; ret < 8; ret++) + *_d++ = *_a++ & *_b++; +} + +static inline void qman_cgrs_xor(struct qman_cgrs *dest, + const struct qman_cgrs *a, const struct qman_cgrs *b) +{ + int ret; + u32 *_d = dest->q.state; + const u32 *_a = a->q.state; + const u32 *_b = b->q.state; + + for (ret = 0; ret < 8; ret++) + *_d++ = *_a++ ^ *_b++; +} + +void qman_init_cgr_all(void); + +struct qm_portal_config { + /* + * Corenet portal addresses; + * [0]==cache-enabled, [1]==cache-inhibited. + */ + void __iomem *addr_virt[2]; + struct device *dev; + struct iommu_domain *iommu_domain; + /* Allow these to be joined in lists */ + struct list_head list; + /* User-visible portal configuration settings */ + /* portal is affined to this cpu */ + int cpu; + /* portal interrupt line */ + int irq; + /* + * the portal's dedicated channel id, used initialising + * frame queues to target this portal when scheduled + */ + u16 channel; + /* + * mask of pool channels this portal has dequeue access to + * (using QM_SDQCR_CHANNELS_POOL(n) for the bitmask) + */ + u32 pools; +}; + +/* Revision info (for errata and feature handling) */ +#define QMAN_REV11 0x0101 +#define QMAN_REV12 0x0102 +#define QMAN_REV20 0x0200 +#define QMAN_REV30 0x0300 +#define QMAN_REV31 0x0301 +extern u16 qman_ip_rev; /* 0 if uninitialised, otherwise QMAN_REVx */ + +#define QM_FQID_RANGE_START 1 /* FQID 0 reserved for internal use */ +extern struct gen_pool *qm_fqalloc; /* FQID allocator */ +extern struct gen_pool *qm_qpalloc; /* pool-channel allocator */ +extern struct gen_pool *qm_cgralloc; /* CGR ID allocator */ +u32 qm_get_pools_sdqcr(void); + +int qman_wq_alloc(void); +void qman_liodn_fixup(u16 channel); +void qman_set_sdest(u16 channel, unsigned int cpu_idx); + +struct qman_portal *qman_create_affine_portal( + const struct qm_portal_config *config, + const struct qman_cgrs *cgrs); +const struct qm_portal_config *qman_destroy_affine_portal(void); + +/* + * qman_query_fq - Queries FQD fields (via h/w query command) + * @fq: the frame queue object to be queried + * @fqd: storage for the queried FQD fields + */ +int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd); + +/* + * For qman_volatile_dequeue(); Choose one PRECEDENCE. EXACT is optional. Use + * NUMFRAMES(n) (6-bit) or NUMFRAMES_TILLEMPTY to fill in the frame-count. Use + * FQID(n) to fill in the frame queue ID. + */ +#define QM_VDQCR_PRECEDENCE_VDQCR 0x0 +#define QM_VDQCR_PRECEDENCE_SDQCR 0x80000000 +#define QM_VDQCR_EXACT 0x40000000 +#define QM_VDQCR_NUMFRAMES_MASK 0x3f000000 +#define QM_VDQCR_NUMFRAMES_SET(n) (((n) & 0x3f) << 24) +#define QM_VDQCR_NUMFRAMES_GET(n) (((n) >> 24) & 0x3f) +#define QM_VDQCR_NUMFRAMES_TILLEMPTY QM_VDQCR_NUMFRAMES_SET(0) + +#define QMAN_VOLATILE_FLAG_WAIT 0x00000001 /* wait if VDQCR is in use */ +#define QMAN_VOLATILE_FLAG_WAIT_INT 0x00000002 /* if wait, interruptible? */ +#define QMAN_VOLATILE_FLAG_FINISH 0x00000004 /* wait till VDQCR completes */ + +/* + * qman_volatile_dequeue - Issue a volatile dequeue command + * @fq: the frame queue object to dequeue from + * @flags: a bit-mask of QMAN_VOLATILE_FLAG_*** options + * @vdqcr: bit mask of QM_VDQCR_*** options, as per qm_dqrr_vdqcr_set() + * + * Attempts to lock access to the portal's VDQCR volatile dequeue functionality. + * The function will block and sleep if QMAN_VOLATILE_FLAG_WAIT is specified and + * the VDQCR is already in use, otherwise returns non-zero for failure. If + * QMAN_VOLATILE_FLAG_FINISH is specified, the function will only return once + * the VDQCR command has finished executing (ie. once the callback for the last + * DQRR entry resulting from the VDQCR command has been called). If not using + * the FINISH flag, completion can be determined either by detecting the + * presence of the QM_DQRR_STAT_UNSCHEDULED and QM_DQRR_STAT_DQCR_EXPIRED bits + * in the "stat" parameter passed to the FQ's dequeue callback, or by waiting + * for the QMAN_FQ_STATE_VDQCR bit to disappear. + */ +int qman_volatile_dequeue(struct qman_fq *fq, u32 flags, u32 vdqcr); + +int qman_alloc_fq_table(u32 num_fqids); + +/* QMan s/w corenet portal, low-level i/face */ + +/* + * For qm_dqrr_sdqcr_set(); Choose one SOURCE. Choose one COUNT. Choose one + * dequeue TYPE. Choose TOKEN (8-bit). + * If SOURCE == CHANNELS, + * Choose CHANNELS_DEDICATED and/or CHANNELS_POOL(n). + * You can choose DEDICATED_PRECEDENCE if the portal channel should have + * priority. + * If SOURCE == SPECIFICWQ, + * Either select the work-queue ID with SPECIFICWQ_WQ(), or select the + * channel (SPECIFICWQ_DEDICATED or SPECIFICWQ_POOL()) and specify the + * work-queue priority (0-7) with SPECIFICWQ_WQ() - either way, you get the + * same value. + */ +#define QM_SDQCR_SOURCE_CHANNELS 0x0 +#define QM_SDQCR_SOURCE_SPECIFICWQ 0x40000000 +#define QM_SDQCR_COUNT_EXACT1 0x0 +#define QM_SDQCR_COUNT_UPTO3 0x20000000 +#define QM_SDQCR_DEDICATED_PRECEDENCE 0x10000000 +#define QM_SDQCR_TYPE_MASK 0x03000000 +#define QM_SDQCR_TYPE_NULL 0x0 +#define QM_SDQCR_TYPE_PRIO_QOS 0x01000000 +#define QM_SDQCR_TYPE_ACTIVE_QOS 0x02000000 +#define QM_SDQCR_TYPE_ACTIVE 0x03000000 +#define QM_SDQCR_TOKEN_MASK 0x00ff0000 +#define QM_SDQCR_TOKEN_SET(v) (((v) & 0xff) << 16) +#define QM_SDQCR_TOKEN_GET(v) (((v) >> 16) & 0xff) +#define QM_SDQCR_CHANNELS_DEDICATED 0x00008000 +#define QM_SDQCR_SPECIFICWQ_MASK 0x000000f7 +#define QM_SDQCR_SPECIFICWQ_DEDICATED 0x00000000 +#define QM_SDQCR_SPECIFICWQ_POOL(n) ((n) << 4) +#define QM_SDQCR_SPECIFICWQ_WQ(n) (n) + +/* For qm_dqrr_vdqcr_set(): use FQID(n) to fill in the frame queue ID */ +#define QM_VDQCR_FQID_MASK 0x00ffffff +#define QM_VDQCR_FQID(n) ((n) & QM_VDQCR_FQID_MASK) + +/* + * Used by all portal interrupt registers except 'inhibit' + * Channels with frame availability + */ +#define QM_PIRQ_DQAVAIL 0x0000ffff + +/* The DQAVAIL interrupt fields break down into these bits; */ +#define QM_DQAVAIL_PORTAL 0x8000 /* Portal channel */ +#define QM_DQAVAIL_POOL(n) (0x8000 >> (n)) /* Pool channel, n==[1..15] */ +#define QM_DQAVAIL_MASK 0xffff +/* This mask contains all the "irqsource" bits visible to API users */ +#define QM_PIRQ_VISIBLE (QM_PIRQ_SLOW | QM_PIRQ_DQRI) + +extern struct qman_portal *affine_portals[NR_CPUS]; +const struct qm_portal_config *qman_get_qm_portal_config( + struct qman_portal *portal); diff --git a/include/soc/fsl/qman.h b/include/soc/fsl/qman.h new file mode 100644 index 0000000000000..37f3eb001a169 --- /dev/null +++ b/include/soc/fsl/qman.h @@ -0,0 +1,1074 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FSL_QMAN_H +#define __FSL_QMAN_H + +#include + +/* Hardware constants */ +#define QM_CHANNEL_SWPORTAL0 0 +#define QMAN_CHANNEL_POOL1 0x21 +#define QMAN_CHANNEL_POOL1_REV3 0x401 +extern u16 qm_channel_pool1; + +/* Portal processing (interrupt) sources */ +#define QM_PIRQ_CSCI 0x00100000 /* Congestion State Change */ +#define QM_PIRQ_EQCI 0x00080000 /* Enqueue Command Committed */ +#define QM_PIRQ_EQRI 0x00040000 /* EQCR Ring (below threshold) */ +#define QM_PIRQ_DQRI 0x00020000 /* DQRR Ring (non-empty) */ +#define QM_PIRQ_MRI 0x00010000 /* MR Ring (non-empty) */ +/* + * This mask contains all the interrupt sources that need handling except DQRI, + * ie. that if present should trigger slow-path processing. + */ +#define QM_PIRQ_SLOW (QM_PIRQ_CSCI | QM_PIRQ_EQCI | QM_PIRQ_EQRI | \ + QM_PIRQ_MRI) + +/* For qman_static_dequeue_*** APIs */ +#define QM_SDQCR_CHANNELS_POOL_MASK 0x00007fff +/* for n in [1,15] */ +#define QM_SDQCR_CHANNELS_POOL(n) (0x00008000 >> (n)) +/* for conversion from n of qm_channel */ +static inline u32 QM_SDQCR_CHANNELS_POOL_CONV(u16 channel) +{ + return QM_SDQCR_CHANNELS_POOL(channel + 1 - qm_channel_pool1); +} + +/* --- QMan data structures (and associated constants) --- */ + +/* "Frame Descriptor (FD)" */ +struct qm_fd { + union { + struct { + u8 cfg8b_w1; + u8 bpid; /* Buffer Pool ID */ + u8 cfg8b_w3; + u8 addr_hi; /* high 8-bits of 40-bit address */ + __be32 addr_lo; /* low 32-bits of 40-bit address */ + } __packed; + __be64 data; + }; + __be32 cfg; /* format, offset, length / congestion */ + union { + __be32 cmd; + __be32 status; + }; +} __aligned(8); + +#define QM_FD_FORMAT_SG BIT(31) +#define QM_FD_FORMAT_LONG BIT(30) +#define QM_FD_FORMAT_COMPOUND BIT(29) +#define QM_FD_FORMAT_MASK GENMASK(31, 29) +#define QM_FD_OFF_SHIFT 20 +#define QM_FD_OFF_MASK GENMASK(28, 20) +#define QM_FD_LEN_MASK GENMASK(19, 0) +#define QM_FD_LEN_BIG_MASK GENMASK(28, 0) + +enum qm_fd_format { + /* + * 'contig' implies a contiguous buffer, whereas 'sg' implies a + * scatter-gather table. 'big' implies a 29-bit length with no offset + * field, otherwise length is 20-bit and offset is 9-bit. 'compound' + * implies a s/g-like table, where each entry itself represents a frame + * (contiguous or scatter-gather) and the 29-bit "length" is + * interpreted purely for congestion calculations, ie. a "congestion + * weight". + */ + qm_fd_contig = 0, + qm_fd_contig_big = QM_FD_FORMAT_LONG, + qm_fd_sg = QM_FD_FORMAT_SG, + qm_fd_sg_big = QM_FD_FORMAT_SG | QM_FD_FORMAT_LONG, + qm_fd_compound = QM_FD_FORMAT_COMPOUND +}; + +static inline dma_addr_t qm_fd_addr(const struct qm_fd *fd) +{ + return be64_to_cpu(fd->data) & 0xffffffffffLLU; +} + +static inline u64 qm_fd_addr_get64(const struct qm_fd *fd) +{ + return be64_to_cpu(fd->data) & 0xffffffffffLLU; +} + +static inline void qm_fd_addr_set64(struct qm_fd *fd, u64 addr) +{ + fd->addr_hi = upper_32_bits(addr); + fd->addr_lo = cpu_to_be32(lower_32_bits(addr)); +} + +/* + * The 'format' field indicates the interpretation of the remaining + * 29 bits of the 32-bit word. + * If 'format' is _contig or _sg, 20b length and 9b offset. + * If 'format' is _contig_big or _sg_big, 29b length. + * If 'format' is _compound, 29b "congestion weight". + */ +static inline enum qm_fd_format qm_fd_get_format(const struct qm_fd *fd) +{ + return be32_to_cpu(fd->cfg) & QM_FD_FORMAT_MASK; +} + +static inline int qm_fd_get_offset(const struct qm_fd *fd) +{ + return (be32_to_cpu(fd->cfg) & QM_FD_OFF_MASK) >> QM_FD_OFF_SHIFT; +} + +static inline int qm_fd_get_length(const struct qm_fd *fd) +{ + return be32_to_cpu(fd->cfg) & QM_FD_LEN_MASK; +} + +static inline int qm_fd_get_len_big(const struct qm_fd *fd) +{ + return be32_to_cpu(fd->cfg) & QM_FD_LEN_BIG_MASK; +} + +static inline void qm_fd_set_param(struct qm_fd *fd, enum qm_fd_format fmt, + int off, int len) +{ + fd->cfg = cpu_to_be32(fmt | (len & QM_FD_LEN_BIG_MASK) | + ((off << QM_FD_OFF_SHIFT) & QM_FD_OFF_MASK)); +} + +#define qm_fd_set_contig(fd, off, len) \ + qm_fd_set_param(fd, qm_fd_contig, off, len) +#define qm_fd_set_sg(fd, off, len) qm_fd_set_param(fd, qm_fd_sg, off, len) +#define qm_fd_set_contig_big(fd, len) \ + qm_fd_set_param(fd, qm_fd_contig_big, 0, len) +#define qm_fd_set_sg_big(fd, len) qm_fd_set_param(fd, qm_fd_sg_big, 0, len) + +static inline void qm_fd_clear_fd(struct qm_fd *fd) +{ + fd->data = 0; + fd->cfg = 0; + fd->cmd = 0; +} + +/* Scatter/Gather table entry */ +struct qm_sg_entry { + union { + struct { + u8 __reserved1[3]; + u8 addr_hi; /* high 8-bits of 40-bit address */ + __be32 addr_lo; /* low 32-bits of 40-bit address */ + }; + __be64 data; + }; + __be32 cfg; /* E bit, F bit, length */ + u8 __reserved2; + u8 bpid; + __be16 offset; /* 13-bit, _res[13-15]*/ +} __packed; + +#define QM_SG_LEN_MASK GENMASK(29, 0) +#define QM_SG_OFF_MASK GENMASK(12, 0) +#define QM_SG_FIN BIT(30) +#define QM_SG_EXT BIT(31) + +static inline dma_addr_t qm_sg_addr(const struct qm_sg_entry *sg) +{ + return be64_to_cpu(sg->data) & 0xffffffffffLLU; +} + +static inline u64 qm_sg_entry_get64(const struct qm_sg_entry *sg) +{ + return be64_to_cpu(sg->data) & 0xffffffffffLLU; +} + +static inline void qm_sg_entry_set64(struct qm_sg_entry *sg, u64 addr) +{ + sg->addr_hi = upper_32_bits(addr); + sg->addr_lo = cpu_to_be32(lower_32_bits(addr)); +} + +static inline bool qm_sg_entry_is_final(const struct qm_sg_entry *sg) +{ + return be32_to_cpu(sg->cfg) & QM_SG_FIN; +} + +static inline bool qm_sg_entry_is_ext(const struct qm_sg_entry *sg) +{ + return be32_to_cpu(sg->cfg) & QM_SG_EXT; +} + +static inline int qm_sg_entry_get_len(const struct qm_sg_entry *sg) +{ + return be32_to_cpu(sg->cfg) & QM_SG_LEN_MASK; +} + +static inline void qm_sg_entry_set_len(struct qm_sg_entry *sg, int len) +{ + sg->cfg = cpu_to_be32(len & QM_SG_LEN_MASK); +} + +static inline void qm_sg_entry_set_f(struct qm_sg_entry *sg, int len) +{ + sg->cfg = cpu_to_be32(QM_SG_FIN | (len & QM_SG_LEN_MASK)); +} + +static inline int qm_sg_entry_get_off(const struct qm_sg_entry *sg) +{ + return be32_to_cpu(sg->offset) & QM_SG_OFF_MASK; +} + +/* "Frame Dequeue Response" */ +struct qm_dqrr_entry { + u8 verb; + u8 stat; + u16 seqnum; /* 15-bit */ + u8 tok; + u8 __reserved2[3]; + u32 fqid; /* 24-bit */ + u32 contextB; + struct qm_fd fd; + u8 __reserved4[32]; +} __packed; +#define QM_DQRR_VERB_VBIT 0x80 +#define QM_DQRR_VERB_MASK 0x7f /* where the verb contains; */ +#define QM_DQRR_VERB_FRAME_DEQUEUE 0x60 /* "this format" */ +#define QM_DQRR_STAT_FQ_EMPTY 0x80 /* FQ empty */ +#define QM_DQRR_STAT_FQ_HELDACTIVE 0x40 /* FQ held active */ +#define QM_DQRR_STAT_FQ_FORCEELIGIBLE 0x20 /* FQ was force-eligible'd */ +#define QM_DQRR_STAT_FD_VALID 0x10 /* has a non-NULL FD */ +#define QM_DQRR_STAT_UNSCHEDULED 0x02 /* Unscheduled dequeue */ +#define QM_DQRR_STAT_DQCR_EXPIRED 0x01 /* VDQCR or PDQCR expired*/ + +/* "ERN Message Response" */ +/* "FQ State Change Notification" */ +union qm_mr_entry { + struct { + u8 verb; + u8 __reserved[63]; + }; + struct { + u8 verb; + u8 dca; + u16 seqnum; + u8 rc; /* Rej Code: 8-bit */ + u8 orp_hi; /* ORP: 24-bit */ + u16 orp_lo; + u32 fqid; /* 24-bit */ + u32 tag; + struct qm_fd fd; + u8 __reserved1[32]; + } __packed ern; + struct { + u8 verb; + u8 fqs; /* Frame Queue Status */ + u8 __reserved1[6]; + u32 fqid; /* 24-bit */ + u32 contextB; + u8 __reserved2[48]; + } __packed fq; /* FQRN/FQRNI/FQRL/FQPN */ +}; +#define QM_MR_VERB_VBIT 0x80 +/* + * ERNs originating from direct-connect portals ("dcern") use 0x20 as a verb + * which would be invalid as a s/w enqueue verb. A s/w ERN can be distinguished + * from the other MR types by noting if the 0x20 bit is unset. + */ +#define QM_MR_VERB_TYPE_MASK 0x27 +#define QM_MR_VERB_DC_ERN 0x20 +#define QM_MR_VERB_FQRN 0x21 +#define QM_MR_VERB_FQRNI 0x22 +#define QM_MR_VERB_FQRL 0x23 +#define QM_MR_VERB_FQPN 0x24 +#define QM_MR_RC_MASK 0xf0 /* contains one of; */ +#define QM_MR_RC_CGR_TAILDROP 0x00 +#define QM_MR_RC_WRED 0x10 +#define QM_MR_RC_ERROR 0x20 +#define QM_MR_RC_ORPWINDOW_EARLY 0x30 +#define QM_MR_RC_ORPWINDOW_LATE 0x40 +#define QM_MR_RC_FQ_TAILDROP 0x50 +#define QM_MR_RC_ORPWINDOW_RETIRED 0x60 +#define QM_MR_RC_ORP_ZERO 0x70 +#define QM_MR_FQS_ORLPRESENT 0x02 /* ORL fragments to come */ +#define QM_MR_FQS_NOTEMPTY 0x01 /* FQ has enqueued frames */ + +/* + * An identical structure of FQD fields is present in the "Init FQ" command and + * the "Query FQ" result, it's suctioned out into the "struct qm_fqd" type. + * Within that, the 'stashing' and 'taildrop' pieces are also factored out, the + * latter has two inlines to assist with converting to/from the mant+exp + * representation. + */ +struct qm_fqd_stashing { + /* See QM_STASHING_EXCL_<...> */ + u8 exclusive; + /* Numbers of cachelines */ + u8 cl; /* _res[6-7], as[4-5], ds[2-3], cs[0-1] */ +}; + +struct qm_fqd_oac { + /* "Overhead Accounting Control", see QM_OAC_<...> */ + u8 oac; /* oac[6-7], _res[0-5] */ + /* Two's-complement value (-128 to +127) */ + s8 oal; /* "Overhead Accounting Length" */ +}; + +struct qm_fqd { + /* _res[6-7], orprws[3-5], oa[2], olws[0-1] */ + u8 orpc; + u8 cgid; + __be16 fq_ctrl; /* See QM_FQCTRL_<...> */ + __be16 dest_wq; /* channel[3-15], wq[0-2] */ + __be16 ics_cred; /* 15-bit */ + /* + * For "Initialize Frame Queue" commands, the write-enable mask + * determines whether 'td' or 'oac_init' is observed. For query + * commands, this field is always 'td', and 'oac_query' (below) reflects + * the Overhead ACcounting values. + */ + union { + __be16 td; /* "Taildrop": _res[13-15], mant[5-12], exp[0-4] */ + struct qm_fqd_oac oac_init; + }; + __be32 context_b; + union { + /* Treat it as 64-bit opaque */ + __be64 opaque; + struct { + __be32 hi; + __be32 lo; + }; + /* Treat it as s/w portal stashing config */ + /* see "FQD Context_A field used for [...]" */ + struct { + struct qm_fqd_stashing stashing; + /* + * 48-bit address of FQ context to + * stash, must be cacheline-aligned + */ + __be16 context_hi; + __be32 context_lo; + } __packed; + } context_a; + struct qm_fqd_oac oac_query; +} __packed; + +#define QM_FQD_CHAN_OFF 3 +#define QM_FQD_WQ_MASK GENMASK(2, 0) +#define QM_FQD_TD_EXP_MASK GENMASK(4, 0) +#define QM_FQD_TD_MANT_OFF 5 +#define QM_FQD_TD_MANT_MASK GENMASK(12, 5) +#define QM_FQD_TD_MAX 0xe0000000 +#define QM_FQD_TD_MANT_MAX 0xff +#define QM_FQD_OAC_OFF 6 +#define QM_FQD_AS_OFF 4 +#define QM_FQD_DS_OFF 2 +#define QM_FQD_XS_MASK 0x3 + +/* 64-bit converters for context_hi/lo */ +static inline u64 qm_fqd_stashing_get64(const struct qm_fqd *fqd) +{ + return be64_to_cpu(fqd->context_a.opaque) & 0xffffffffffffULL; +} + +static inline dma_addr_t qm_fqd_stashing_addr(const struct qm_fqd *fqd) +{ + return be64_to_cpu(fqd->context_a.opaque) & 0xffffffffffffULL; +} + +static inline u64 qm_fqd_context_a_get64(const struct qm_fqd *fqd) +{ + return qm_fqd_stashing_get64(fqd); +} + +static inline void qm_fqd_stashing_set64(struct qm_fqd *fqd, u64 addr) +{ + fqd->context_a.context_hi = upper_32_bits(addr); + fqd->context_a.context_lo = lower_32_bits(addr); +} + +static inline void qm_fqd_context_a_set64(struct qm_fqd *fqd, u64 addr) +{ + fqd->context_a.hi = cpu_to_be16(upper_32_bits(addr)); + fqd->context_a.lo = cpu_to_be32(lower_32_bits(addr)); +} + +/* convert a threshold value into mant+exp representation */ +static inline int qm_fqd_set_taildrop(struct qm_fqd *fqd, u32 val, + int roundup) +{ + u32 e = 0; + int td, oddbit = 0; + + if (val > QM_FQD_TD_MAX) + return -ERANGE; + + while (val > QM_FQD_TD_MANT_MAX) { + oddbit = val & 1; + val >>= 1; + e++; + if (roundup && oddbit) + val++; + } + + td = (val << QM_FQD_TD_MANT_OFF) & QM_FQD_TD_MANT_MASK; + td |= (e & QM_FQD_TD_EXP_MASK); + fqd->td = cpu_to_be16(td); + return 0; +} +/* and the other direction */ +static inline int qm_fqd_get_taildrop(const struct qm_fqd *fqd) +{ + int td = be16_to_cpu(fqd->td); + + return ((td & QM_FQD_TD_MANT_MASK) >> QM_FQD_TD_MANT_OFF) + << (td & QM_FQD_TD_EXP_MASK); +} + +static inline void qm_fqd_set_stashing(struct qm_fqd *fqd, u8 as, u8 ds, u8 cs) +{ + struct qm_fqd_stashing *st = &fqd->context_a.stashing; + + st->cl = ((as & QM_FQD_XS_MASK) << QM_FQD_AS_OFF) | + ((ds & QM_FQD_XS_MASK) << QM_FQD_DS_OFF) | + (cs & QM_FQD_XS_MASK); +} + +static inline u8 qm_fqd_get_stashing(const struct qm_fqd *fqd) +{ + return fqd->context_a.stashing.cl; +} + +static inline void qm_fqd_set_oac(struct qm_fqd *fqd, u8 val) +{ + fqd->oac_init.oac = val << QM_FQD_OAC_OFF; +} + +static inline void qm_fqd_set_oal(struct qm_fqd *fqd, s8 val) +{ + fqd->oac_init.oal = val; +} + +static inline void qm_fqd_set_destwq(struct qm_fqd *fqd, int ch, int wq) +{ + fqd->dest_wq = cpu_to_be16((ch << QM_FQD_CHAN_OFF) | + (wq & QM_FQD_WQ_MASK)); +} + +static inline int qm_fqd_get_chan(const struct qm_fqd *fqd) +{ + return be16_to_cpu(fqd->dest_wq) >> QM_FQD_CHAN_OFF; +} + +static inline int qm_fqd_get_wq(const struct qm_fqd *fqd) +{ + return be16_to_cpu(fqd->dest_wq) & QM_FQD_WQ_MASK; +} + +/* See "Frame Queue Descriptor (FQD)" */ +/* Frame Queue Descriptor (FQD) field 'fq_ctrl' uses these constants */ +#define QM_FQCTRL_MASK 0x07ff /* 'fq_ctrl' flags; */ +#define QM_FQCTRL_CGE 0x0400 /* Congestion Group Enable */ +#define QM_FQCTRL_TDE 0x0200 /* Tail-Drop Enable */ +#define QM_FQCTRL_CTXASTASHING 0x0080 /* Context-A stashing */ +#define QM_FQCTRL_CPCSTASH 0x0040 /* CPC Stash Enable */ +#define QM_FQCTRL_FORCESFDR 0x0008 /* High-priority SFDRs */ +#define QM_FQCTRL_AVOIDBLOCK 0x0004 /* Don't block active */ +#define QM_FQCTRL_HOLDACTIVE 0x0002 /* Hold active in portal */ +#define QM_FQCTRL_PREFERINCACHE 0x0001 /* Aggressively cache FQD */ +#define QM_FQCTRL_LOCKINCACHE QM_FQCTRL_PREFERINCACHE /* older naming */ + +/* See "FQD Context_A field used for [...] */ +/* Frame Queue Descriptor (FQD) field 'CONTEXT_A' uses these constants */ +#define QM_STASHING_EXCL_ANNOTATION 0x04 +#define QM_STASHING_EXCL_DATA 0x02 +#define QM_STASHING_EXCL_CTX 0x01 + +/* See "Intra Class Scheduling" */ +/* FQD field 'OAC' (Overhead ACcounting) uses these constants */ +#define QM_OAC_ICS 0x2 /* Accounting for Intra-Class Scheduling */ +#define QM_OAC_CG 0x1 /* Accounting for Congestion Groups */ + +/* + * This struct represents the 32-bit "WR_PARM_[GYR]" parameters in CGR fields + * and associated commands/responses. The WRED parameters are calculated from + * these fields as follows; + * MaxTH = MA * (2 ^ Mn) + * Slope = SA / (2 ^ Sn) + * MaxP = 4 * (Pn + 1) + */ +struct qm_cgr_wr_parm { + /* MA[24-31], Mn[19-23], SA[12-18], Sn[6-11], Pn[0-5] */ + u32 word; +}; +/* + * This struct represents the 13-bit "CS_THRES" CGR field. In the corresponding + * management commands, this is padded to a 16-bit structure field, so that's + * how we represent it here. The congestion state threshold is calculated from + * these fields as follows; + * CS threshold = TA * (2 ^ Tn) + */ +struct qm_cgr_cs_thres { + /* _res[13-15], TA[5-12], Tn[0-4] */ + u16 word; +}; +/* + * This identical structure of CGR fields is present in the "Init/Modify CGR" + * commands and the "Query CGR" result. It's suctioned out here into its own + * struct. + */ +struct __qm_mc_cgr { + struct qm_cgr_wr_parm wr_parm_g; + struct qm_cgr_wr_parm wr_parm_y; + struct qm_cgr_wr_parm wr_parm_r; + u8 wr_en_g; /* boolean, use QM_CGR_EN */ + u8 wr_en_y; /* boolean, use QM_CGR_EN */ + u8 wr_en_r; /* boolean, use QM_CGR_EN */ + u8 cscn_en; /* boolean, use QM_CGR_EN */ + union { + struct { + u16 cscn_targ_upd_ctrl; /* use QM_CSCN_TARG_UDP_ */ + u16 cscn_targ_dcp_low; /* CSCN_TARG_DCP low-16bits */ + }; + u32 cscn_targ; /* use QM_CGR_TARG_* */ + }; + u8 cstd_en; /* boolean, use QM_CGR_EN */ + u8 cs; /* boolean, only used in query response */ + struct qm_cgr_cs_thres cs_thres; /* use qm_cgr_cs_thres_set64() */ + u8 mode; /* QMAN_CGR_MODE_FRAME not supported in rev1.0 */ +} __packed; +#define QM_CGR_EN 0x01 /* For wr_en_*, cscn_en, cstd_en */ +#define QM_CGR_TARG_UDP_CTRL_WRITE_BIT 0x8000 /* value written to portal bit*/ +#define QM_CGR_TARG_UDP_CTRL_DCP 0x4000 /* 0: SWP, 1: DCP */ +#define QM_CGR_TARG_PORTAL(n) (0x80000000 >> (n)) /* s/w portal, 0-9 */ +#define QM_CGR_TARG_FMAN0 0x00200000 /* direct-connect portal: fman0 */ +#define QM_CGR_TARG_FMAN1 0x00100000 /* : fman1 */ +/* Convert CGR thresholds to/from "cs_thres" format */ +static inline u64 qm_cgr_cs_thres_get64(const struct qm_cgr_cs_thres *th) +{ + return ((th->word >> 5) & 0xff) << (th->word & 0x1f); +} + +static inline int qm_cgr_cs_thres_set64(struct qm_cgr_cs_thres *th, u64 val, + int roundup) +{ + u32 e = 0; + int oddbit = 0; + + while (val > 0xff) { + oddbit = val & 1; + val >>= 1; + e++; + if (roundup && oddbit) + val++; + } + th->word = ((val & 0xff) << 5) | (e & 0x1f); + return 0; +} + +/* "Initialize FQ" */ +struct qm_mcc_initfq { + u8 __reserved1[2]; + u16 we_mask; /* Write Enable Mask */ + u32 fqid; /* 24-bit */ + u16 count; /* Initialises 'count+1' FQDs */ + struct qm_fqd fqd; /* the FQD fields go here */ + u8 __reserved2[30]; +} __packed; +/* "Initialize/Modify CGR" */ +struct qm_mcc_initcgr { + u8 __reserve1[2]; + u16 we_mask; /* Write Enable Mask */ + struct __qm_mc_cgr cgr; /* CGR fields */ + u8 __reserved2[2]; + u8 cgid; + u8 __reserved3[32]; +} __packed; + +/* INITFQ-specific flags */ +#define QM_INITFQ_WE_MASK 0x01ff /* 'Write Enable' flags; */ +#define QM_INITFQ_WE_OAC 0x0100 +#define QM_INITFQ_WE_ORPC 0x0080 +#define QM_INITFQ_WE_CGID 0x0040 +#define QM_INITFQ_WE_FQCTRL 0x0020 +#define QM_INITFQ_WE_DESTWQ 0x0010 +#define QM_INITFQ_WE_ICSCRED 0x0008 +#define QM_INITFQ_WE_TDTHRESH 0x0004 +#define QM_INITFQ_WE_CONTEXTB 0x0002 +#define QM_INITFQ_WE_CONTEXTA 0x0001 +/* INITCGR/MODIFYCGR-specific flags */ +#define QM_CGR_WE_MASK 0x07ff /* 'Write Enable Mask'; */ +#define QM_CGR_WE_WR_PARM_G 0x0400 +#define QM_CGR_WE_WR_PARM_Y 0x0200 +#define QM_CGR_WE_WR_PARM_R 0x0100 +#define QM_CGR_WE_WR_EN_G 0x0080 +#define QM_CGR_WE_WR_EN_Y 0x0040 +#define QM_CGR_WE_WR_EN_R 0x0020 +#define QM_CGR_WE_CSCN_EN 0x0010 +#define QM_CGR_WE_CSCN_TARG 0x0008 +#define QM_CGR_WE_CSTD_EN 0x0004 +#define QM_CGR_WE_CS_THRES 0x0002 +#define QM_CGR_WE_MODE 0x0001 + +#define QMAN_CGR_FLAG_USE_INIT 0x00000001 + + /* Portal and Frame Queues */ +/* Represents a managed portal */ +struct qman_portal; + +/* + * This object type represents QMan frame queue descriptors (FQD), it is + * cacheline-aligned, and initialised by qman_create_fq(). The structure is + * defined further down. + */ +struct qman_fq; + +/* + * This object type represents a QMan congestion group, it is defined further + * down. + */ +struct qman_cgr; + +/* + * This enum, and the callback type that returns it, are used when handling + * dequeued frames via DQRR. Note that for "null" callbacks registered with the + * portal object (for handling dequeues that do not demux because contextB is + * NULL), the return value *MUST* be qman_cb_dqrr_consume. + */ +enum qman_cb_dqrr_result { + /* DQRR entry can be consumed */ + qman_cb_dqrr_consume, + /* Like _consume, but requests parking - FQ must be held-active */ + qman_cb_dqrr_park, + /* Does not consume, for DCA mode only. */ + qman_cb_dqrr_defer, + /* + * Stop processing without consuming this ring entry. Exits the current + * qman_p_poll_dqrr() or interrupt-handling, as appropriate. If within + * an interrupt handler, the callback would typically call + * qman_irqsource_remove(QM_PIRQ_DQRI) before returning this value, + * otherwise the interrupt will reassert immediately. + */ + qman_cb_dqrr_stop, + /* Like qman_cb_dqrr_stop, but consumes the current entry. */ + qman_cb_dqrr_consume_stop +}; +typedef enum qman_cb_dqrr_result (*qman_cb_dqrr)(struct qman_portal *qm, + struct qman_fq *fq, + const struct qm_dqrr_entry *dqrr); + +/* + * This callback type is used when handling ERNs, FQRNs and FQRLs via MR. They + * are always consumed after the callback returns. + */ +typedef void (*qman_cb_mr)(struct qman_portal *qm, struct qman_fq *fq, + const union qm_mr_entry *msg); + +/* + * s/w-visible states. Ie. tentatively scheduled + truly scheduled + active + + * held-active + held-suspended are just "sched". Things like "retired" will not + * be assumed until it is complete (ie. QMAN_FQ_STATE_CHANGING is set until + * then, to indicate it's completing and to gate attempts to retry the retire + * command). Note, park commands do not set QMAN_FQ_STATE_CHANGING because it's + * technically impossible in the case of enqueue DCAs (which refer to DQRR ring + * index rather than the FQ that ring entry corresponds to), so repeated park + * commands are allowed (if you're silly enough to try) but won't change FQ + * state, and the resulting park notifications move FQs from "sched" to + * "parked". + */ +enum qman_fq_state { + qman_fq_state_oos, + qman_fq_state_parked, + qman_fq_state_sched, + qman_fq_state_retired +}; + +#define QMAN_FQ_STATE_CHANGING 0x80000000 /* 'state' is changing */ +#define QMAN_FQ_STATE_NE 0x40000000 /* retired FQ isn't empty */ +#define QMAN_FQ_STATE_ORL 0x20000000 /* retired FQ has ORL */ +#define QMAN_FQ_STATE_BLOCKOOS 0xe0000000 /* if any are set, no OOS */ +#define QMAN_FQ_STATE_CGR_EN 0x10000000 /* CGR enabled */ +#define QMAN_FQ_STATE_VDQCR 0x08000000 /* being volatile dequeued */ + +/* + * Frame queue objects (struct qman_fq) are stored within memory passed to + * qman_create_fq(), as this allows stashing of caller-provided demux callback + * pointers at no extra cost to stashing of (driver-internal) FQ state. If the + * caller wishes to add per-FQ state and have it benefit from dequeue-stashing, + * they should; + * + * (a) extend the qman_fq structure with their state; eg. + * + * // myfq is allocated and driver_fq callbacks filled in; + * struct my_fq { + * struct qman_fq base; + * int an_extra_field; + * [ ... add other fields to be associated with each FQ ...] + * } *myfq = some_my_fq_allocator(); + * struct qman_fq *fq = qman_create_fq(fqid, flags, &myfq->base); + * + * // in a dequeue callback, access extra fields from 'fq' via a cast; + * struct my_fq *myfq = (struct my_fq *)fq; + * do_something_with(myfq->an_extra_field); + * [...] + * + * (b) when and if configuring the FQ for context stashing, specify how ever + * many cachelines are required to stash 'struct my_fq', to accelerate not + * only the QMan driver but the callback as well. + */ + +struct qman_fq_cb { + qman_cb_dqrr dqrr; /* for dequeued frames */ + qman_cb_mr ern; /* for s/w ERNs */ + qman_cb_mr fqs; /* frame-queue state changes*/ +}; + +struct qman_fq { + /* Caller of qman_create_fq() provides these demux callbacks */ + struct qman_fq_cb cb; + /* + * These are internal to the driver, don't touch. In particular, they + * may change, be removed, or extended (so you shouldn't rely on + * sizeof(qman_fq) being a constant). + */ + u32 fqid, idx; + unsigned long flags; + enum qman_fq_state state; + int cgr_groupid; +}; + +/* + * This callback type is used when handling congestion group entry/exit. + * 'congested' is non-zero on congestion-entry, and zero on congestion-exit. + */ +typedef void (*qman_cb_cgr)(struct qman_portal *qm, + struct qman_cgr *cgr, int congested); + +struct qman_cgr { + /* Set these prior to qman_create_cgr() */ + u32 cgrid; /* 0..255, but u32 to allow specials like -1, 256, etc.*/ + qman_cb_cgr cb; + /* These are private to the driver */ + u16 chan; /* portal channel this object is created on */ + struct list_head node; +}; + +/* Flags to qman_create_fq() */ +#define QMAN_FQ_FLAG_NO_ENQUEUE 0x00000001 /* can't enqueue */ +#define QMAN_FQ_FLAG_NO_MODIFY 0x00000002 /* can only enqueue */ +#define QMAN_FQ_FLAG_TO_DCPORTAL 0x00000004 /* consumed by CAAM/PME/Fman */ +#define QMAN_FQ_FLAG_DYNAMIC_FQID 0x00000020 /* (de)allocate fqid */ + +/* Flags to qman_init_fq() */ +#define QMAN_INITFQ_FLAG_SCHED 0x00000001 /* schedule rather than park */ +#define QMAN_INITFQ_FLAG_LOCAL 0x00000004 /* set dest portal */ + + /* Portal Management */ +/** + * qman_p_irqsource_add - add processing sources to be interrupt-driven + * @bits: bitmask of QM_PIRQ_**I processing sources + * + * Adds processing sources that should be interrupt-driven (rather than + * processed via qman_poll_***() functions). + */ +void qman_p_irqsource_add(struct qman_portal *p, u32 bits); + +/** + * qman_p_irqsource_remove - remove processing sources from being int-driven + * @bits: bitmask of QM_PIRQ_**I processing sources + * + * Removes processing sources from being interrupt-driven, so that they will + * instead be processed via qman_poll_***() functions. + */ +void qman_p_irqsource_remove(struct qman_portal *p, u32 bits); + +/** + * qman_affine_cpus - return a mask of cpus that have affine portals + */ +const cpumask_t *qman_affine_cpus(void); + +/** + * qman_affine_channel - return the channel ID of an portal + * @cpu: the cpu whose affine portal is the subject of the query + * + * If @cpu is -1, the affine portal for the current CPU will be used. It is a + * bug to call this function for any value of @cpu (other than -1) that is not a + * member of the mask returned from qman_affine_cpus(). + */ +u16 qman_affine_channel(int cpu); + +/** + * qman_get_affine_portal - return the portal pointer affine to cpu + * @cpu: the cpu whose affine portal is the subject of the query + */ +struct qman_portal *qman_get_affine_portal(int cpu); + +/** + * qman_p_poll_dqrr - process DQRR (fast-path) entries + * @limit: the maximum number of DQRR entries to process + * + * Use of this function requires that DQRR processing not be interrupt-driven. + * The return value represents the number of DQRR entries processed. + */ +int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit); + +/** + * qman_p_static_dequeue_add - Add pool channels to the portal SDQCR + * @pools: bit-mask of pool channels, using QM_SDQCR_CHANNELS_POOL(n) + * + * Adds a set of pool channels to the portal's static dequeue command register + * (SDQCR). The requested pools are limited to those the portal has dequeue + * access to. + */ +void qman_p_static_dequeue_add(struct qman_portal *p, u32 pools); + + /* FQ management */ +/** + * qman_create_fq - Allocates a FQ + * @fqid: the index of the FQD to encapsulate, must be "Out of Service" + * @flags: bit-mask of QMAN_FQ_FLAG_*** options + * @fq: memory for storing the 'fq', with callbacks filled in + * + * Creates a frame queue object for the given @fqid, unless the + * QMAN_FQ_FLAG_DYNAMIC_FQID flag is set in @flags, in which case a FQID is + * dynamically allocated (or the function fails if none are available). Once + * created, the caller should not touch the memory at 'fq' except as extended to + * adjacent memory for user-defined fields (see the definition of "struct + * qman_fq" for more info). NO_MODIFY is only intended for enqueuing to + * pre-existing frame-queues that aren't to be otherwise interfered with, it + * prevents all other modifications to the frame queue. The TO_DCPORTAL flag + * causes the driver to honour any contextB modifications requested in the + * qm_init_fq() API, as this indicates the frame queue will be consumed by a + * direct-connect portal (PME, CAAM, or Fman). When frame queues are consumed by + * software portals, the contextB field is controlled by the driver and can't be + * modified by the caller. + */ +int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq); + +/** + * qman_destroy_fq - Deallocates a FQ + * @fq: the frame queue object to release + * + * The memory for this frame queue object ('fq' provided in qman_create_fq()) is + * not deallocated but the caller regains ownership, to do with as desired. The + * FQ must be in the 'out-of-service' or in the 'parked' state. + */ +void qman_destroy_fq(struct qman_fq *fq); + +/** + * qman_fq_fqid - Queries the frame queue ID of a FQ object + * @fq: the frame queue object to query + */ +u32 qman_fq_fqid(struct qman_fq *fq); + +/** + * qman_init_fq - Initialises FQ fields, leaves the FQ "parked" or "scheduled" + * @fq: the frame queue object to modify, must be 'parked' or new. + * @flags: bit-mask of QMAN_INITFQ_FLAG_*** options + * @opts: the FQ-modification settings, as defined in the low-level API + * + * The @opts parameter comes from the low-level portal API. Select + * QMAN_INITFQ_FLAG_SCHED in @flags to cause the frame queue to be scheduled + * rather than parked. NB, @opts can be NULL. + * + * Note that some fields and options within @opts may be ignored or overwritten + * by the driver; + * 1. the 'count' and 'fqid' fields are always ignored (this operation only + * affects one frame queue: @fq). + * 2. the QM_INITFQ_WE_CONTEXTB option of the 'we_mask' field and the associated + * 'fqd' structure's 'context_b' field are sometimes overwritten; + * - if @fq was not created with QMAN_FQ_FLAG_TO_DCPORTAL, then context_b is + * initialised to a value used by the driver for demux. + * - if context_b is initialised for demux, so is context_a in case stashing + * is requested (see item 4). + * (So caller control of context_b is only possible for TO_DCPORTAL frame queue + * objects.) + * 3. if @flags contains QMAN_INITFQ_FLAG_LOCAL, the 'fqd' structure's + * 'dest::channel' field will be overwritten to match the portal used to issue + * the command. If the WE_DESTWQ write-enable bit had already been set by the + * caller, the channel workqueue will be left as-is, otherwise the write-enable + * bit is set and the workqueue is set to a default of 4. If the "LOCAL" flag + * isn't set, the destination channel/workqueue fields and the write-enable bit + * are left as-is. + * 4. if the driver overwrites context_a/b for demux, then if + * QM_INITFQ_WE_CONTEXTA is set, the driver will only overwrite + * context_a.address fields and will leave the stashing fields provided by the + * user alone, otherwise it will zero out the context_a.stashing fields. + */ +int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts); + +/** + * qman_schedule_fq - Schedules a FQ + * @fq: the frame queue object to schedule, must be 'parked' + * + * Schedules the frame queue, which must be Parked, which takes it to + * Tentatively-Scheduled or Truly-Scheduled depending on its fill-level. + */ +int qman_schedule_fq(struct qman_fq *fq); + +/** + * qman_retire_fq - Retires a FQ + * @fq: the frame queue object to retire + * @flags: FQ flags (QMAN_FQ_STATE*) if retirement completes immediately + * + * Retires the frame queue. This returns zero if it succeeds immediately, +1 if + * the retirement was started asynchronously, otherwise it returns negative for + * failure. When this function returns zero, @flags is set to indicate whether + * the retired FQ is empty and/or whether it has any ORL fragments (to show up + * as ERNs). Otherwise the corresponding flags will be known when a subsequent + * FQRN message shows up on the portal's message ring. + * + * NB, if the retirement is asynchronous (the FQ was in the Truly Scheduled or + * Active state), the completion will be via the message ring as a FQRN - but + * the corresponding callback may occur before this function returns!! Ie. the + * caller should be prepared to accept the callback as the function is called, + * not only once it has returned. + */ +int qman_retire_fq(struct qman_fq *fq, u32 *flags); + +/** + * qman_oos_fq - Puts a FQ "out of service" + * @fq: the frame queue object to be put out-of-service, must be 'retired' + * + * The frame queue must be retired and empty, and if any order restoration list + * was released as ERNs at the time of retirement, they must all be consumed. + */ +int qman_oos_fq(struct qman_fq *fq); + +/** + * qman_enqueue - Enqueue a frame to a frame queue + * @fq: the frame queue object to enqueue to + * @fd: a descriptor of the frame to be enqueued + * + * Fills an entry in the EQCR of portal @qm to enqueue the frame described by + * @fd. The descriptor details are copied from @fd to the EQCR entry, the 'pid' + * field is ignored. The return value is non-zero on error, such as ring full. + */ +int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd); + +/** + * qman_alloc_fqid_range - Allocate a contiguous range of FQIDs + * @result: is set by the API to the base FQID of the allocated range + * @count: the number of FQIDs required + * + * Returns 0 on success, or a negative error code. + */ +int qman_alloc_fqid_range(u32 *result, u32 count); +#define qman_alloc_fqid(result) qman_alloc_fqid_range(result, 1) + +/** + * qman_release_fqid - Release the specified frame queue ID + * @fqid: the FQID to be released back to the resource pool + * + * This function can also be used to seed the allocator with + * FQID ranges that it can subsequently allocate from. + * Returns 0 on success, or a negative error code. + */ +int qman_release_fqid(u32 fqid); + + /* Pool-channel management */ +/** + * qman_alloc_pool_range - Allocate a contiguous range of pool-channel IDs + * @result: is set by the API to the base pool-channel ID of the allocated range + * @count: the number of pool-channel IDs required + * + * Returns 0 on success, or a negative error code. + */ +int qman_alloc_pool_range(u32 *result, u32 count); +#define qman_alloc_pool(result) qman_alloc_pool_range(result, 1) + +/** + * qman_release_pool - Release the specified pool-channel ID + * @id: the pool-chan ID to be released back to the resource pool + * + * This function can also be used to seed the allocator with + * pool-channel ID ranges that it can subsequently allocate from. + * Returns 0 on success, or a negative error code. + */ +int qman_release_pool(u32 id); + + /* CGR management */ +/** + * qman_create_cgr - Register a congestion group object + * @cgr: the 'cgr' object, with fields filled in + * @flags: QMAN_CGR_FLAG_* values + * @opts: optional state of CGR settings + * + * Registers this object to receiving congestion entry/exit callbacks on the + * portal affine to the cpu portal on which this API is executed. If opts is + * NULL then only the callback (cgr->cb) function is registered. If @flags + * contains QMAN_CGR_FLAG_USE_INIT, then an init hw command (which will reset + * any unspecified parameters) will be used rather than a modify hw hardware + * (which only modifies the specified parameters). + */ +int qman_create_cgr(struct qman_cgr *cgr, u32 flags, + struct qm_mcc_initcgr *opts); + +/** + * qman_delete_cgr - Deregisters a congestion group object + * @cgr: the 'cgr' object to deregister + * + * "Unplugs" this CGR object from the portal affine to the cpu on which this API + * is executed. This must be excuted on the same affine portal on which it was + * created. + */ +int qman_delete_cgr(struct qman_cgr *cgr); + +/** + * qman_delete_cgr_safe - Deregisters a congestion group object from any CPU + * @cgr: the 'cgr' object to deregister + * + * This will select the proper CPU and run there qman_delete_cgr(). + */ +void qman_delete_cgr_safe(struct qman_cgr *cgr); + +/** + * qman_query_cgr_congested - Queries CGR's congestion status + * @cgr: the 'cgr' object to query + * @result: returns 'cgr's congestion status, 1 (true) if congested + */ +int qman_query_cgr_congested(struct qman_cgr *cgr, bool *result); + +/** + * qman_alloc_cgrid_range - Allocate a contiguous range of CGR IDs + * @result: is set by the API to the base CGR ID of the allocated range + * @count: the number of CGR IDs required + * + * Returns 0 on success, or a negative error code. + */ +int qman_alloc_cgrid_range(u32 *result, u32 count); +#define qman_alloc_cgrid(result) qman_alloc_cgrid_range(result, 1) + +/** + * qman_release_cgrid - Release the specified CGR ID + * @id: the CGR ID to be released back to the resource pool + * + * This function can also be used to seed the allocator with + * CGR ID ranges that it can subsequently allocate from. + * Returns 0 on success, or a negative error code. + */ +int qman_release_cgrid(u32 id); + +#endif /* __FSL_QMAN_H */ -- GitLab From 97e0d385b13998980252ff63123d8ebc4138db0a Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 22 Sep 2016 18:04:10 +0300 Subject: [PATCH 0130/1167] soc/bman: Add self-test for BMan driver Add a self test for the DPAA 1.x Buffer Manager driver. This test ensures that the driver can properly acquire and release buffers using the BMan portal infrastructure. Signed-off-by: Roy Pledge Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/Kconfig | 16 +++ drivers/soc/fsl/qbman/Makefile | 4 + drivers/soc/fsl/qbman/bman_test.c | 53 +++++++++ drivers/soc/fsl/qbman/bman_test.h | 35 ++++++ drivers/soc/fsl/qbman/bman_test_api.c | 151 ++++++++++++++++++++++++++ 5 files changed, 259 insertions(+) create mode 100644 drivers/soc/fsl/qbman/bman_test.c create mode 100644 drivers/soc/fsl/qbman/bman_test.h create mode 100644 drivers/soc/fsl/qbman/bman_test_api.c diff --git a/drivers/soc/fsl/qbman/Kconfig b/drivers/soc/fsl/qbman/Kconfig index 8f2df64224bf9..e6da6a2f396d8 100644 --- a/drivers/soc/fsl/qbman/Kconfig +++ b/drivers/soc/fsl/qbman/Kconfig @@ -25,4 +25,20 @@ config FSL_DPAA_CHECKING Compiles in additional checks, to sanity-check the drivers and any use of the exported API. Not recommended for performance. +config FSL_BMAN_TEST + tristate "BMan self-tests" + help + Compile the BMan self-test code. These tests will + exercise the BMan APIs to confirm functionality + of both the software drivers and hardware device. + +config FSL_BMAN_TEST_API + bool "High-level API self-test" + depends on FSL_BMAN_TEST + default y + help + This requires the presence of cpu-affine portals, and performs + high-level API testing with them (whichever portal(s) are affine + to the cpu(s) the test executes on). + endif # FSL_DPAA diff --git a/drivers/soc/fsl/qbman/Makefile b/drivers/soc/fsl/qbman/Makefile index 6e0ee30b28344..714dd97484b31 100644 --- a/drivers/soc/fsl/qbman/Makefile +++ b/drivers/soc/fsl/qbman/Makefile @@ -1,3 +1,7 @@ obj-$(CONFIG_FSL_DPAA) += bman_ccsr.o qman_ccsr.o \ bman_portal.o qman_portal.o \ bman.o qman.o + +obj-$(CONFIG_FSL_BMAN_TEST) += bman-test.o +bman-test-y = bman_test.o +bman-test-$(CONFIG_FSL_BMAN_TEST_API) += bman_test_api.o diff --git a/drivers/soc/fsl/qbman/bman_test.c b/drivers/soc/fsl/qbman/bman_test.c new file mode 100644 index 0000000000000..09b1c960b26a9 --- /dev/null +++ b/drivers/soc/fsl/qbman/bman_test.c @@ -0,0 +1,53 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_test.h" + +MODULE_AUTHOR("Geoff Thorpe"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("BMan testing"); + +static int test_init(void) +{ +#ifdef CONFIG_FSL_BMAN_TEST_API + int loop = 1; + + while (loop--) + bman_test_api(); +#endif + return 0; +} + +static void test_exit(void) +{ +} + +module_init(test_init); +module_exit(test_exit); diff --git a/drivers/soc/fsl/qbman/bman_test.h b/drivers/soc/fsl/qbman/bman_test.h new file mode 100644 index 0000000000000..037ed342add41 --- /dev/null +++ b/drivers/soc/fsl/qbman/bman_test.h @@ -0,0 +1,35 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_priv.h" + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +void bman_test_api(void); diff --git a/drivers/soc/fsl/qbman/bman_test_api.c b/drivers/soc/fsl/qbman/bman_test_api.c new file mode 100644 index 0000000000000..6f6bdd154fe39 --- /dev/null +++ b/drivers/soc/fsl/qbman/bman_test_api.c @@ -0,0 +1,151 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_test.h" + +#define NUM_BUFS 93 +#define LOOPS 3 +#define BMAN_TOKEN_MASK 0x00FFFFFFFFFFLLU + +static struct bman_pool *pool; +static struct bm_buffer bufs_in[NUM_BUFS] ____cacheline_aligned; +static struct bm_buffer bufs_out[NUM_BUFS] ____cacheline_aligned; +static int bufs_received; + +static void bufs_init(void) +{ + int i; + + for (i = 0; i < NUM_BUFS; i++) + bm_buffer_set64(&bufs_in[i], 0xfedc01234567LLU * i); + bufs_received = 0; +} + +static inline int bufs_cmp(const struct bm_buffer *a, const struct bm_buffer *b) +{ + if (bman_ip_rev == BMAN_REV20 || bman_ip_rev == BMAN_REV21) { + + /* + * On SoCs with BMan revison 2.0, BMan only respects the 40 + * LS-bits of buffer addresses, masking off the upper 8-bits on + * release commands. The API provides for 48-bit addresses + * because some SoCs support all 48-bits. When generating + * garbage addresses for testing, we either need to zero the + * upper 8-bits when releasing to BMan (otherwise we'll be + * disappointed when the buffers we acquire back from BMan + * don't match), or we need to mask the upper 8-bits off when + * comparing. We do the latter. + */ + if ((bm_buffer_get64(a) & BMAN_TOKEN_MASK) < + (bm_buffer_get64(b) & BMAN_TOKEN_MASK)) + return -1; + if ((bm_buffer_get64(a) & BMAN_TOKEN_MASK) > + (bm_buffer_get64(b) & BMAN_TOKEN_MASK)) + return 1; + } else { + if (bm_buffer_get64(a) < bm_buffer_get64(b)) + return -1; + if (bm_buffer_get64(a) > bm_buffer_get64(b)) + return 1; + } + + return 0; +} + +static void bufs_confirm(void) +{ + int i, j; + + for (i = 0; i < NUM_BUFS; i++) { + int matches = 0; + + for (j = 0; j < NUM_BUFS; j++) + if (!bufs_cmp(&bufs_in[i], &bufs_out[j])) + matches++; + WARN_ON(matches != 1); + } +} + +/* test */ +void bman_test_api(void) +{ + int i, loops = LOOPS; + + bufs_init(); + + pr_info("%s(): Starting\n", __func__); + + pool = bman_new_pool(); + if (!pool) { + pr_crit("bman_new_pool() failed\n"); + goto failed; + } + + /* Release buffers */ +do_loop: + i = 0; + while (i < NUM_BUFS) { + int num = 8; + + if (i + num > NUM_BUFS) + num = NUM_BUFS - i; + if (bman_release(pool, bufs_in + i, num)) { + pr_crit("bman_release() failed\n"); + goto failed; + } + i += num; + } + + /* Acquire buffers */ + while (i > 0) { + int tmp, num = 8; + + if (num > i) + num = i; + tmp = bman_acquire(pool, bufs_out + i - num, num); + WARN_ON(tmp != num); + i -= num; + } + i = bman_acquire(pool, NULL, 1); + WARN_ON(i > 0); + + bufs_confirm(); + + if (--loops) + goto do_loop; + + /* Clean up */ + bman_free_pool(pool); + pr_info("%s(): Finished\n", __func__); + return; + +failed: + WARN_ON(1); +} -- GitLab From de7756233994b48cfc4d948904380cd0453a0063 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 22 Sep 2016 18:04:11 +0300 Subject: [PATCH 0131/1167] soc/qman: Add self-test for QMan driver Add self tests for the DPAA 1.x Queue Manager driver. The tests ensure that the driver can properly enqueue and dequeue to/from frame queues using the QMan portal infrastructure. Signed-off-by: Roy Pledge Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/Kconfig | 23 + drivers/soc/fsl/qbman/Makefile | 5 + drivers/soc/fsl/qbman/qman_test.c | 62 +++ drivers/soc/fsl/qbman/qman_test.h | 36 ++ drivers/soc/fsl/qbman/qman_test_api.c | 252 ++++++++++ drivers/soc/fsl/qbman/qman_test_stash.c | 617 ++++++++++++++++++++++++ 6 files changed, 995 insertions(+) create mode 100644 drivers/soc/fsl/qbman/qman_test.c create mode 100644 drivers/soc/fsl/qbman/qman_test.h create mode 100644 drivers/soc/fsl/qbman/qman_test_api.c create mode 100644 drivers/soc/fsl/qbman/qman_test_stash.c diff --git a/drivers/soc/fsl/qbman/Kconfig b/drivers/soc/fsl/qbman/Kconfig index e6da6a2f396d8..757033c0586c5 100644 --- a/drivers/soc/fsl/qbman/Kconfig +++ b/drivers/soc/fsl/qbman/Kconfig @@ -41,4 +41,27 @@ config FSL_BMAN_TEST_API high-level API testing with them (whichever portal(s) are affine to the cpu(s) the test executes on). +config FSL_QMAN_TEST + tristate "QMan self-tests" + help + Compile self-test code for QMan. + +config FSL_QMAN_TEST_API + bool "QMan high-level self-test" + depends on FSL_QMAN_TEST + default y + help + This requires the presence of cpu-affine portals, and performs + high-level API testing with them (whichever portal(s) are affine to + the cpu(s) the test executes on). + +config FSL_QMAN_TEST_STASH + bool "QMan 'hot potato' data-stashing self-test" + depends on FSL_QMAN_TEST + default y + help + This performs a "hot potato" style test enqueuing/dequeuing a frame + across a series of FQs scheduled to different portals (and cpus), with + DQRR, data and context stashing always on. + endif # FSL_DPAA diff --git a/drivers/soc/fsl/qbman/Makefile b/drivers/soc/fsl/qbman/Makefile index 714dd97484b31..7ae199f1664ee 100644 --- a/drivers/soc/fsl/qbman/Makefile +++ b/drivers/soc/fsl/qbman/Makefile @@ -5,3 +5,8 @@ obj-$(CONFIG_FSL_DPAA) += bman_ccsr.o qman_ccsr.o \ obj-$(CONFIG_FSL_BMAN_TEST) += bman-test.o bman-test-y = bman_test.o bman-test-$(CONFIG_FSL_BMAN_TEST_API) += bman_test_api.o + +obj-$(CONFIG_FSL_QMAN_TEST) += qman-test.o +qman-test-y = qman_test.o +qman-test-$(CONFIG_FSL_QMAN_TEST_API) += qman_test_api.o +qman-test-$(CONFIG_FSL_QMAN_TEST_STASH) += qman_test_stash.o diff --git a/drivers/soc/fsl/qbman/qman_test.c b/drivers/soc/fsl/qbman/qman_test.c new file mode 100644 index 0000000000000..18f7f0202fa77 --- /dev/null +++ b/drivers/soc/fsl/qbman/qman_test.c @@ -0,0 +1,62 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_test.h" + +MODULE_AUTHOR("Geoff Thorpe"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("QMan testing"); + +static int test_init(void) +{ + int loop = 1; + int err = 0; + + while (loop--) { +#ifdef CONFIG_FSL_QMAN_TEST_STASH + err = qman_test_stash(); + if (err) + break; +#endif +#ifdef CONFIG_FSL_QMAN_TEST_API + err = qman_test_api(); + if (err) + break; +#endif + } + return err; +} + +static void test_exit(void) +{ +} + +module_init(test_init); +module_exit(test_exit); diff --git a/drivers/soc/fsl/qbman/qman_test.h b/drivers/soc/fsl/qbman/qman_test.h new file mode 100644 index 0000000000000..d5f8cb2260dc1 --- /dev/null +++ b/drivers/soc/fsl/qbman/qman_test.h @@ -0,0 +1,36 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_priv.h" + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +int qman_test_stash(void); +int qman_test_api(void); diff --git a/drivers/soc/fsl/qbman/qman_test_api.c b/drivers/soc/fsl/qbman/qman_test_api.c new file mode 100644 index 0000000000000..6880ff17f45e3 --- /dev/null +++ b/drivers/soc/fsl/qbman/qman_test_api.c @@ -0,0 +1,252 @@ +/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_test.h" + +#define CGR_ID 27 +#define POOL_ID 2 +#define FQ_FLAGS QMAN_FQ_FLAG_DYNAMIC_FQID +#define NUM_ENQUEUES 10 +#define NUM_PARTIAL 4 +#define PORTAL_SDQCR (QM_SDQCR_SOURCE_CHANNELS | \ + QM_SDQCR_TYPE_PRIO_QOS | \ + QM_SDQCR_TOKEN_SET(0x98) | \ + QM_SDQCR_CHANNELS_DEDICATED | \ + QM_SDQCR_CHANNELS_POOL(POOL_ID)) +#define PORTAL_OPAQUE ((void *)0xf00dbeef) +#define VDQCR_FLAGS (QMAN_VOLATILE_FLAG_WAIT | QMAN_VOLATILE_FLAG_FINISH) + +static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *, + struct qman_fq *, + const struct qm_dqrr_entry *); +static void cb_ern(struct qman_portal *, struct qman_fq *, + const union qm_mr_entry *); +static void cb_fqs(struct qman_portal *, struct qman_fq *, + const union qm_mr_entry *); + +static struct qm_fd fd, fd_dq; +static struct qman_fq fq_base = { + .cb.dqrr = cb_dqrr, + .cb.ern = cb_ern, + .cb.fqs = cb_fqs +}; +static DECLARE_WAIT_QUEUE_HEAD(waitqueue); +static int retire_complete, sdqcr_complete; + +/* Helpers for initialising and "incrementing" a frame descriptor */ +static void fd_init(struct qm_fd *fd) +{ + qm_fd_addr_set64(fd, 0xabdeadbeefLLU); + qm_fd_set_contig_big(fd, 0x0000ffff); + fd->cmd = 0xfeedf00d; +} + +static void fd_inc(struct qm_fd *fd) +{ + u64 t = qm_fd_addr_get64(fd); + int z = t >> 40; + unsigned int len, off; + enum qm_fd_format fmt; + + t <<= 1; + if (z) + t |= 1; + qm_fd_addr_set64(fd, t); + + fmt = qm_fd_get_format(fd); + off = qm_fd_get_offset(fd); + len = qm_fd_get_length(fd); + len--; + qm_fd_set_param(fd, fmt, off, len); + + fd->cmd++; +} + +/* The only part of the 'fd' we can't memcmp() is the ppid */ +static int fd_cmp(const struct qm_fd *a, const struct qm_fd *b) +{ + int r = (qm_fd_addr_get64(a) == qm_fd_addr_get64(b)) ? 0 : -1; + + if (!r) { + enum qm_fd_format fmt_a, fmt_b; + + fmt_a = qm_fd_get_format(a); + fmt_b = qm_fd_get_format(b); + r = fmt_a - fmt_b; + } + if (!r) + r = a->cfg - b->cfg; + if (!r) + r = a->cmd - b->cmd; + return r; +} + +/* test */ +static int do_enqueues(struct qman_fq *fq) +{ + unsigned int loop; + int err = 0; + + for (loop = 0; loop < NUM_ENQUEUES; loop++) { + if (qman_enqueue(fq, &fd)) { + pr_crit("qman_enqueue() failed\n"); + err = -EIO; + } + fd_inc(&fd); + } + + return err; +} + +int qman_test_api(void) +{ + unsigned int flags, frmcnt; + int err; + struct qman_fq *fq = &fq_base; + + pr_info("%s(): Starting\n", __func__); + fd_init(&fd); + fd_init(&fd_dq); + + /* Initialise (parked) FQ */ + err = qman_create_fq(0, FQ_FLAGS, fq); + if (err) { + pr_crit("qman_create_fq() failed\n"); + goto failed; + } + err = qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, NULL); + if (err) { + pr_crit("qman_init_fq() failed\n"); + goto failed; + } + /* Do enqueues + VDQCR, twice. (Parked FQ) */ + err = do_enqueues(fq); + if (err) + goto failed; + pr_info("VDQCR (till-empty);\n"); + frmcnt = QM_VDQCR_NUMFRAMES_TILLEMPTY; + err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt); + if (err) { + pr_crit("qman_volatile_dequeue() failed\n"); + goto failed; + } + err = do_enqueues(fq); + if (err) + goto failed; + pr_info("VDQCR (%d of %d);\n", NUM_PARTIAL, NUM_ENQUEUES); + frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_PARTIAL); + err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt); + if (err) { + pr_crit("qman_volatile_dequeue() failed\n"); + goto failed; + } + pr_info("VDQCR (%d of %d);\n", NUM_ENQUEUES - NUM_PARTIAL, + NUM_ENQUEUES); + frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_ENQUEUES - NUM_PARTIAL); + err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt); + if (err) { + pr_err("qman_volatile_dequeue() failed\n"); + goto failed; + } + + err = do_enqueues(fq); + if (err) + goto failed; + pr_info("scheduled dequeue (till-empty)\n"); + err = qman_schedule_fq(fq); + if (err) { + pr_crit("qman_schedule_fq() failed\n"); + goto failed; + } + wait_event(waitqueue, sdqcr_complete); + + /* Retire and OOS the FQ */ + err = qman_retire_fq(fq, &flags); + if (err < 0) { + pr_crit("qman_retire_fq() failed\n"); + goto failed; + } + wait_event(waitqueue, retire_complete); + if (flags & QMAN_FQ_STATE_BLOCKOOS) { + err = -EIO; + pr_crit("leaking frames\n"); + goto failed; + } + err = qman_oos_fq(fq); + if (err) { + pr_crit("qman_oos_fq() failed\n"); + goto failed; + } + qman_destroy_fq(fq); + pr_info("%s(): Finished\n", __func__); + return 0; + +failed: + WARN_ON(1); + return err; +} + +static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + if (WARN_ON(fd_cmp(&fd_dq, &dq->fd))) { + pr_err("BADNESS: dequeued frame doesn't match;\n"); + return qman_cb_dqrr_consume; + } + fd_inc(&fd_dq); + if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_cmp(&fd_dq, &fd)) { + sdqcr_complete = 1; + wake_up(&waitqueue); + } + return qman_cb_dqrr_consume; +} + +static void cb_ern(struct qman_portal *p, struct qman_fq *fq, + const union qm_mr_entry *msg) +{ + pr_crit("cb_ern() unimplemented"); + WARN_ON(1); +} + +static void cb_fqs(struct qman_portal *p, struct qman_fq *fq, + const union qm_mr_entry *msg) +{ + u8 verb = (msg->verb & QM_MR_VERB_TYPE_MASK); + + if ((verb != QM_MR_VERB_FQRN) && (verb != QM_MR_VERB_FQRNI)) { + pr_crit("unexpected FQS message"); + WARN_ON(1); + return; + } + pr_info("Retirement message received\n"); + retire_complete = 1; + wake_up(&waitqueue); +} diff --git a/drivers/soc/fsl/qbman/qman_test_stash.c b/drivers/soc/fsl/qbman/qman_test_stash.c new file mode 100644 index 0000000000000..43cf66ba42f59 --- /dev/null +++ b/drivers/soc/fsl/qbman/qman_test_stash.c @@ -0,0 +1,617 @@ +/* Copyright 2009 - 2016 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_test.h" + +#include +#include + +/* + * Algorithm: + * + * Each cpu will have HP_PER_CPU "handlers" set up, each of which incorporates + * an rx/tx pair of FQ objects (both of which are stashed on dequeue). The + * organisation of FQIDs is such that the HP_PER_CPU*NUM_CPUS handlers will + * shuttle a "hot potato" frame around them such that every forwarding action + * moves it from one cpu to another. (The use of more than one handler per cpu + * is to allow enough handlers/FQs to truly test the significance of caching - + * ie. when cache-expiries are occurring.) + * + * The "hot potato" frame content will be HP_NUM_WORDS*4 bytes in size, and the + * first and last words of the frame data will undergo a transformation step on + * each forwarding action. To achieve this, each handler will be assigned a + * 32-bit "mixer", that is produced using a 32-bit LFSR. When a frame is + * received by a handler, the mixer of the expected sender is XOR'd into all + * words of the entire frame, which is then validated against the original + * values. Then, before forwarding, the entire frame is XOR'd with the mixer of + * the current handler. Apart from validating that the frame is taking the + * expected path, this also provides some quasi-realistic overheads to each + * forwarding action - dereferencing *all* the frame data, computation, and + * conditional branching. There is a "special" handler designated to act as the + * instigator of the test by creating an enqueuing the "hot potato" frame, and + * to determine when the test has completed by counting HP_LOOPS iterations. + * + * Init phases: + * + * 1. prepare each cpu's 'hp_cpu' struct using on_each_cpu(,,1) and link them + * into 'hp_cpu_list'. Specifically, set processor_id, allocate HP_PER_CPU + * handlers and link-list them (but do no other handler setup). + * + * 2. scan over 'hp_cpu_list' HP_PER_CPU times, the first time sets each + * hp_cpu's 'iterator' to point to its first handler. With each loop, + * allocate rx/tx FQIDs and mixer values to the hp_cpu's iterator handler + * and advance the iterator for the next loop. This includes a final fixup, + * which connects the last handler to the first (and which is why phase 2 + * and 3 are separate). + * + * 3. scan over 'hp_cpu_list' HP_PER_CPU times, the first time sets each + * hp_cpu's 'iterator' to point to its first handler. With each loop, + * initialise FQ objects and advance the iterator for the next loop. + * Moreover, do this initialisation on the cpu it applies to so that Rx FQ + * initialisation targets the correct cpu. + */ + +/* + * helper to run something on all cpus (can't use on_each_cpu(), as that invokes + * the fn from irq context, which is too restrictive). + */ +struct bstrap { + int (*fn)(void); + atomic_t started; +}; +static int bstrap_fn(void *bs) +{ + struct bstrap *bstrap = bs; + int err; + + atomic_inc(&bstrap->started); + err = bstrap->fn(); + if (err) + return err; + while (!kthread_should_stop()) + msleep(20); + return 0; +} +static int on_all_cpus(int (*fn)(void)) +{ + int cpu; + + for_each_cpu(cpu, cpu_online_mask) { + struct bstrap bstrap = { + .fn = fn, + .started = ATOMIC_INIT(0) + }; + struct task_struct *k = kthread_create(bstrap_fn, &bstrap, + "hotpotato%d", cpu); + int ret; + + if (IS_ERR(k)) + return -ENOMEM; + kthread_bind(k, cpu); + wake_up_process(k); + /* + * If we call kthread_stop() before the "wake up" has had an + * effect, then the thread may exit with -EINTR without ever + * running the function. So poll until it's started before + * requesting it to stop. + */ + while (!atomic_read(&bstrap.started)) + msleep(20); + ret = kthread_stop(k); + if (ret) + return ret; + } + return 0; +} + +struct hp_handler { + + /* The following data is stashed when 'rx' is dequeued; */ + /* -------------- */ + /* The Rx FQ, dequeues of which will stash the entire hp_handler */ + struct qman_fq rx; + /* The Tx FQ we should forward to */ + struct qman_fq tx; + /* The value we XOR post-dequeue, prior to validating */ + u32 rx_mixer; + /* The value we XOR pre-enqueue, after validating */ + u32 tx_mixer; + /* what the hotpotato address should be on dequeue */ + dma_addr_t addr; + u32 *frame_ptr; + + /* The following data isn't (necessarily) stashed on dequeue; */ + /* -------------- */ + u32 fqid_rx, fqid_tx; + /* list node for linking us into 'hp_cpu' */ + struct list_head node; + /* Just to check ... */ + unsigned int processor_id; +} ____cacheline_aligned; + +struct hp_cpu { + /* identify the cpu we run on; */ + unsigned int processor_id; + /* root node for the per-cpu list of handlers */ + struct list_head handlers; + /* list node for linking us into 'hp_cpu_list' */ + struct list_head node; + /* + * when repeatedly scanning 'hp_list', each time linking the n'th + * handlers together, this is used as per-cpu iterator state + */ + struct hp_handler *iterator; +}; + +/* Each cpu has one of these */ +static DEFINE_PER_CPU(struct hp_cpu, hp_cpus); + +/* links together the hp_cpu structs, in first-come first-serve order. */ +static LIST_HEAD(hp_cpu_list); +static spinlock_t hp_lock = __SPIN_LOCK_UNLOCKED(hp_lock); + +static unsigned int hp_cpu_list_length; + +/* the "special" handler, that starts and terminates the test. */ +static struct hp_handler *special_handler; +static int loop_counter; + +/* handlers are allocated out of this, so they're properly aligned. */ +static struct kmem_cache *hp_handler_slab; + +/* this is the frame data */ +static void *__frame_ptr; +static u32 *frame_ptr; +static dma_addr_t frame_dma; + +/* the main function waits on this */ +static DECLARE_WAIT_QUEUE_HEAD(queue); + +#define HP_PER_CPU 2 +#define HP_LOOPS 8 +/* 80 bytes, like a small ethernet frame, and bleeds into a second cacheline */ +#define HP_NUM_WORDS 80 +/* First word of the LFSR-based frame data */ +#define HP_FIRST_WORD 0xabbaf00d + +static inline u32 do_lfsr(u32 prev) +{ + return (prev >> 1) ^ (-(prev & 1u) & 0xd0000001u); +} + +static int allocate_frame_data(void) +{ + u32 lfsr = HP_FIRST_WORD; + int loop; + struct platform_device *pdev = platform_device_alloc("foobar", -1); + + if (!pdev) { + pr_crit("platform_device_alloc() failed"); + return -EIO; + } + if (platform_device_add(pdev)) { + pr_crit("platform_device_add() failed"); + return -EIO; + } + __frame_ptr = kmalloc(4 * HP_NUM_WORDS, GFP_KERNEL); + if (!__frame_ptr) + return -ENOMEM; + + frame_ptr = PTR_ALIGN(__frame_ptr, 64); + for (loop = 0; loop < HP_NUM_WORDS; loop++) { + frame_ptr[loop] = lfsr; + lfsr = do_lfsr(lfsr); + } + frame_dma = dma_map_single(&pdev->dev, frame_ptr, 4 * HP_NUM_WORDS, + DMA_BIDIRECTIONAL); + platform_device_del(pdev); + platform_device_put(pdev); + return 0; +} + +static void deallocate_frame_data(void) +{ + kfree(__frame_ptr); +} + +static inline int process_frame_data(struct hp_handler *handler, + const struct qm_fd *fd) +{ + u32 *p = handler->frame_ptr; + u32 lfsr = HP_FIRST_WORD; + int loop; + + if (qm_fd_addr_get64(fd) != handler->addr) { + pr_crit("bad frame address"); + return -EIO; + } + for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) { + *p ^= handler->rx_mixer; + if (*p != lfsr) { + pr_crit("corrupt frame data"); + return -EIO; + } + *p ^= handler->tx_mixer; + lfsr = do_lfsr(lfsr); + } + return 0; +} + +static enum qman_cb_dqrr_result normal_dqrr(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dqrr) +{ + struct hp_handler *handler = (struct hp_handler *)fq; + + if (process_frame_data(handler, &dqrr->fd)) { + WARN_ON(1); + goto skip; + } + if (qman_enqueue(&handler->tx, &dqrr->fd)) { + pr_crit("qman_enqueue() failed"); + WARN_ON(1); + } +skip: + return qman_cb_dqrr_consume; +} + +static enum qman_cb_dqrr_result special_dqrr(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dqrr) +{ + struct hp_handler *handler = (struct hp_handler *)fq; + + process_frame_data(handler, &dqrr->fd); + if (++loop_counter < HP_LOOPS) { + if (qman_enqueue(&handler->tx, &dqrr->fd)) { + pr_crit("qman_enqueue() failed"); + WARN_ON(1); + goto skip; + } + } else { + pr_info("Received final (%dth) frame\n", loop_counter); + wake_up(&queue); + } +skip: + return qman_cb_dqrr_consume; +} + +static int create_per_cpu_handlers(void) +{ + struct hp_handler *handler; + int loop; + struct hp_cpu *hp_cpu = this_cpu_ptr(&hp_cpus); + + hp_cpu->processor_id = smp_processor_id(); + spin_lock(&hp_lock); + list_add_tail(&hp_cpu->node, &hp_cpu_list); + hp_cpu_list_length++; + spin_unlock(&hp_lock); + INIT_LIST_HEAD(&hp_cpu->handlers); + for (loop = 0; loop < HP_PER_CPU; loop++) { + handler = kmem_cache_alloc(hp_handler_slab, GFP_KERNEL); + if (!handler) { + pr_crit("kmem_cache_alloc() failed"); + WARN_ON(1); + return -EIO; + } + handler->processor_id = hp_cpu->processor_id; + handler->addr = frame_dma; + handler->frame_ptr = frame_ptr; + list_add_tail(&handler->node, &hp_cpu->handlers); + } + return 0; +} + +static int destroy_per_cpu_handlers(void) +{ + struct list_head *loop, *tmp; + struct hp_cpu *hp_cpu = this_cpu_ptr(&hp_cpus); + + spin_lock(&hp_lock); + list_del(&hp_cpu->node); + spin_unlock(&hp_lock); + list_for_each_safe(loop, tmp, &hp_cpu->handlers) { + u32 flags = 0; + struct hp_handler *handler = list_entry(loop, struct hp_handler, + node); + if (qman_retire_fq(&handler->rx, &flags) || + (flags & QMAN_FQ_STATE_BLOCKOOS)) { + pr_crit("qman_retire_fq(rx) failed, flags: %x", flags); + WARN_ON(1); + return -EIO; + } + if (qman_oos_fq(&handler->rx)) { + pr_crit("qman_oos_fq(rx) failed"); + WARN_ON(1); + return -EIO; + } + qman_destroy_fq(&handler->rx); + qman_destroy_fq(&handler->tx); + qman_release_fqid(handler->fqid_rx); + list_del(&handler->node); + kmem_cache_free(hp_handler_slab, handler); + } + return 0; +} + +static inline u8 num_cachelines(u32 offset) +{ + u8 res = (offset + (L1_CACHE_BYTES - 1)) + / (L1_CACHE_BYTES); + if (res > 3) + return 3; + return res; +} +#define STASH_DATA_CL \ + num_cachelines(HP_NUM_WORDS * 4) +#define STASH_CTX_CL \ + num_cachelines(offsetof(struct hp_handler, fqid_rx)) + +static int init_handler(void *h) +{ + struct qm_mcc_initfq opts; + struct hp_handler *handler = h; + int err; + + if (handler->processor_id != smp_processor_id()) { + err = -EIO; + goto failed; + } + /* Set up rx */ + memset(&handler->rx, 0, sizeof(handler->rx)); + if (handler == special_handler) + handler->rx.cb.dqrr = special_dqrr; + else + handler->rx.cb.dqrr = normal_dqrr; + err = qman_create_fq(handler->fqid_rx, 0, &handler->rx); + if (err) { + pr_crit("qman_create_fq(rx) failed"); + goto failed; + } + memset(&opts, 0, sizeof(opts)); + opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_CONTEXTA; + opts.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING; + qm_fqd_set_stashing(&opts.fqd, 0, STASH_DATA_CL, STASH_CTX_CL); + err = qman_init_fq(&handler->rx, QMAN_INITFQ_FLAG_SCHED | + QMAN_INITFQ_FLAG_LOCAL, &opts); + if (err) { + pr_crit("qman_init_fq(rx) failed"); + goto failed; + } + /* Set up tx */ + memset(&handler->tx, 0, sizeof(handler->tx)); + err = qman_create_fq(handler->fqid_tx, QMAN_FQ_FLAG_NO_MODIFY, + &handler->tx); + if (err) { + pr_crit("qman_create_fq(tx) failed"); + goto failed; + } + + return 0; +failed: + return err; +} + +static void init_handler_cb(void *h) +{ + if (init_handler(h)) + WARN_ON(1); +} + +static int init_phase2(void) +{ + int loop; + u32 fqid = 0; + u32 lfsr = 0xdeadbeef; + struct hp_cpu *hp_cpu; + struct hp_handler *handler; + + for (loop = 0; loop < HP_PER_CPU; loop++) { + list_for_each_entry(hp_cpu, &hp_cpu_list, node) { + int err; + + if (!loop) + hp_cpu->iterator = list_first_entry( + &hp_cpu->handlers, + struct hp_handler, node); + else + hp_cpu->iterator = list_entry( + hp_cpu->iterator->node.next, + struct hp_handler, node); + /* Rx FQID is the previous handler's Tx FQID */ + hp_cpu->iterator->fqid_rx = fqid; + /* Allocate new FQID for Tx */ + err = qman_alloc_fqid(&fqid); + if (err) { + pr_crit("qman_alloc_fqid() failed"); + return err; + } + hp_cpu->iterator->fqid_tx = fqid; + /* Rx mixer is the previous handler's Tx mixer */ + hp_cpu->iterator->rx_mixer = lfsr; + /* Get new mixer for Tx */ + lfsr = do_lfsr(lfsr); + hp_cpu->iterator->tx_mixer = lfsr; + } + } + /* Fix up the first handler (fqid_rx==0, rx_mixer=0xdeadbeef) */ + hp_cpu = list_first_entry(&hp_cpu_list, struct hp_cpu, node); + handler = list_first_entry(&hp_cpu->handlers, struct hp_handler, node); + if (handler->fqid_rx != 0 || handler->rx_mixer != 0xdeadbeef) + return 1; + handler->fqid_rx = fqid; + handler->rx_mixer = lfsr; + /* and tag it as our "special" handler */ + special_handler = handler; + return 0; +} + +static int init_phase3(void) +{ + int loop, err; + struct hp_cpu *hp_cpu; + + for (loop = 0; loop < HP_PER_CPU; loop++) { + list_for_each_entry(hp_cpu, &hp_cpu_list, node) { + if (!loop) + hp_cpu->iterator = list_first_entry( + &hp_cpu->handlers, + struct hp_handler, node); + else + hp_cpu->iterator = list_entry( + hp_cpu->iterator->node.next, + struct hp_handler, node); + preempt_disable(); + if (hp_cpu->processor_id == smp_processor_id()) { + err = init_handler(hp_cpu->iterator); + if (err) + return err; + } else { + smp_call_function_single(hp_cpu->processor_id, + init_handler_cb, hp_cpu->iterator, 1); + } + preempt_enable(); + } + } + return 0; +} + +static int send_first_frame(void *ignore) +{ + u32 *p = special_handler->frame_ptr; + u32 lfsr = HP_FIRST_WORD; + int loop, err; + struct qm_fd fd; + + if (special_handler->processor_id != smp_processor_id()) { + err = -EIO; + goto failed; + } + memset(&fd, 0, sizeof(fd)); + qm_fd_addr_set64(&fd, special_handler->addr); + qm_fd_set_contig_big(&fd, HP_NUM_WORDS * 4); + for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) { + if (*p != lfsr) { + err = -EIO; + pr_crit("corrupt frame data"); + goto failed; + } + *p ^= special_handler->tx_mixer; + lfsr = do_lfsr(lfsr); + } + pr_info("Sending first frame\n"); + err = qman_enqueue(&special_handler->tx, &fd); + if (err) { + pr_crit("qman_enqueue() failed"); + goto failed; + } + + return 0; +failed: + return err; +} + +static void send_first_frame_cb(void *ignore) +{ + if (send_first_frame(NULL)) + WARN_ON(1); +} + +int qman_test_stash(void) +{ + int err; + + if (cpumask_weight(cpu_online_mask) < 2) { + pr_info("%s(): skip - only 1 CPU\n", __func__); + return 0; + } + + pr_info("%s(): Starting\n", __func__); + + hp_cpu_list_length = 0; + loop_counter = 0; + hp_handler_slab = kmem_cache_create("hp_handler_slab", + sizeof(struct hp_handler), L1_CACHE_BYTES, + SLAB_HWCACHE_ALIGN, NULL); + if (!hp_handler_slab) { + err = -EIO; + pr_crit("kmem_cache_create() failed"); + goto failed; + } + + err = allocate_frame_data(); + if (err) + goto failed; + + /* Init phase 1 */ + pr_info("Creating %d handlers per cpu...\n", HP_PER_CPU); + if (on_all_cpus(create_per_cpu_handlers)) { + err = -EIO; + pr_crit("on_each_cpu() failed"); + goto failed; + } + pr_info("Number of cpus: %d, total of %d handlers\n", + hp_cpu_list_length, hp_cpu_list_length * HP_PER_CPU); + + err = init_phase2(); + if (err) + goto failed; + + err = init_phase3(); + if (err) + goto failed; + + preempt_disable(); + if (special_handler->processor_id == smp_processor_id()) { + err = send_first_frame(NULL); + if (err) + goto failed; + } else { + smp_call_function_single(special_handler->processor_id, + send_first_frame_cb, NULL, 1); + } + preempt_enable(); + + wait_event(queue, loop_counter == HP_LOOPS); + deallocate_frame_data(); + if (on_all_cpus(destroy_per_cpu_handlers)) { + err = -EIO; + pr_crit("on_each_cpu() failed"); + goto failed; + } + kmem_cache_destroy(hp_handler_slab); + pr_info("%s(): Finished\n", __func__); + + return 0; +failed: + WARN_ON(1); + return err; +} -- GitLab From e0b80f00bb96b925995d53980e0c764430bedb42 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 22 Sep 2016 18:04:12 +0300 Subject: [PATCH 0132/1167] arch/powerpc: Add CONFIG_FSL_DPAA to corenetXX_smp_defconfig Enable the drivers on the powerpc arch. Signed-off-by: Roy Pledge Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- arch/powerpc/Makefile | 4 ++-- arch/powerpc/configs/dpaa.config | 1 + drivers/soc/Kconfig | 1 + drivers/soc/fsl/Makefile | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/configs/dpaa.config diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 50d020ac0f487..617dece679242 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -318,12 +318,12 @@ mpc85xx_smp_defconfig: PHONY += corenet32_smp_defconfig corenet32_smp_defconfig: $(call merge_into_defconfig,corenet_basic_defconfig,\ - 85xx-32bit 85xx-smp 85xx-hw fsl-emb-nonhw) + 85xx-32bit 85xx-smp 85xx-hw fsl-emb-nonhw dpaa) PHONY += corenet64_smp_defconfig corenet64_smp_defconfig: $(call merge_into_defconfig,corenet_basic_defconfig,\ - 85xx-64bit 85xx-smp altivec 85xx-hw fsl-emb-nonhw) + 85xx-64bit 85xx-smp altivec 85xx-hw fsl-emb-nonhw dpaa) PHONY += mpc86xx_defconfig mpc86xx_defconfig: diff --git a/arch/powerpc/configs/dpaa.config b/arch/powerpc/configs/dpaa.config new file mode 100644 index 0000000000000..efa99c0485434 --- /dev/null +++ b/arch/powerpc/configs/dpaa.config @@ -0,0 +1 @@ +CONFIG_FSL_DPAA=y diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index fe42a2fdf351c..e6e90e80519a7 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -1,6 +1,7 @@ menu "SOC (System On Chip) specific Drivers" source "drivers/soc/bcm/Kconfig" +source "drivers/soc/fsl/qbman/Kconfig" source "drivers/soc/fsl/qe/Kconfig" source "drivers/soc/mediatek/Kconfig" source "drivers/soc/qcom/Kconfig" diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile index 203307fd92c15..75e1f53348210 100644 --- a/drivers/soc/fsl/Makefile +++ b/drivers/soc/fsl/Makefile @@ -2,5 +2,6 @@ # Makefile for the Linux Kernel SOC fsl specific device drivers # +obj-$(CONFIG_FSL_DPAA) += qbman/ obj-$(CONFIG_QUICC_ENGINE) += qe/ obj-$(CONFIG_CPM) += qe/ -- GitLab From 0825b8ee2e58ac6616a9936a745a8ad68b0dd362 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Mon, 26 Sep 2016 20:00:59 +0800 Subject: [PATCH 0133/1167] scsi: be2iscsi: mark symbols static where possible We get 6 warnings when building kernel with W=1: drivers/scsi/be2iscsi/be_main.c:65:1: warning: no previous prototype for 'beiscsi_log_enable_disp' [-Wmissing-prototypes] drivers/scsi/be2iscsi/be_main.c:78:1: warning: no previous prototype for 'beiscsi_log_enable_change' [-Wmissing-prototypes] drivers/scsi/be2iscsi/be_main.c:97:1: warning: no previous prototype for 'beiscsi_log_enable_store' [-Wmissing-prototypes] drivers/scsi/be2iscsi/be_main.c:116:1: warning: no previous prototype for 'beiscsi_log_enable_init' [-Wmissing-prototypes] drivers/scsi/be2iscsi/be_main.c:4587:5: warning: no previous prototype for 'beiscsi_iotask_v2' [-Wmissing-prototypes] drivers/scsi/be2iscsi/be_main.c:4976:6: warning: no previous prototype for 'beiscsi_hba_attrs_init' [-Wmissing-prototypes] In fact, these functions are only used in the file in which they are declared and don't need a declaration, but can be made static. So this patch marks these functions with 'static'. Signed-off-by: Baoyou Xie Reviewed-by: Jitendra Bhivare Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 6a6906f847dbb..68138a647dfc1 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -61,7 +61,7 @@ MODULE_PARM_DESC(be_max_phys_size, "memory that can be allocated. Range is 16 - 128"); #define beiscsi_disp_param(_name)\ -ssize_t \ +static ssize_t \ beiscsi_##_name##_disp(struct device *dev,\ struct device_attribute *attrib, char *buf) \ { \ @@ -74,7 +74,7 @@ beiscsi_##_name##_disp(struct device *dev,\ } #define beiscsi_change_param(_name, _minval, _maxval, _defaval)\ -int \ +static int \ beiscsi_##_name##_change(struct beiscsi_hba *phba, uint32_t val)\ {\ if (val >= _minval && val <= _maxval) {\ @@ -93,7 +93,7 @@ beiscsi_##_name##_change(struct beiscsi_hba *phba, uint32_t val)\ } #define beiscsi_store_param(_name) \ -ssize_t \ +static ssize_t \ beiscsi_##_name##_store(struct device *dev,\ struct device_attribute *attr, const char *buf,\ size_t count) \ @@ -112,7 +112,7 @@ beiscsi_##_name##_store(struct device *dev,\ } #define beiscsi_init_param(_name, _minval, _maxval, _defval) \ -int \ +static int \ beiscsi_##_name##_init(struct beiscsi_hba *phba, uint32_t val) \ { \ if (val >= _minval && val <= _maxval) {\ @@ -4584,7 +4584,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->cmd_bhs = NULL; return -ENOMEM; } -int beiscsi_iotask_v2(struct iscsi_task *task, struct scatterlist *sg, +static int beiscsi_iotask_v2(struct iscsi_task *task, struct scatterlist *sg, unsigned int num_sg, unsigned int xferlen, unsigned int writedir) { @@ -4973,7 +4973,7 @@ static int beiscsi_bsg_request(struct bsg_job *job) return rc; } -void beiscsi_hba_attrs_init(struct beiscsi_hba *phba) +static void beiscsi_hba_attrs_init(struct beiscsi_hba *phba) { /* Set the logging parameter */ beiscsi_log_enable_init(phba, beiscsi_log_enable); -- GitLab From 46c1cf706076500cdcde3445be97233793eec7f1 Mon Sep 17 00:00:00 2001 From: Kyuho Choi Date: Mon, 26 Sep 2016 23:58:25 +0900 Subject: [PATCH 0134/1167] scsi: ufs: Enable no vccq quirk for skhynix device This patch enable no vccq quirk for SKHynix devices. SKHynix ufs device don't need vccq vrail for device operation. Signed-off-by: Kyuho Choi Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs_quirks.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index ee4ab85e2801b..22f881e9253a2 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -25,6 +25,7 @@ #define UFS_VENDOR_TOSHIBA 0x198 #define UFS_VENDOR_SAMSUNG 0x1CE +#define UFS_VENDOR_SKHYNIX 0x1AD /** * ufs_device_info - ufs device details @@ -145,6 +146,7 @@ static struct ufs_dev_fix ufs_fixups[] = { UFS_DEVICE_QUIRK_PA_TACTIVATE), UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG", UFS_DEVICE_QUIRK_PA_TACTIVATE), + UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), END_FIX }; -- GitLab From 623290a204571b80dc6d720d47d0aa29d31f9ecd Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Mon, 26 Sep 2016 15:25:30 -0700 Subject: [PATCH 0135/1167] MAINTAINERS: Update open-iscsi maintainers Chris Leech and I are taking over as open-iscsi maintainers. Signed-off-by: Lee Duncan Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- MAINTAINERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 48f2b480ac6e2..f0ee7a6faadf1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6430,10 +6430,10 @@ S: Maintained F: drivers/firmware/iscsi_ibft* ISCSI -M: Mike Christie +M: Lee Duncan +M: Chris Leech L: open-iscsi@googlegroups.com -W: www.open-iscsi.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mnc/linux-2.6-iscsi.git +W: www.open-iscsi.com S: Maintained F: drivers/scsi/*iscsi* F: include/scsi/*iscsi* -- GitLab From fe9b34bfcb4e80b809a8a3dccdd49737d073593b Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Fri, 23 Sep 2016 20:07:40 +0530 Subject: [PATCH 0136/1167] scsi: cxgb4i: Set completion bit in work request If SKCBF_TX_FLAG_COMPL flag is set and unacknowledged credits are >= max credits / 2, set completion bit in work request to reclaim credits. Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index e4ba2d2616cdb..2487ae6be272b 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -682,6 +682,11 @@ static int push_tx_frames(struct cxgbi_sock *csk, int req_completion) req_completion); csk->snd_nxt += len; cxgbi_skcb_clear_flag(skb, SKCBF_TX_NEED_HDR); + } else if (cxgbi_skcb_test_flag(skb, SKCBF_TX_FLAG_COMPL) && + (csk->wr_una_cred >= (csk->wr_max_cred / 2))) { + struct cpl_close_con_req *req = + (struct cpl_close_con_req *)skb->data; + req->wr.wr_hi |= htonl(FW_WR_COMPL_F); } total_size += skb->truesize; t4_set_arp_err_handler(skb, csk, arp_failure_skb_discard); -- GitLab From 679a5e3f12830392d14f94b04bbe0f3cabdbd773 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 29 Sep 2016 11:58:36 +0200 Subject: [PATCH 0137/1167] cpuset: fix error handling regression in proc_cpuset_show() 4c737b41de7f ("cgroup: make cgroup_path() and friends behave in the style of strlcpy()") botched the conversion of proc_cpuset_show() and broke its error handling. It made the function return 0 on failures and fail to handle error returns from cgroup_path_ns(). Fix it. Reported-by: Dan Carpenter Signed-off-by: Tejun Heo --- kernel/cpuset.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 793ae6fd96dcd..97dd8e1787864 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -2698,12 +2698,13 @@ int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, if (!buf) goto out; - retval = -ENAMETOOLONG; css = task_get_css(tsk, cpuset_cgrp_id); retval = cgroup_path_ns(css->cgroup, buf, PATH_MAX, current->nsproxy->cgroup_ns); css_put(css); if (retval >= PATH_MAX) + retval = -ENAMETOOLONG; + if (retval < 0) goto out_free; seq_puts(m, buf); seq_putc(m, '\n'); @@ -2711,7 +2712,7 @@ int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, out_free: kfree(buf); out: - return 0; + return retval; } #endif /* CONFIG_PROC_PID_CPUSET */ -- GitLab From e0223003e6e141533446d01a92784592a97a8552 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 29 Sep 2016 15:49:40 +0200 Subject: [PATCH 0138/1167] cgroup: fix error handling regressions in proc_cgroup_show() and cgroup_release_agent() 4c737b41de7f ("cgroup: make cgroup_path() and friends behave in the style of strlcpy()") broke error handling in proc_cgroup_show() and cgroup_release_agent() by not handling negative return values from cgroup_path_ns_locked(). Fix it. Reported-by: Dan Carpenter Signed-off-by: Tejun Heo --- kernel/cgroup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 5e2e81ad9175c..a7f9fb4e1fc7d 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -5781,10 +5781,10 @@ int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) { retval = cgroup_path_ns_locked(cgrp, buf, PATH_MAX, current->nsproxy->cgroup_ns); - if (retval >= PATH_MAX) { + if (retval >= PATH_MAX) retval = -ENAMETOOLONG; + if (retval < 0) goto out_unlock; - } seq_puts(m, buf); } else { @@ -6069,7 +6069,7 @@ static void cgroup_release_agent(struct work_struct *work) spin_lock_irq(&css_set_lock); ret = cgroup_path_ns_locked(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns); spin_unlock_irq(&css_set_lock); - if (ret >= PATH_MAX) + if (ret < 0 || ret >= PATH_MAX) goto out; argv[0] = agentbuf; -- GitLab From 54f9c4d0778b3f9ab791b1b7eb1a5d2809f02f50 Mon Sep 17 00:00:00 2001 From: Alistair Popple Date: Tue, 20 Sep 2016 09:01:38 +0200 Subject: [PATCH 0139/1167] ipmi: add an Aspeed BT IPMI BMC driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a simple device driver to expose the iBT interface on Aspeed SOCs (AST2400 and AST2500) as a character device. Such SOCs are commonly used as BMCs (BaseBoard Management Controllers) and this driver implements the BMC side of the BT interface. The BT (Block Transfer) interface is used to perform in-band IPMI communication between a host and its BMC. Entire messages are buffered before sending a notification to the other end, host or BMC, that there is data to be read. Usually, the host emits requests and the BMC responses but the specification provides a mean for the BMC to send SMS Attention (BMC-to-Host attention or System Management Software attention) messages. For this purpose, the driver introduces a specific ioctl on the device: 'BT_BMC_IOCTL_SMS_ATN' that can be used by the system running on the BMC to signal the host of such an event. The device name defaults to '/dev/ipmi-bt-host' Signed-off-by: Alistair Popple Signed-off-by: Jeremy Kerr Signed-off-by: Joel Stanley [clg: - checkpatch fixes - added a devicetree binding documentation - replace 'bt_host' by 'bt_bmc' to reflect that the driver is the BMC side of the IPMI BT interface - renamed the device to 'ipmi-bt-host' - introduced a temporary buffer to copy_{to,from}_user - used platform_get_irq() - moved the driver under drivers/char/ipmi/ but kept it as a misc device - changed the compatible cell to "aspeed,ast2400-bt-bmc" ] Signed-off-by: Cédric Le Goater Acked-by: Arnd Bergmann [clg: - checkpatch --strict fixes - removed the use of devm_iounmap, devm_kfree in cleanup paths - introduced an atomic-t to limit opens to 1 - introduced a mutex to protect write/read operations] Acked-by: Rob Herring Signed-off-by: Cédric Le Goater Signed-off-by: Corey Minyard --- .../bindings/ipmi/aspeed,ast2400-bt-bmc.txt | 23 + .../bindings/{ipmi.txt => ipmi/ipmi-smic.txt} | 0 drivers/Makefile | 2 +- drivers/char/ipmi/Kconfig | 7 + drivers/char/ipmi/Makefile | 1 + drivers/char/ipmi/bt-bmc.c | 510 ++++++++++++++++++ include/uapi/linux/Kbuild | 1 + include/uapi/linux/bt-bmc.h | 18 + 8 files changed, 561 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/ipmi/aspeed,ast2400-bt-bmc.txt rename Documentation/devicetree/bindings/{ipmi.txt => ipmi/ipmi-smic.txt} (100%) create mode 100644 drivers/char/ipmi/bt-bmc.c create mode 100644 include/uapi/linux/bt-bmc.h diff --git a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-bt-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-bt-bmc.txt new file mode 100644 index 0000000000000..fbbacd9582402 --- /dev/null +++ b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-bt-bmc.txt @@ -0,0 +1,23 @@ +* Aspeed BT (Block Transfer) IPMI interface + +The Aspeed SOCs (AST2400 and AST2500) are commonly used as BMCs +(BaseBoard Management Controllers) and the BT interface can be used to +perform in-band IPMI communication with their host. + +Required properties: + +- compatible : should be "aspeed,ast2400-bt-bmc" +- reg: physical address and size of the registers + +Optional properties: + +- interrupts: interrupt generated by the BT interface. without an + interrupt, the driver will operate in poll mode. + +Example: + + ibt@1e789140 { + compatible = "aspeed,ast2400-bt-bmc"; + reg = <0x1e789140 0x18>; + interrupts = <8>; + }; diff --git a/Documentation/devicetree/bindings/ipmi.txt b/Documentation/devicetree/bindings/ipmi/ipmi-smic.txt similarity index 100% rename from Documentation/devicetree/bindings/ipmi.txt rename to Documentation/devicetree/bindings/ipmi/ipmi-smic.txt diff --git a/drivers/Makefile b/drivers/Makefile index 53abb4a5f7360..5a9e7b6b7928d 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -21,7 +21,7 @@ obj-y += video/ obj-y += idle/ # IPMI must come before ACPI in order to provide IPMI opregion support -obj-$(CONFIG_IPMI_HANDLER) += char/ipmi/ +obj-y += char/ipmi/ obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_SFI) += sfi/ diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index 5a9350b1069a3..2c234e3e75132 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -76,3 +76,10 @@ config IPMI_POWEROFF the IPMI management controller is capable of this. endif # IPMI_HANDLER + +config ASPEED_BT_IPMI_BMC + tristate "BT IPMI bmc driver" + help + Provides a driver for the BT (Block Transfer) IPMI interface + found on Aspeed SOCs (AST2400 and AST2500). The driver + implements the BMC side of the BT interface. diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index f3ffde1f5f1f5..0d98cd91def1d 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o +obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c new file mode 100644 index 0000000000000..2e880bf0be26a --- /dev/null +++ b/drivers/char/ipmi/bt-bmc.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2015-2016, IBM Corporation. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This is a BMC device used to communicate to the host + */ +#define DEVICE_NAME "ipmi-bt-host" + +#define BT_IO_BASE 0xe4 +#define BT_IRQ 10 + +#define BT_CR0 0x0 +#define BT_CR0_IO_BASE 16 +#define BT_CR0_IRQ 12 +#define BT_CR0_EN_CLR_SLV_RDP 0x8 +#define BT_CR0_EN_CLR_SLV_WRP 0x4 +#define BT_CR0_ENABLE_IBT 0x1 +#define BT_CR1 0x4 +#define BT_CR1_IRQ_H2B 0x01 +#define BT_CR1_IRQ_HBUSY 0x40 +#define BT_CR2 0x8 +#define BT_CR2_IRQ_H2B 0x01 +#define BT_CR2_IRQ_HBUSY 0x40 +#define BT_CR3 0xc +#define BT_CTRL 0x10 +#define BT_CTRL_B_BUSY 0x80 +#define BT_CTRL_H_BUSY 0x40 +#define BT_CTRL_OEM0 0x20 +#define BT_CTRL_SMS_ATN 0x10 +#define BT_CTRL_B2H_ATN 0x08 +#define BT_CTRL_H2B_ATN 0x04 +#define BT_CTRL_CLR_RD_PTR 0x02 +#define BT_CTRL_CLR_WR_PTR 0x01 +#define BT_BMC2HOST 0x14 +#define BT_INTMASK 0x18 +#define BT_INTMASK_B2H_IRQEN 0x01 +#define BT_INTMASK_B2H_IRQ 0x02 +#define BT_INTMASK_BMC_HWRST 0x80 + +#define BT_BMC_BUFFER_SIZE 256 + +struct bt_bmc { + struct device dev; + struct miscdevice miscdev; + void __iomem *base; + int irq; + wait_queue_head_t queue; + struct timer_list poll_timer; + struct mutex mutex; +}; + +static atomic_t open_count = ATOMIC_INIT(0); + +static u8 bt_inb(struct bt_bmc *bt_bmc, int reg) +{ + return ioread8(bt_bmc->base + reg); +} + +static void bt_outb(struct bt_bmc *bt_bmc, u8 data, int reg) +{ + iowrite8(data, bt_bmc->base + reg); +} + +static void clr_rd_ptr(struct bt_bmc *bt_bmc) +{ + bt_outb(bt_bmc, BT_CTRL_CLR_RD_PTR, BT_CTRL); +} + +static void clr_wr_ptr(struct bt_bmc *bt_bmc) +{ + bt_outb(bt_bmc, BT_CTRL_CLR_WR_PTR, BT_CTRL); +} + +static void clr_h2b_atn(struct bt_bmc *bt_bmc) +{ + bt_outb(bt_bmc, BT_CTRL_H2B_ATN, BT_CTRL); +} + +static void set_b_busy(struct bt_bmc *bt_bmc) +{ + if (!(bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_B_BUSY)) + bt_outb(bt_bmc, BT_CTRL_B_BUSY, BT_CTRL); +} + +static void clr_b_busy(struct bt_bmc *bt_bmc) +{ + if (bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_B_BUSY) + bt_outb(bt_bmc, BT_CTRL_B_BUSY, BT_CTRL); +} + +static void set_b2h_atn(struct bt_bmc *bt_bmc) +{ + bt_outb(bt_bmc, BT_CTRL_B2H_ATN, BT_CTRL); +} + +static u8 bt_read(struct bt_bmc *bt_bmc) +{ + return bt_inb(bt_bmc, BT_BMC2HOST); +} + +static ssize_t bt_readn(struct bt_bmc *bt_bmc, u8 *buf, size_t n) +{ + int i; + + for (i = 0; i < n; i++) + buf[i] = bt_read(bt_bmc); + return n; +} + +static void bt_write(struct bt_bmc *bt_bmc, u8 c) +{ + bt_outb(bt_bmc, c, BT_BMC2HOST); +} + +static ssize_t bt_writen(struct bt_bmc *bt_bmc, u8 *buf, size_t n) +{ + int i; + + for (i = 0; i < n; i++) + bt_write(bt_bmc, buf[i]); + return n; +} + +static void set_sms_atn(struct bt_bmc *bt_bmc) +{ + bt_outb(bt_bmc, BT_CTRL_SMS_ATN, BT_CTRL); +} + +static struct bt_bmc *file_bt_bmc(struct file *file) +{ + return container_of(file->private_data, struct bt_bmc, miscdev); +} + +static int bt_bmc_open(struct inode *inode, struct file *file) +{ + struct bt_bmc *bt_bmc = file_bt_bmc(file); + + if (atomic_inc_return(&open_count) == 1) { + clr_b_busy(bt_bmc); + return 0; + } + + atomic_dec(&open_count); + return -EBUSY; +} + +/* + * The BT (Block Transfer) interface means that entire messages are + * buffered by the host before a notification is sent to the BMC that + * there is data to be read. The first byte is the length and the + * message data follows. The read operation just tries to capture the + * whole before returning it to userspace. + * + * BT Message format : + * + * Byte 1 Byte 2 Byte 3 Byte 4 Byte 5:N + * Length NetFn/LUN Seq Cmd Data + * + */ +static ssize_t bt_bmc_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct bt_bmc *bt_bmc = file_bt_bmc(file); + u8 len; + int len_byte = 1; + u8 kbuffer[BT_BMC_BUFFER_SIZE]; + ssize_t ret = 0; + ssize_t nread; + + if (!access_ok(VERIFY_WRITE, buf, count)) + return -EFAULT; + + WARN_ON(*ppos); + + if (wait_event_interruptible(bt_bmc->queue, + bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN)) + return -ERESTARTSYS; + + mutex_lock(&bt_bmc->mutex); + + if (unlikely(!(bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN))) { + ret = -EIO; + goto out_unlock; + } + + set_b_busy(bt_bmc); + clr_h2b_atn(bt_bmc); + clr_rd_ptr(bt_bmc); + + /* + * The BT frames start with the message length, which does not + * include the length byte. + */ + kbuffer[0] = bt_read(bt_bmc); + len = kbuffer[0]; + + /* We pass the length back to userspace as well */ + if (len + 1 > count) + len = count - 1; + + while (len) { + nread = min_t(ssize_t, len, sizeof(kbuffer) - len_byte); + + bt_readn(bt_bmc, kbuffer + len_byte, nread); + + if (copy_to_user(buf, kbuffer, nread + len_byte)) { + ret = -EFAULT; + break; + } + len -= nread; + buf += nread + len_byte; + ret += nread + len_byte; + len_byte = 0; + } + + clr_b_busy(bt_bmc); + +out_unlock: + mutex_unlock(&bt_bmc->mutex); + return ret; +} + +/* + * BT Message response format : + * + * Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6:N + * Length NetFn/LUN Seq Cmd Code Data + */ +static ssize_t bt_bmc_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct bt_bmc *bt_bmc = file_bt_bmc(file); + u8 kbuffer[BT_BMC_BUFFER_SIZE]; + ssize_t ret = 0; + ssize_t nwritten; + + /* + * send a minimum response size + */ + if (count < 5) + return -EINVAL; + + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + + WARN_ON(*ppos); + + /* + * There's no interrupt for clearing bmc busy so we have to + * poll + */ + if (wait_event_interruptible(bt_bmc->queue, + !(bt_inb(bt_bmc, BT_CTRL) & + (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN)))) + return -ERESTARTSYS; + + mutex_lock(&bt_bmc->mutex); + + if (unlikely(bt_inb(bt_bmc, BT_CTRL) & + (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))) { + ret = -EIO; + goto out_unlock; + } + + clr_wr_ptr(bt_bmc); + + while (count) { + nwritten = min_t(ssize_t, count, sizeof(kbuffer)); + if (copy_from_user(&kbuffer, buf, nwritten)) { + ret = -EFAULT; + break; + } + + bt_writen(bt_bmc, kbuffer, nwritten); + + count -= nwritten; + buf += nwritten; + ret += nwritten; + } + + set_b2h_atn(bt_bmc); + +out_unlock: + mutex_unlock(&bt_bmc->mutex); + return ret; +} + +static long bt_bmc_ioctl(struct file *file, unsigned int cmd, + unsigned long param) +{ + struct bt_bmc *bt_bmc = file_bt_bmc(file); + + switch (cmd) { + case BT_BMC_IOCTL_SMS_ATN: + set_sms_atn(bt_bmc); + return 0; + } + return -EINVAL; +} + +static int bt_bmc_release(struct inode *inode, struct file *file) +{ + struct bt_bmc *bt_bmc = file_bt_bmc(file); + + atomic_dec(&open_count); + set_b_busy(bt_bmc); + return 0; +} + +static unsigned int bt_bmc_poll(struct file *file, poll_table *wait) +{ + struct bt_bmc *bt_bmc = file_bt_bmc(file); + unsigned int mask = 0; + u8 ctrl; + + poll_wait(file, &bt_bmc->queue, wait); + + ctrl = bt_inb(bt_bmc, BT_CTRL); + + if (ctrl & BT_CTRL_H2B_ATN) + mask |= POLLIN; + + if (!(ctrl & (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))) + mask |= POLLOUT; + + return mask; +} + +static const struct file_operations bt_bmc_fops = { + .owner = THIS_MODULE, + .open = bt_bmc_open, + .read = bt_bmc_read, + .write = bt_bmc_write, + .release = bt_bmc_release, + .poll = bt_bmc_poll, + .unlocked_ioctl = bt_bmc_ioctl, +}; + +static void poll_timer(unsigned long data) +{ + struct bt_bmc *bt_bmc = (void *)data; + + bt_bmc->poll_timer.expires += msecs_to_jiffies(500); + wake_up(&bt_bmc->queue); + add_timer(&bt_bmc->poll_timer); +} + +static irqreturn_t bt_bmc_irq(int irq, void *arg) +{ + struct bt_bmc *bt_bmc = arg; + u32 reg; + + reg = ioread32(bt_bmc->base + BT_CR2); + reg &= BT_CR2_IRQ_H2B | BT_CR2_IRQ_HBUSY; + if (!reg) + return IRQ_NONE; + + /* ack pending IRQs */ + iowrite32(reg, bt_bmc->base + BT_CR2); + + wake_up(&bt_bmc->queue); + return IRQ_HANDLED; +} + +static int bt_bmc_config_irq(struct bt_bmc *bt_bmc, + struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + u32 reg; + int rc; + + bt_bmc->irq = platform_get_irq(pdev, 0); + if (!bt_bmc->irq) + return -ENODEV; + + rc = devm_request_irq(dev, bt_bmc->irq, bt_bmc_irq, IRQF_SHARED, + DEVICE_NAME, bt_bmc); + if (rc < 0) { + dev_warn(dev, "Unable to request IRQ %d\n", bt_bmc->irq); + bt_bmc->irq = 0; + return rc; + } + + /* + * Configure IRQs on the bmc clearing the H2B and HBUSY bits; + * H2B will be asserted when the bmc has data for us; HBUSY + * will be cleared (along with B2H) when we can write the next + * message to the BT buffer + */ + reg = ioread32(bt_bmc->base + BT_CR1); + reg |= BT_CR1_IRQ_H2B | BT_CR1_IRQ_HBUSY; + iowrite32(reg, bt_bmc->base + BT_CR1); + + return 0; +} + +static int bt_bmc_probe(struct platform_device *pdev) +{ + struct bt_bmc *bt_bmc; + struct device *dev; + struct resource *res; + int rc; + + if (!pdev || !pdev->dev.of_node) + return -ENODEV; + + dev = &pdev->dev; + dev_info(dev, "Found bt bmc device\n"); + + bt_bmc = devm_kzalloc(dev, sizeof(*bt_bmc), GFP_KERNEL); + if (!bt_bmc) + return -ENOMEM; + + dev_set_drvdata(&pdev->dev, bt_bmc); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "Unable to find resources\n"); + return -ENXIO; + } + + bt_bmc->base = devm_ioremap_resource(&pdev->dev, res); + if (!bt_bmc->base) + return -ENOMEM; + + mutex_init(&bt_bmc->mutex); + init_waitqueue_head(&bt_bmc->queue); + + bt_bmc->miscdev.minor = MISC_DYNAMIC_MINOR, + bt_bmc->miscdev.name = DEVICE_NAME, + bt_bmc->miscdev.fops = &bt_bmc_fops, + bt_bmc->miscdev.parent = dev; + rc = misc_register(&bt_bmc->miscdev); + if (rc) { + dev_err(dev, "Unable to register misc device\n"); + return rc; + } + + bt_bmc_config_irq(bt_bmc, pdev); + + if (bt_bmc->irq) { + dev_info(dev, "Using IRQ %d\n", bt_bmc->irq); + } else { + dev_info(dev, "No IRQ; using timer\n"); + setup_timer(&bt_bmc->poll_timer, poll_timer, + (unsigned long)bt_bmc); + bt_bmc->poll_timer.expires = jiffies + msecs_to_jiffies(10); + add_timer(&bt_bmc->poll_timer); + } + + iowrite32((BT_IO_BASE << BT_CR0_IO_BASE) | + (BT_IRQ << BT_CR0_IRQ) | + BT_CR0_EN_CLR_SLV_RDP | + BT_CR0_EN_CLR_SLV_WRP | + BT_CR0_ENABLE_IBT, + bt_bmc->base + BT_CR0); + + clr_b_busy(bt_bmc); + + return 0; +} + +static int bt_bmc_remove(struct platform_device *pdev) +{ + struct bt_bmc *bt_bmc = dev_get_drvdata(&pdev->dev); + + misc_deregister(&bt_bmc->miscdev); + if (!bt_bmc->irq) + del_timer_sync(&bt_bmc->poll_timer); + return 0; +} + +static const struct of_device_id bt_bmc_match[] = { + { .compatible = "aspeed,ast2400-bt-bmc" }, + { }, +}; + +static struct platform_driver bt_bmc_driver = { + .driver = { + .name = DEVICE_NAME, + .of_match_table = bt_bmc_match, + }, + .probe = bt_bmc_probe, + .remove = bt_bmc_remove, +}; + +module_platform_driver(bt_bmc_driver); + +MODULE_DEVICE_TABLE(of, bt_bmc_match); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alistair Popple "); +MODULE_DESCRIPTION("Linux device interface to the BT interface"); diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 185f8ea2702fc..17b12942c67d0 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -74,6 +74,7 @@ header-y += bpf_common.h header-y += bpf.h header-y += bpqether.h header-y += bsg.h +header-y += bt-bmc.h header-y += btrfs.h header-y += can.h header-y += capability.h diff --git a/include/uapi/linux/bt-bmc.h b/include/uapi/linux/bt-bmc.h new file mode 100644 index 0000000000000..d9ec766a63d09 --- /dev/null +++ b/include/uapi/linux/bt-bmc.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2015-2016, IBM Corporation. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _UAPI_LINUX_BT_BMC_H +#define _UAPI_LINUX_BT_BMC_H + +#include + +#define __BT_BMC_IOCTL_MAGIC 0xb1 +#define BT_BMC_IOCTL_SMS_ATN _IO(__BT_BMC_IOCTL_MAGIC, 0x00) + +#endif /* _UAPI_LINUX_BT_BMC_H */ -- GitLab From 1a377a79211a08c5c8a05c0b6dee6d5b13ef4107 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 21 Sep 2016 19:35:53 +0930 Subject: [PATCH 0140/1167] ipmi: Fix ioremap error handling in bt-bmc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit devm_ioremap_resource returns ERR_PTR so we can't check for NULL. Signed-off-by: Joel Stanley Acked-by: Cédric Le Goater Signed-off-by: Corey Minyard --- drivers/char/ipmi/bt-bmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c index 2e880bf0be26a..de64bf1f2f4d4 100644 --- a/drivers/char/ipmi/bt-bmc.c +++ b/drivers/char/ipmi/bt-bmc.c @@ -438,8 +438,8 @@ static int bt_bmc_probe(struct platform_device *pdev) } bt_bmc->base = devm_ioremap_resource(&pdev->dev, res); - if (!bt_bmc->base) - return -ENOMEM; + if (IS_ERR(bt_bmc->base)) + return PTR_ERR(bt_bmc->base); mutex_init(&bt_bmc->mutex); init_waitqueue_head(&bt_bmc->queue); -- GitLab From a3e6061bad6292f2d5be3c1c4ccf1fa136517dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 21 Sep 2016 12:24:34 +0200 Subject: [PATCH 0141/1167] ipmi/bt-bmc: add a dependency on ARCH_ASPEED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cédric Le Goater Signed-off-by: Corey Minyard --- drivers/char/ipmi/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index 2c234e3e75132..7f816655cbbfa 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -78,6 +78,7 @@ config IPMI_POWEROFF endif # IPMI_HANDLER config ASPEED_BT_IPMI_BMC + depends on ARCH_ASPEED tristate "BT IPMI bmc driver" help Provides a driver for the BT (Block Transfer) IPMI interface -- GitLab From 6861285ce8f8a9a55aab4775847de6e48b2dc7f2 Mon Sep 17 00:00:00 2001 From: Zang Leigang Date: Thu, 25 Aug 2016 17:39:19 +0800 Subject: [PATCH 0142/1167] scsi: ufs: Data Segment only needed for WRITE DESCRIPTOR Some devices have problems handling a Query UPIU with Data Segment set. Only set it for WRITE DESCRIPTOR commands. [mkp: updated patch description] Signed-off-by: Zang Leigang Reviewed-by: Subhash Jadavani Reviewed-by: Kiwoong Kim Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 37f3c51e9d921..d2ec425126413 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1266,9 +1266,12 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD( 0, query->request.query_func, 0, 0); - /* Data segment length */ - ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD( - 0, 0, len >> 8, (u8)len); + /* Data segment length only need for WRITE_DESC */ + if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) + ucd_req_ptr->header.dword_2 = + UPIU_HEADER_DWORD(0, 0, (len >> 8), (u8)len); + else + ucd_req_ptr->header.dword_2 = 0; /* Copy the Query Request buffer as is */ memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, -- GitLab From 73811c942954a1d2470656d1bd9e990e327ac580 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 28 Sep 2016 14:49:42 +0000 Subject: [PATCH 0143/1167] scsi: ufs: Fix error return code in ufshcd_init() Fix to return a negative error code from the error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Reviewed-by: Subhash Jadavani Reviewed-by: Kiwoong Kim Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d2ec425126413..05c745663c103 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -6503,6 +6503,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) if (IS_ERR(hba->devfreq)) { dev_err(hba->dev, "Unable to register with devfreq %ld\n", PTR_ERR(hba->devfreq)); + err = PTR_ERR(hba->devfreq); goto out_remove_scsi_host; } /* Suspend devfreq until the UFS device is detected */ -- GitLab From c47946c2dda311216ac11e981809b2d70609258f Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 27 Sep 2016 21:00:23 +0200 Subject: [PATCH 0144/1167] scsi: g_NCR5380: Remove deprecated __setup Remove deprecated __setup for parsing command line parameters. g_NCR5380.* parameters could be used instead. This might break existing setups with g_NCR5380 built-in (if there are any). But it has to go in order to remove the overrides[] array. Signed-off-by: Ondrej Zary Acked-by: Finn Thain Signed-off-by: Martin K. Petersen --- Documentation/scsi/g_NCR5380.txt | 10 --- drivers/scsi/g_NCR5380.c | 135 ------------------------------- 2 files changed, 145 deletions(-) diff --git a/Documentation/scsi/g_NCR5380.txt b/Documentation/scsi/g_NCR5380.txt index fd880150aeead..843cbae88ebbb 100644 --- a/Documentation/scsi/g_NCR5380.txt +++ b/Documentation/scsi/g_NCR5380.txt @@ -21,16 +21,6 @@ NCR53c400 card, the Trantor T130B in its default configuration: The NCR53c400 does not support DMA but it does have Pseudo-DMA which is supported by the driver. -If the default configuration does not work for you, you can use the kernel -command lines (eg using the lilo append command): - ncr5380=addr,irq - ncr53c400=addr,irq - ncr53c400a=addr,irq - dtc3181e=addr,irq - -The driver does not probe for any addresses or ports other than those in -the OVERRIDE or given to the kernel as above. - This driver provides some information on what it has detected in /proc/scsi/g_NCR5380/x where x is the scsi card number as detected at boot time. More info to come in the future. diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 516bd6c4f4425..7e50b44eb36a4 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -56,136 +56,6 @@ static struct override { #define NO_OVERRIDES ARRAY_SIZE(overrides) -#ifndef MODULE - -/** - * internal_setup - handle lilo command string override - * @board: BOARD_* identifier for the board - * @str: unused - * @ints: numeric parameters - * - * Do LILO command line initialization of the overrides array. Display - * errors when needed - * - * Locks: none - */ - -static void __init internal_setup(int board, char *str, int *ints) -{ - static int commandline_current; - switch (board) { - case BOARD_NCR5380: - if (ints[0] != 2 && ints[0] != 3) { - printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); - return; - } - break; - case BOARD_NCR53C400: - if (ints[0] != 2) { - printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - case BOARD_NCR53C400A: - if (ints[0] != 2) { - printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - case BOARD_DTC3181E: - if (ints[0] != 2) { - printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - } - - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1]; - overrides[commandline_current].irq = ints[2]; - if (ints[0] == 3) - overrides[commandline_current].dma = ints[3]; - else - overrides[commandline_current].dma = DMA_NONE; - overrides[commandline_current].board = board; - ++commandline_current; - } -} - - -/** - * do_NCR53C80_setup - set up entry point - * @str: unused - * - * Setup function invoked at boot to parse the ncr5380= command - * line. - */ - -static int __init do_NCR5380_setup(char *str) -{ - int ints[10]; - - get_options(str, ARRAY_SIZE(ints), ints); - internal_setup(BOARD_NCR5380, str, ints); - return 1; -} - -/** - * do_NCR53C400_setup - set up entry point - * @str: unused - * @ints: integer parameters from kernel setup code - * - * Setup function invoked at boot to parse the ncr53c400= command - * line. - */ - -static int __init do_NCR53C400_setup(char *str) -{ - int ints[10]; - - get_options(str, ARRAY_SIZE(ints), ints); - internal_setup(BOARD_NCR53C400, str, ints); - return 1; -} - -/** - * do_NCR53C400A_setup - set up entry point - * @str: unused - * @ints: integer parameters from kernel setup code - * - * Setup function invoked at boot to parse the ncr53c400a= command - * line. - */ - -static int __init do_NCR53C400A_setup(char *str) -{ - int ints[10]; - - get_options(str, ARRAY_SIZE(ints), ints); - internal_setup(BOARD_NCR53C400A, str, ints); - return 1; -} - -/** - * do_DTC3181E_setup - set up entry point - * @str: unused - * @ints: integer parameters from kernel setup code - * - * Setup function invoked at boot to parse the dtc3181e= command - * line. - */ - -static int __init do_DTC3181E_setup(char *str) -{ - int ints[10]; - - get_options(str, ARRAY_SIZE(ints), ints); - internal_setup(BOARD_DTC3181E, str, ints); - return 1; -} - -#endif - #ifndef SCSI_G_NCR5380_MEM /* * Configure I/O address of 53C400A or DTC436 by writing magic numbers @@ -741,8 +611,3 @@ static struct isapnp_device_id id_table[] = { MODULE_DEVICE_TABLE(isapnp, id_table); #endif - -__setup("ncr5380=", do_NCR5380_setup); -__setup("ncr53c400=", do_NCR53C400_setup); -__setup("ncr53c400a=", do_NCR53C400A_setup); -__setup("dtc3181e=", do_DTC3181E_setup); -- GitLab From d91f5afe595a3c4bdc1b755225024862c2e917f0 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 27 Sep 2016 21:00:24 +0200 Subject: [PATCH 0145/1167] scsi: g_NCR5380: Reduce overrides[] from array to struct Remove compile-time card type definition GENERIC_NCR5380_OVERRIDE. Then remove all code iterating the overrides[] array and reduce it to struct card. Signed-off-by: Ondrej Zary Acked-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/g_NCR5380.c | 351 +++++++++++++++++++-------------------- 1 file changed, 167 insertions(+), 184 deletions(-) diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 7e50b44eb36a4..5162de61a92fc 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -42,19 +42,12 @@ static int ncr_53c400a; static int dtc_3181e; static int hp_c2502; -static struct override { +static struct card { NCR5380_map_type NCR5380_map_name; int irq; int dma; int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ -} overrides -#ifdef GENERIC_NCR5380_OVERRIDE -[] __initdata = GENERIC_NCR5380_OVERRIDE; -#else -[1] __initdata = { { 0,},}; -#endif - -#define NO_OVERRIDES ARRAY_SIZE(overrides) +} card; #ifndef SCSI_G_NCR5380_MEM /* @@ -85,16 +78,13 @@ static void magic_configure(int idx, u8 irq, u8 magic[]) * @tpnt: the scsi template * * Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E - * and DTC436(ISAPnP) controllers. If overrides have been set we use - * them. + * and DTC436(ISAPnP) controllers. * * Locks: none */ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) { - static int current_override; - int count; unsigned int *ports; u8 *magic = NULL; #ifndef SCSI_G_NCR5380_MEM @@ -124,28 +114,25 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) #endif if (ncr_irq) - overrides[0].irq = ncr_irq; + card.irq = ncr_irq; if (ncr_dma) - overrides[0].dma = ncr_dma; + card.dma = ncr_dma; if (ncr_addr) - overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr; + card.NCR5380_map_name = (NCR5380_map_type) ncr_addr; if (ncr_5380) - overrides[0].board = BOARD_NCR5380; + card.board = BOARD_NCR5380; else if (ncr_53c400) - overrides[0].board = BOARD_NCR53C400; + card.board = BOARD_NCR53C400; else if (ncr_53c400a) - overrides[0].board = BOARD_NCR53C400A; + card.board = BOARD_NCR53C400A; else if (dtc_3181e) - overrides[0].board = BOARD_DTC3181E; + card.board = BOARD_DTC3181E; else if (hp_c2502) - overrides[0].board = BOARD_HP_C2502; + card.board = BOARD_HP_C2502; #ifndef SCSI_G_NCR5380_MEM - if (!current_override && isapnp_present()) { + if (isapnp_present()) { struct pnp_dev *dev = NULL; - count = 0; while ((dev = pnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) { - if (count >= NO_OVERRIDES) - break; if (pnp_device_attach(dev) < 0) continue; if (pnp_activate_dev(dev) < 0) { @@ -159,202 +146,198 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) continue; } if (pnp_irq_valid(dev, 0)) - overrides[count].irq = pnp_irq(dev, 0); + card.irq = pnp_irq(dev, 0); else - overrides[count].irq = NO_IRQ; + card.irq = NO_IRQ; if (pnp_dma_valid(dev, 0)) - overrides[count].dma = pnp_dma(dev, 0); + card.dma = pnp_dma(dev, 0); else - overrides[count].dma = DMA_NONE; - overrides[count].NCR5380_map_name = (NCR5380_map_type) pnp_port_start(dev, 0); - overrides[count].board = BOARD_DTC3181E; - count++; + card.dma = DMA_NONE; + card.NCR5380_map_name = (NCR5380_map_type) pnp_port_start(dev, 0); + card.board = BOARD_DTC3181E; + break; } } #endif - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - if (!(overrides[current_override].NCR5380_map_name)) - continue; + if (!(card.NCR5380_map_name)) + return 0; - ports = NULL; - flags = 0; - switch (overrides[current_override].board) { - case BOARD_NCR5380: - flags = FLAG_NO_PSEUDO_DMA | FLAG_DMA_FIXUP; - break; - case BOARD_NCR53C400A: - ports = ncr_53c400a_ports; - magic = ncr_53c400a_magic; - break; - case BOARD_HP_C2502: - ports = ncr_53c400a_ports; - magic = hp_c2502_magic; - break; - case BOARD_DTC3181E: - ports = dtc_3181e_ports; - magic = ncr_53c400a_magic; - break; - } + ports = NULL; + flags = 0; + switch (card.board) { + case BOARD_NCR5380: + flags = FLAG_NO_PSEUDO_DMA | FLAG_DMA_FIXUP; + break; + case BOARD_NCR53C400A: + ports = ncr_53c400a_ports; + magic = ncr_53c400a_magic; + break; + case BOARD_HP_C2502: + ports = ncr_53c400a_ports; + magic = hp_c2502_magic; + break; + case BOARD_DTC3181E: + ports = dtc_3181e_ports; + magic = ncr_53c400a_magic; + break; + } #ifndef SCSI_G_NCR5380_MEM - if (ports && magic) { - /* wakeup sequence for the NCR53C400A and DTC3181E */ - - /* Disable the adapter and look for a free io port */ - magic_configure(-1, 0, magic); - - region_size = 16; - - if (overrides[current_override].NCR5380_map_name != PORT_AUTO) - for (i = 0; ports[i]; i++) { - if (!request_region(ports[i], region_size, "ncr53c80")) - continue; - if (overrides[current_override].NCR5380_map_name == ports[i]) - break; - release_region(ports[i], region_size); - } else - for (i = 0; ports[i]; i++) { - if (!request_region(ports[i], region_size, "ncr53c80")) - continue; - if (inb(ports[i]) == 0xff) - break; - release_region(ports[i], region_size); - } - if (ports[i]) { - /* At this point we have our region reserved */ - magic_configure(i, 0, magic); /* no IRQ yet */ - outb(0xc0, ports[i] + 9); - if (inb(ports[i] + 9) != 0x80) + if (ports && magic) { + /* wakeup sequence for the NCR53C400A and DTC3181E */ + + /* Disable the adapter and look for a free io port */ + magic_configure(-1, 0, magic); + + region_size = 16; + + if (card.NCR5380_map_name != PORT_AUTO) + for (i = 0; ports[i]; i++) { + if (!request_region(ports[i], region_size, "ncr53c80")) continue; - overrides[current_override].NCR5380_map_name = ports[i]; - port_idx = i; - } else - continue; - } - else - { - /* Not a 53C400A style setup - just grab */ - region_size = 8; - if (!request_region(overrides[current_override].NCR5380_map_name, - region_size, "ncr5380")) - continue; - } + if (card.NCR5380_map_name == ports[i]) + break; + release_region(ports[i], region_size); + } else + for (i = 0; ports[i]; i++) { + if (!request_region(ports[i], region_size, "ncr53c80")) + continue; + if (inb(ports[i]) == 0xff) + break; + release_region(ports[i], region_size); + } + if (ports[i]) { + /* At this point we have our region reserved */ + magic_configure(i, 0, magic); /* no IRQ yet */ + outb(0xc0, ports[i] + 9); + if (inb(ports[i] + 9) != 0x80) + return 0; + card.NCR5380_map_name = ports[i]; + port_idx = i; + } else + return 0; + } + else + { + /* Not a 53C400A style setup - just grab */ + region_size = 8; + if (!request_region(card.NCR5380_map_name, + region_size, "ncr5380")) + return 0; + } #else - base = overrides[current_override].NCR5380_map_name; - iomem_size = NCR53C400_region_size; - if (!request_mem_region(base, iomem_size, "ncr5380")) - continue; - iomem = ioremap(base, iomem_size); - if (!iomem) { - release_mem_region(base, iomem_size); - continue; - } + base = card.NCR5380_map_name; + iomem_size = NCR53C400_region_size; + if (!request_mem_region(base, iomem_size, "ncr5380")) + return 0; + iomem = ioremap(base, iomem_size); + if (!iomem) { + release_mem_region(base, iomem_size); + return 0; + } #endif - instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); - if (instance == NULL) - goto out_release; - hostdata = shost_priv(instance); + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) + goto out_release; + hostdata = shost_priv(instance); #ifndef SCSI_G_NCR5380_MEM - instance->io_port = overrides[current_override].NCR5380_map_name; - instance->n_io_port = region_size; - hostdata->io_width = 1; /* 8-bit PDMA by default */ - - /* - * On NCR53C400 boards, NCR5380 registers are mapped 8 past - * the base address. - */ - switch (overrides[current_override].board) { - case BOARD_NCR53C400: - instance->io_port += 8; - hostdata->c400_ctl_status = 0; - hostdata->c400_blk_cnt = 1; - hostdata->c400_host_buf = 4; - break; - case BOARD_DTC3181E: - hostdata->io_width = 2; /* 16-bit PDMA */ - /* fall through */ - case BOARD_NCR53C400A: - case BOARD_HP_C2502: - hostdata->c400_ctl_status = 9; - hostdata->c400_blk_cnt = 10; - hostdata->c400_host_buf = 8; - break; - } + instance->io_port = card.NCR5380_map_name; + instance->n_io_port = region_size; + hostdata->io_width = 1; /* 8-bit PDMA by default */ + + /* + * On NCR53C400 boards, NCR5380 registers are mapped 8 past + * the base address. + */ + switch (card.board) { + case BOARD_NCR53C400: + instance->io_port += 8; + hostdata->c400_ctl_status = 0; + hostdata->c400_blk_cnt = 1; + hostdata->c400_host_buf = 4; + break; + case BOARD_DTC3181E: + hostdata->io_width = 2; /* 16-bit PDMA */ + /* fall through */ + case BOARD_NCR53C400A: + case BOARD_HP_C2502: + hostdata->c400_ctl_status = 9; + hostdata->c400_blk_cnt = 10; + hostdata->c400_host_buf = 8; + break; + } #else - instance->base = overrides[current_override].NCR5380_map_name; - hostdata->iomem = iomem; - hostdata->iomem_size = iomem_size; - switch (overrides[current_override].board) { - case BOARD_NCR53C400: - hostdata->c400_ctl_status = 0x100; - hostdata->c400_blk_cnt = 0x101; - hostdata->c400_host_buf = 0x104; - break; - case BOARD_DTC3181E: - case BOARD_NCR53C400A: - case BOARD_HP_C2502: - pr_err(DRV_MODULE_NAME ": unknown register offsets\n"); - goto out_unregister; - } + instance->base = card.NCR5380_map_name; + hostdata->iomem = iomem; + hostdata->iomem_size = iomem_size; + switch (card.board) { + case BOARD_NCR53C400: + hostdata->c400_ctl_status = 0x100; + hostdata->c400_blk_cnt = 0x101; + hostdata->c400_host_buf = 0x104; + break; + case BOARD_DTC3181E: + case BOARD_NCR53C400A: + case BOARD_HP_C2502: + pr_err(DRV_MODULE_NAME ": unknown register offsets\n"); + goto out_unregister; + } #endif - if (NCR5380_init(instance, flags | FLAG_LATE_DMA_SETUP)) - goto out_unregister; + if (NCR5380_init(instance, flags | FLAG_LATE_DMA_SETUP)) + goto out_unregister; - switch (overrides[current_override].board) { - case BOARD_NCR53C400: - case BOARD_DTC3181E: - case BOARD_NCR53C400A: - case BOARD_HP_C2502: - NCR5380_write(hostdata->c400_ctl_status, CSR_BASE); - } + switch (card.board) { + case BOARD_NCR53C400: + case BOARD_DTC3181E: + case BOARD_NCR53C400A: + case BOARD_HP_C2502: + NCR5380_write(hostdata->c400_ctl_status, CSR_BASE); + } - NCR5380_maybe_reset_bus(instance); + NCR5380_maybe_reset_bus(instance); - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, 0xffff); + if (card.irq != IRQ_AUTO) + instance->irq = card.irq; + else + instance->irq = NCR5380_probe_irq(instance, 0xffff); - /* Compatibility with documented NCR5380 kernel parameters */ - if (instance->irq == 255) - instance->irq = NO_IRQ; + /* Compatibility with documented NCR5380 kernel parameters */ + if (instance->irq == 255) + instance->irq = NO_IRQ; - if (instance->irq != NO_IRQ) { + if (instance->irq != NO_IRQ) { #ifndef SCSI_G_NCR5380_MEM - /* set IRQ for HP C2502 */ - if (overrides[current_override].board == BOARD_HP_C2502) - magic_configure(port_idx, instance->irq, magic); + /* set IRQ for HP C2502 */ + if (card.board == BOARD_HP_C2502) + magic_configure(port_idx, instance->irq, magic); #endif - if (request_irq(instance->irq, generic_NCR5380_intr, - 0, "NCR5380", instance)) { - printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); - instance->irq = NO_IRQ; - } - } - - if (instance->irq == NO_IRQ) { - printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + if (request_irq(instance->irq, generic_NCR5380_intr, + 0, "NCR5380", instance)) { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = NO_IRQ; } + } - ++current_override; - ++count; + if (instance->irq == NO_IRQ) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); } - return count; + + return 1; out_unregister: scsi_unregister(instance); out_release: #ifndef SCSI_G_NCR5380_MEM - release_region(overrides[current_override].NCR5380_map_name, region_size); + release_region(card.NCR5380_map_name, region_size); #else iounmap(iomem); release_mem_region(base, iomem_size); #endif - return count; + return 0; } /** -- GitLab From a8cfbcaec0c1214ddebf1b7a39aa0df545fbbf90 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 27 Sep 2016 21:00:25 +0200 Subject: [PATCH 0146/1167] scsi: g_NCR5380: Stop using scsi_module.c Convert g_NCR5380 to use scsi_add_host instead of scsi_module.c Use pnp_driver and isa_driver to manage cards. In order to support multiple cards, new module parameter format is introduced. The old parameters are kept for compatibility. Signed-off-by: Ondrej Zary Acked-by: Finn Thain Signed-off-by: Martin K. Petersen --- Documentation/scsi/g_NCR5380.txt | 24 ++- drivers/scsi/g_NCR5380.c | 335 ++++++++++++++++++------------- drivers/scsi/g_NCR5380.h | 8 - 3 files changed, 215 insertions(+), 152 deletions(-) diff --git a/Documentation/scsi/g_NCR5380.txt b/Documentation/scsi/g_NCR5380.txt index 843cbae88ebbb..e2c187947e588 100644 --- a/Documentation/scsi/g_NCR5380.txt +++ b/Documentation/scsi/g_NCR5380.txt @@ -28,6 +28,16 @@ time. More info to come in the future. This driver works as a module. When included as a module, parameters can be passed on the insmod/modprobe command line: + irq=xx[,...] the interrupt(s) + base=xx[,...] the port or base address(es) (for port or memory mapped, resp.) + card=xx[,...] card type(s): + 0 = NCR5380, + 1 = NCR53C400, + 2 = NCR53C400A, + 3 = Domex Technology Corp 3181E (DTC3181E) + 4 = Hewlett Packard C2502 + +These old-style parameters can support only one card: ncr_irq=xx the interrupt ncr_addr=xx the port or base address (for port or memory mapped, resp.) @@ -36,11 +46,19 @@ command line: ncr_53c400a=1 to set up for a NCR53C400A board dtc_3181e=1 to set up for a Domex Technology Corp 3181E board hp_c2502=1 to set up for a Hewlett Packard C2502 board + e.g. -modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1 +OLD: modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1 +NEW: modprobe g_NCR5380 irq=5 base=0x350 card=0 for a port mapped NCR5380 board or -modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 - for a memory mapped NCR53C400 board with interrupts disabled. + +OLD: modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 +NEW: modprobe g_NCR5380 irq=255 base=0xc8000 card=1 + for a memory mapped NCR53C400 board with interrupts disabled or + +NEW: modprobe g_NCR5380 irq=0,7 base=0x240,0x300 card=3,4 + for two cards: DTC3181 (in non-PnP mode) at 0x240 with no IRQ + and HP C2502 at 0x300 with IRQ 7 (255 should be specified for no or DMA interrupt, 254 to autoprobe for an IRQ line if overridden on the command line.) diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 5162de61a92fc..cbf010324c187 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -30,24 +30,41 @@ #include "NCR5380.h" #include #include -#include +#include +#include #include +#define MAX_CARDS 8 + +/* old-style parameters for compatibility */ static int ncr_irq; -static int ncr_dma; static int ncr_addr; static int ncr_5380; static int ncr_53c400; static int ncr_53c400a; static int dtc_3181e; static int hp_c2502; +module_param(ncr_irq, int, 0); +module_param(ncr_addr, int, 0); +module_param(ncr_5380, int, 0); +module_param(ncr_53c400, int, 0); +module_param(ncr_53c400a, int, 0); +module_param(dtc_3181e, int, 0); +module_param(hp_c2502, int, 0); + +static int irq[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +module_param_array(irq, int, NULL, 0); +MODULE_PARM_DESC(irq, "IRQ number(s)"); -static struct card { - NCR5380_map_type NCR5380_map_name; - int irq; - int dma; - int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ -} card; +static int base[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +module_param_array(base, int, NULL, 0); +MODULE_PARM_DESC(base, "base address(es)"); + +static int card[] = { -1, -1, -1, -1, -1, -1, -1, -1 }; +module_param_array(card, int, NULL, 0); +MODULE_PARM_DESC(card, "card type (0=NCR5380, 1=NCR53C400, 2=NCR53C400A, 3=DTC3181E, 4=HP C2502)"); + +MODULE_LICENSE("GPL"); #ifndef SCSI_G_NCR5380_MEM /* @@ -73,17 +90,8 @@ static void magic_configure(int idx, u8 irq, u8 magic[]) } #endif -/** - * generic_NCR5380_detect - look for NCR5380 controllers - * @tpnt: the scsi template - * - * Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E - * and DTC436(ISAPnP) controllers. - * - * Locks: none - */ - -static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) +static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, + struct device *pdev, int base, int irq, int board) { unsigned int *ports; u8 *magic = NULL; @@ -92,80 +100,29 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) int port_idx = -1; unsigned long region_size; #endif - static unsigned int __initdata ncr_53c400a_ports[] = { + static unsigned int ncr_53c400a_ports[] = { 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 }; - static unsigned int __initdata dtc_3181e_ports[] = { + static unsigned int dtc_3181e_ports[] = { 0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0 }; - static u8 ncr_53c400a_magic[] __initdata = { /* 53C400A & DTC436 */ + static u8 ncr_53c400a_magic[] = { /* 53C400A & DTC436 */ 0x59, 0xb9, 0xc5, 0xae, 0xa6 }; - static u8 hp_c2502_magic[] __initdata = { /* HP C2502 */ + static u8 hp_c2502_magic[] = { /* HP C2502 */ 0x0f, 0x22, 0xf0, 0x20, 0x80 }; - int flags; + int flags, ret; struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; #ifdef SCSI_G_NCR5380_MEM - unsigned long base; void __iomem *iomem; resource_size_t iomem_size; #endif - if (ncr_irq) - card.irq = ncr_irq; - if (ncr_dma) - card.dma = ncr_dma; - if (ncr_addr) - card.NCR5380_map_name = (NCR5380_map_type) ncr_addr; - if (ncr_5380) - card.board = BOARD_NCR5380; - else if (ncr_53c400) - card.board = BOARD_NCR53C400; - else if (ncr_53c400a) - card.board = BOARD_NCR53C400A; - else if (dtc_3181e) - card.board = BOARD_DTC3181E; - else if (hp_c2502) - card.board = BOARD_HP_C2502; -#ifndef SCSI_G_NCR5380_MEM - if (isapnp_present()) { - struct pnp_dev *dev = NULL; - while ((dev = pnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) { - if (pnp_device_attach(dev) < 0) - continue; - if (pnp_activate_dev(dev) < 0) { - printk(KERN_ERR "dtc436e probe: activate failed\n"); - pnp_device_detach(dev); - continue; - } - if (!pnp_port_valid(dev, 0)) { - printk(KERN_ERR "dtc436e probe: no valid port\n"); - pnp_device_detach(dev); - continue; - } - if (pnp_irq_valid(dev, 0)) - card.irq = pnp_irq(dev, 0); - else - card.irq = NO_IRQ; - if (pnp_dma_valid(dev, 0)) - card.dma = pnp_dma(dev, 0); - else - card.dma = DMA_NONE; - card.NCR5380_map_name = (NCR5380_map_type) pnp_port_start(dev, 0); - card.board = BOARD_DTC3181E; - break; - } - } -#endif - - if (!(card.NCR5380_map_name)) - return 0; - ports = NULL; flags = 0; - switch (card.board) { + switch (board) { case BOARD_NCR5380: flags = FLAG_NO_PSEUDO_DMA | FLAG_DMA_FIXUP; break; @@ -191,17 +148,20 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) magic_configure(-1, 0, magic); region_size = 16; - - if (card.NCR5380_map_name != PORT_AUTO) + if (base) for (i = 0; ports[i]; i++) { - if (!request_region(ports[i], region_size, "ncr53c80")) - continue; - if (card.NCR5380_map_name == ports[i]) + if (base == ports[i]) { /* index found */ + if (!request_region(ports[i], + region_size, + "ncr53c80")) + return -EBUSY; break; - release_region(ports[i], region_size); - } else + } + } + else for (i = 0; ports[i]; i++) { - if (!request_region(ports[i], region_size, "ncr53c80")) + if (!request_region(ports[i], region_size, + "ncr53c80")) continue; if (inb(ports[i]) == 0xff) break; @@ -211,39 +171,41 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) /* At this point we have our region reserved */ magic_configure(i, 0, magic); /* no IRQ yet */ outb(0xc0, ports[i] + 9); - if (inb(ports[i] + 9) != 0x80) - return 0; - card.NCR5380_map_name = ports[i]; + if (inb(ports[i] + 9) != 0x80) { + ret = -ENODEV; + goto out_release; + } + base = ports[i]; port_idx = i; } else - return 0; + return -EINVAL; } else { - /* Not a 53C400A style setup - just grab */ + /* NCR5380 - no configuration, just grab */ region_size = 8; - if (!request_region(card.NCR5380_map_name, - region_size, "ncr5380")) - return 0; + if (!base || !request_region(base, region_size, "ncr5380")) + return -EBUSY; } #else - base = card.NCR5380_map_name; iomem_size = NCR53C400_region_size; if (!request_mem_region(base, iomem_size, "ncr5380")) - return 0; + return -EBUSY; iomem = ioremap(base, iomem_size); if (!iomem) { release_mem_region(base, iomem_size); - return 0; + return -ENOMEM; } #endif - instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); - if (instance == NULL) + instance = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) { + ret = -ENOMEM; goto out_release; + } hostdata = shost_priv(instance); #ifndef SCSI_G_NCR5380_MEM - instance->io_port = card.NCR5380_map_name; + instance->io_port = base; instance->n_io_port = region_size; hostdata->io_width = 1; /* 8-bit PDMA by default */ @@ -251,7 +213,7 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) * On NCR53C400 boards, NCR5380 registers are mapped 8 past * the base address. */ - switch (card.board) { + switch (board) { case BOARD_NCR53C400: instance->io_port += 8; hostdata->c400_ctl_status = 0; @@ -269,10 +231,10 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) break; } #else - instance->base = card.NCR5380_map_name; + instance->base = base; hostdata->iomem = iomem; hostdata->iomem_size = iomem_size; - switch (card.board) { + switch (board) { case BOARD_NCR53C400: hostdata->c400_ctl_status = 0x100; hostdata->c400_blk_cnt = 0x101; @@ -282,14 +244,16 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) case BOARD_NCR53C400A: case BOARD_HP_C2502: pr_err(DRV_MODULE_NAME ": unknown register offsets\n"); + ret = -EINVAL; goto out_unregister; } #endif - if (NCR5380_init(instance, flags | FLAG_LATE_DMA_SETUP)) + ret = NCR5380_init(instance, flags | FLAG_LATE_DMA_SETUP); + if (ret) goto out_unregister; - switch (card.board) { + switch (board) { case BOARD_NCR53C400: case BOARD_DTC3181E: case BOARD_NCR53C400A: @@ -299,8 +263,8 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) NCR5380_maybe_reset_bus(instance); - if (card.irq != IRQ_AUTO) - instance->irq = card.irq; + if (irq != IRQ_AUTO) + instance->irq = irq; else instance->irq = NCR5380_probe_irq(instance, 0xffff); @@ -311,7 +275,7 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) if (instance->irq != NO_IRQ) { #ifndef SCSI_G_NCR5380_MEM /* set IRQ for HP C2502 */ - if (card.board == BOARD_HP_C2502) + if (board == BOARD_HP_C2502) magic_configure(port_idx, instance->irq, magic); #endif if (request_irq(instance->irq, generic_NCR5380_intr, @@ -326,31 +290,32 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); } - return 1; + ret = scsi_add_host(instance, pdev); + if (ret) + goto out_free_irq; + scsi_scan_host(instance); + dev_set_drvdata(pdev, instance); + return 0; +out_free_irq: + if (instance->irq != NO_IRQ) + free_irq(instance->irq, instance); + NCR5380_exit(instance); out_unregister: - scsi_unregister(instance); + scsi_host_put(instance); out_release: #ifndef SCSI_G_NCR5380_MEM - release_region(card.NCR5380_map_name, region_size); + release_region(base, region_size); #else iounmap(iomem); release_mem_region(base, iomem_size); #endif - return 0; + return ret; } -/** - * generic_NCR5380_release_resources - free resources - * @instance: host adapter to clean up - * - * Free the generic interface resources from this adapter. - * - * Locks: none - */ - -static int generic_NCR5380_release_resources(struct Scsi_Host *instance) +static void generic_NCR5380_release_resources(struct Scsi_Host *instance) { + scsi_remove_host(instance); if (instance->irq != NO_IRQ) free_irq(instance->irq, instance); NCR5380_exit(instance); @@ -364,7 +329,7 @@ static int generic_NCR5380_release_resources(struct Scsi_Host *instance) release_mem_region(instance->base, hostdata->iomem_size); } #endif - return 0; + scsi_host_put(instance); } /** @@ -554,10 +519,9 @@ static int generic_NCR5380_dma_xfer_len(struct Scsi_Host *instance, #include "NCR5380.c" static struct scsi_host_template driver_template = { + .module = THIS_MODULE, .proc_name = DRV_MODULE_NAME, .name = "Generic NCR5380/NCR53C400 SCSI", - .detect = generic_NCR5380_detect, - .release = generic_NCR5380_release_resources, .info = generic_NCR5380_info, .queuecommand = generic_NCR5380_queue_command, .eh_abort_handler = generic_NCR5380_abort, @@ -571,26 +535,115 @@ static struct scsi_host_template driver_template = { .max_sectors = 128, }; -#include "scsi_module.c" -module_param(ncr_irq, int, 0); -module_param(ncr_dma, int, 0); -module_param(ncr_addr, int, 0); -module_param(ncr_5380, int, 0); -module_param(ncr_53c400, int, 0); -module_param(ncr_53c400a, int, 0); -module_param(dtc_3181e, int, 0); -module_param(hp_c2502, int, 0); -MODULE_LICENSE("GPL"); +static int generic_NCR5380_isa_match(struct device *pdev, unsigned int ndev) +{ + int ret = generic_NCR5380_init_one(&driver_template, pdev, base[ndev], + irq[ndev], card[ndev]); + if (ret) { + if (base[ndev]) + printk(KERN_WARNING "Card not found at address 0x%03x\n", + base[ndev]); + return 0; + } -#if !defined(SCSI_G_NCR5380_MEM) && defined(MODULE) -static struct isapnp_device_id id_table[] = { - { - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), - 0}, - {0} + return 1; +} + +static int generic_NCR5380_isa_remove(struct device *pdev, + unsigned int ndev) +{ + generic_NCR5380_release_resources(dev_get_drvdata(pdev)); + dev_set_drvdata(pdev, NULL); + return 0; +} + +static struct isa_driver generic_NCR5380_isa_driver = { + .match = generic_NCR5380_isa_match, + .remove = generic_NCR5380_isa_remove, + .driver = { + .name = DRV_MODULE_NAME + }, +}; + +#if !defined(SCSI_G_NCR5380_MEM) && defined(CONFIG_PNP) +static struct pnp_device_id generic_NCR5380_pnp_ids[] = { + { .id = "DTC436e", .driver_data = BOARD_DTC3181E }, + { .id = "" } +}; +MODULE_DEVICE_TABLE(pnp, generic_NCR5380_pnp_ids); + +static int generic_NCR5380_pnp_probe(struct pnp_dev *pdev, + const struct pnp_device_id *id) +{ + int base, irq; + + if (pnp_activate_dev(pdev) < 0) + return -EBUSY; + + base = pnp_port_start(pdev, 0); + irq = pnp_irq(pdev, 0); + + return generic_NCR5380_init_one(&driver_template, &pdev->dev, base, irq, + id->driver_data); +} + +static void generic_NCR5380_pnp_remove(struct pnp_dev *pdev) +{ + generic_NCR5380_release_resources(pnp_get_drvdata(pdev)); + pnp_set_drvdata(pdev, NULL); +} + +static struct pnp_driver generic_NCR5380_pnp_driver = { + .name = DRV_MODULE_NAME, + .id_table = generic_NCR5380_pnp_ids, + .probe = generic_NCR5380_pnp_probe, + .remove = generic_NCR5380_pnp_remove, }; +#endif /* !defined(SCSI_G_NCR5380_MEM) && defined(CONFIG_PNP) */ -MODULE_DEVICE_TABLE(isapnp, id_table); +static int pnp_registered, isa_registered; + +static int __init generic_NCR5380_init(void) +{ + int ret = 0; + + /* compatibility with old-style parameters */ + if (irq[0] == 0 && base[0] == 0 && card[0] == -1) { + irq[0] = ncr_irq; + base[0] = ncr_addr; + if (ncr_5380) + card[0] = BOARD_NCR5380; + if (ncr_53c400) + card[0] = BOARD_NCR53C400; + if (ncr_53c400a) + card[0] = BOARD_NCR53C400A; + if (dtc_3181e) + card[0] = BOARD_DTC3181E; + if (hp_c2502) + card[0] = BOARD_HP_C2502; + } + +#if !defined(SCSI_G_NCR5380_MEM) && defined(CONFIG_PNP) + if (!pnp_register_driver(&generic_NCR5380_pnp_driver)) + pnp_registered = 1; #endif + ret = isa_register_driver(&generic_NCR5380_isa_driver, MAX_CARDS); + if (!ret) + isa_registered = 1; + + return (pnp_registered || isa_registered) ? 0 : ret; +} + +static void __exit generic_NCR5380_exit(void) +{ +#if !defined(SCSI_G_NCR5380_MEM) && defined(CONFIG_PNP) + if (pnp_registered) + pnp_unregister_driver(&generic_NCR5380_pnp_driver); +#endif + if (isa_registered) + isa_unregister_driver(&generic_NCR5380_isa_driver); +} + +module_init(generic_NCR5380_init); +module_exit(generic_NCR5380_exit); diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h index 595177428d762..b175b92344586 100644 --- a/drivers/scsi/g_NCR5380.h +++ b/drivers/scsi/g_NCR5380.h @@ -14,15 +14,9 @@ #ifndef GENERIC_NCR5380_H #define GENERIC_NCR5380_H -#define __STRVAL(x) #x -#define STRVAL(x) __STRVAL(x) - #ifndef SCSI_G_NCR5380_MEM #define DRV_MODULE_NAME "g_NCR5380" -#define NCR5380_map_type int -#define NCR5380_map_name port - #define NCR5380_read(reg) \ inb(instance->io_port + (reg)) #define NCR5380_write(reg, value) \ @@ -38,8 +32,6 @@ /* therefore SCSI_G_NCR5380_MEM */ #define DRV_MODULE_NAME "g_NCR5380_mmio" -#define NCR5380_map_type unsigned long -#define NCR5380_map_name base #define NCR53C400_mem_base 0x3880 #define NCR53C400_host_buffer 0x3900 #define NCR53C400_region_size 0x3a00 -- GitLab From 5404fb7cec7473413bc1dd2d114dbe7c291dfb15 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Fri, 23 Sep 2016 12:52:52 +0100 Subject: [PATCH 0147/1167] scsi: ufs: Kconfig fix Currently if we have PCI and UFSHCD configured in the kernel, both SCSI_UFS_DWC_TC_PCI and SCSI_UFSHCD_PCI show up, which is not correct. This patch changes the UFS Kconfig to assure hierarchy between the 2 options. Signed-off-by: Joao Pinto Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 47966909286dc..e27b4d4e6ae2d 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -63,7 +63,7 @@ config SCSI_UFSHCD_PCI config SCSI_UFS_DWC_TC_PCI tristate "DesignWare pci support using a G210 Test Chip" - depends on SCSI_UFSHCD && PCI + depends on SCSI_UFSHCD_PCI ---help--- Synopsys Test Chip is a PHY for prototyping purposes. -- GitLab From 1ce788d24268a33513d832d9030ceab93f1c2ce2 Mon Sep 17 00:00:00 2001 From: Tang Yuantian Date: Fri, 30 Sep 2016 14:13:13 +0800 Subject: [PATCH 0148/1167] ahci: qoriq: Revert "ahci: qoriq: Disable NCQ on ls2080a SoC" This reverts commit 640847298e2b7f19 ("ahci: qoriq: Disable NCQ on ls2080a SoC") The erratum has been fixed in ls2080a v2.0 and later soc. In reality, customer will not get any ls2080a v1.0 soc. Neither apply to any products. So reverting this commit won't create any side effect. Blacklisting v2.0 could also be a option, but that needs to check the soc version which is not suitable in the driver. Signed-off-by: Tang Yuantian Signed-off-by: Tejun Heo --- drivers/ata/ahci_qoriq.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index 925c4b6a753bb..1eba8dff875eb 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -136,7 +136,7 @@ static struct ata_port_operations ahci_qoriq_ops = { .hardreset = ahci_qoriq_hardreset, }; -static struct ata_port_info ahci_qoriq_port_info = { +static const struct ata_port_info ahci_qoriq_port_info = { .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, @@ -221,12 +221,6 @@ static int ahci_qoriq_probe(struct platform_device *pdev) if (rc) goto disable_resources; - /* Workaround for ls2080a */ - if (qoriq_priv->type == AHCI_LS2080A) { - hpriv->flags |= AHCI_HFLAG_NO_NCQ; - ahci_qoriq_port_info.flags &= ~ATA_FLAG_NCQ; - } - rc = ahci_platform_init_host(pdev, hpriv, &ahci_qoriq_port_info, &ahci_qoriq_sht); if (rc) -- GitLab From bbb427e342495df1cda10051d0566388697499c0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 29 Sep 2016 08:33:30 -0700 Subject: [PATCH 0149/1167] blkcg: Unlock blkcg_pol_mutex only once when cpd == NULL Unlocking a mutex twice is wrong. Hence modify blkcg_policy_register() such that blkcg_pol_mutex is unlocked once if cpd == NULL. This patch avoids that smatch reports the following error: block/blk-cgroup.c:1378: blkcg_policy_register() error: double unlock 'mutex:&blkcg_pol_mutex' Fixes: 06b285bd1125 ("blkcg: fix blkcg_policy_data allocation bug") Signed-off-by: Bart Van Assche Cc: Tejun Heo Cc: # v4.2+ Signed-off-by: Tejun Heo --- block/blk-cgroup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index dd38e5ced4a3f..b08ccbb9393a7 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -1340,10 +1340,8 @@ int blkcg_policy_register(struct blkcg_policy *pol) struct blkcg_policy_data *cpd; cpd = pol->cpd_alloc_fn(GFP_KERNEL); - if (!cpd) { - mutex_unlock(&blkcg_pol_mutex); + if (!cpd) goto err_free_cpds; - } blkcg->cpd[pol->plid] = cpd; cpd->blkcg = blkcg; -- GitLab From d94655b405ba08838fb3db301dddb02a435ae16c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 24 Sep 2016 12:02:54 +0000 Subject: [PATCH 0150/1167] ipmi/bt-bmc: remove redundant return value check of platform_get_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unneeded error handling on the result of a call to platform_get_resource() when the value is passed to devm_ioremap_resource(). Signed-off-by: Wei Yongjun Acked-by: Cédric Le Goater Signed-off-by: Corey Minyard --- drivers/char/ipmi/bt-bmc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c index de64bf1f2f4d4..b49e613209529 100644 --- a/drivers/char/ipmi/bt-bmc.c +++ b/drivers/char/ipmi/bt-bmc.c @@ -432,11 +432,6 @@ static int bt_bmc_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, bt_bmc); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "Unable to find resources\n"); - return -ENXIO; - } - bt_bmc->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(bt_bmc->base)) return PTR_ERR(bt_bmc->base); -- GitLab From 231147ee77f39f4134935686e9d7e415bdf48149 Mon Sep 17 00:00:00 2001 From: sayli karnik Date: Wed, 28 Sep 2016 21:46:51 +0530 Subject: [PATCH 0151/1167] iio: maxim_thermocouple: Align 16 bit big endian value of raw reads Driver was reporting invalid raw read values for MAX6675 on big endian architectures. MAX6675 buffered mode is not affected, nor is the MAX31855. The driver was losing a 2 byte read value when it used a 32 bit integer buffer to store a 16 bit big endian value. Use big endian types to properly align buffers on big endian architectures. Fixes following sparse endianness warnings: warning: cast to restricted __be16 warning: cast to restricted __be32 Fixes checkpatch issue: CHECK: No space is necessary after a cast Signed-off-by: sayli karnik Fixes: 1f25ca11d84a ("iio: temperature: add support for Maxim thermocouple chips") Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/maxim_thermocouple.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index 39dd2026ccc92..066161a4bccd9 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -123,22 +123,24 @@ static int maxim_thermocouple_read(struct maxim_thermocouple_data *data, { unsigned int storage_bytes = data->chip->read_size; unsigned int shift = chan->scan_type.shift + (chan->address * 8); - unsigned int buf; + __be16 buf16; + __be32 buf32; int ret; - ret = spi_read(data->spi, (void *) &buf, storage_bytes); - if (ret) - return ret; - switch (storage_bytes) { case 2: - *val = be16_to_cpu(buf); + ret = spi_read(data->spi, (void *)&buf16, storage_bytes); + *val = be16_to_cpu(buf16); break; case 4: - *val = be32_to_cpu(buf); + ret = spi_read(data->spi, (void *)&buf32, storage_bytes); + *val = be32_to_cpu(buf32); break; } + if (ret) + return ret; + /* check to be sure this is a valid reading */ if (*val & data->chip->status_bit) return -EINVAL; -- GitLab From 43d96390d57aa0e61d15ce2bcb887df8516d58f5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 21 Sep 2016 17:48:39 +0200 Subject: [PATCH 0152/1167] Coccinelle: limit memdup_user transformation to GFP_KERNEL case Memdup_user encapsulates a memory allocation with the flag GFP_KERNEL, so only allow this flag in the original code. Signed-off-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/api/memdup_user.cocci | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/coccinelle/api/memdup_user.cocci b/scripts/coccinelle/api/memdup_user.cocci index c606231b0e469..2a5aea8e8487c 100644 --- a/scripts/coccinelle/api/memdup_user.cocci +++ b/scripts/coccinelle/api/memdup_user.cocci @@ -15,11 +15,11 @@ virtual org virtual report @depends on patch@ -expression from,to,size,flag; +expression from,to,size; identifier l1,l2; @@ -- to = \(kmalloc\|kzalloc\)(size,flag); +- to = \(kmalloc\|kzalloc\)(size,GFP_KERNEL); + to = memdup_user(from,size); if ( - to==NULL @@ -37,12 +37,12 @@ identifier l1,l2; - } @r depends on !patch@ -expression from,to,size,flag; +expression from,to,size; position p; statement S1,S2; @@ -* to = \(kmalloc@p\|kzalloc@p\)(size,flag); +* to = \(kmalloc@p\|kzalloc@p\)(size,GFP_KERNEL); if (to==NULL || ...) S1 if (copy_from_user(to, from, size) != 0) S2 -- GitLab From d97629f1686574a800a76eb0d2ce65e3f3d3ef92 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 22 Sep 2016 10:28:55 +0200 Subject: [PATCH 0153/1167] Coccinelle: pm_runtime: ensure relevance of pm_runtime reports pm_runtime.cocci starts with one rule that searches for a variety of functions calls, followed by various rules that report errors. Previously, the only connection between the first rule and the rest was to check that the first rule had matched somewhere. Change the rules to propagate a position from the first rule to the others, to make sure that the sites reported on are the same as the sites that were identified as having the relevant functions. Signed-off-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/api/pm_runtime.cocci | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/scripts/coccinelle/api/pm_runtime.cocci b/scripts/coccinelle/api/pm_runtime.cocci index 89b98a2f7a6f4..d67ccf5f82279 100644 --- a/scripts/coccinelle/api/pm_runtime.cocci +++ b/scripts/coccinelle/api/pm_runtime.cocci @@ -17,9 +17,10 @@ virtual report @runtime_bad_err_handle exists@ expression ret; +position p; @@ ( -ret = \(pm_runtime_idle\| +ret@p = \(pm_runtime_idle\| pm_runtime_suspend\| pm_runtime_autosuspend\| pm_runtime_resume\| @@ -47,12 +48,13 @@ IS_ERR_VALUE(ret) // For context mode //---------------------------------------------------------- -@depends on runtime_bad_err_handle && context@ +@depends on context@ identifier pm_runtime_api; expression ret; +position runtime_bad_err_handle.p; @@ ( -ret = pm_runtime_api(...); +ret@p = pm_runtime_api(...); ... * IS_ERR_VALUE(ret) ... @@ -62,12 +64,13 @@ ret = pm_runtime_api(...); // For patch mode //---------------------------------------------------------- -@depends on runtime_bad_err_handle && patch@ +@depends on patch@ identifier pm_runtime_api; expression ret; +position runtime_bad_err_handle.p; @@ ( -ret = pm_runtime_api(...); +ret@p = pm_runtime_api(...); ... - IS_ERR_VALUE(ret) + ret < 0 @@ -78,13 +81,14 @@ ret = pm_runtime_api(...); // For org and report mode //---------------------------------------------------------- -@r depends on runtime_bad_err_handle && (org || report) exists@ +@r depends on (org || report) exists@ position p1, p2; identifier pm_runtime_api; expression ret; +position runtime_bad_err_handle.p; @@ ( -ret = pm_runtime_api@p1(...); +ret@p = pm_runtime_api@p1(...); ... IS_ERR_VALUE@p2(ret) ... -- GitLab From bd85f4b37ddf2da22ccf5b29d264b2459b6722df Mon Sep 17 00:00:00 2001 From: Xie XiuQi Date: Tue, 27 Sep 2016 15:07:12 +0800 Subject: [PATCH 0154/1167] ipmi: fix crash on reading version from proc after unregisted bmc I meet a crash, which could be reproduce: 1) while true; do cat /proc/ipmi/0/version; done 2) modprobe -rv ipmi_si ipmi_msghandler ipmi_devintf [82761.021137] IPMI BT: req2rsp=5 secs retries=2 [82761.034524] ipmi device interface [82761.222218] ipmi_si ipmi_si.0: Found new BMC (man_id: 0x0007db, prod_id: 0x0001, dev_id: 0x01) [82761.222230] ipmi_si ipmi_si.0: IPMI bt interface initialized [82903.922740] BUG: unable to handle kernel NULL pointer dereference at 00000000000002d4 [82903.930952] IP: [] smi_version_proc_show+0x18/0x40 [ipmi_msghandler] [82903.939220] PGD 86693a067 PUD 865304067 PMD 0 [82903.943893] Thread overran stack, or stack corrupted [82903.949034] Oops: 0000 [#1] SMP [82903.983091] Modules linked in: ipmi_si(-) ipmi_msghandler binfmt_misc ebtable_filter ebtables ip6table_filter ip6_tables iptable_filter ... [82904.057285] pps_core scsi_transport_sas dm_mod vfio_iommu_type1 vfio xt_sctp nf_conntrack_proto_sctp nf_nat_proto_sctp nf_nat nf_conntrack sctp libcrc32c [last unloaded: ipmi_devintf] [82904.073169] CPU: 37 PID: 28089 Comm: cat Tainted: GF O ---- ------- 3.10.0-327.28.3.el7.x86_64 #1 [82904.083373] Hardware name: Huawei RH2288H V3/BC11HGSA0, BIOS 3.22 05/16/2016 [82904.090592] task: ffff880101cc2e00 ti: ffff880369c54000 task.ti: ffff880369c54000 [82904.098414] RIP: 0010:[] [] smi_version_proc_show+0x18/0x40 [ipmi_msghandler] [82904.109124] RSP: 0018:ffff880369c57e70 EFLAGS: 00010203 [82904.114608] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000024688470 [82904.121912] RDX: fffffffffffffff4 RSI: ffffffffa0313404 RDI: ffff8808670ce200 [82904.129218] RBP: ffff880369c57e70 R08: 0000000000019720 R09: ffffffff81204a27 [82904.136521] R10: ffff88046f803300 R11: 0000000000000246 R12: ffff880662399700 [82904.143828] R13: 0000000000000001 R14: ffff880369c57f48 R15: ffff8808670ce200 [82904.151128] FS: 00007fb70c9ca740(0000) GS:ffff88086e340000(0000) knlGS:0000000000000000 [82904.159557] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [82904.165473] CR2: 00000000000002d4 CR3: 0000000864c0c000 CR4: 00000000003407e0 [82904.172778] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [82904.180084] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [82904.187385] Stack: [82904.189573] ffff880369c57ee0 ffffffff81204f1a 00000000122a2427 0000000001426000 [82904.197392] ffff8808670ce238 0000000000010000 0000000000000000 0000000000000fff [82904.205198] 00000000122a2427 ffff880862079600 0000000001426000 ffff880369c57f48 [82904.212962] Call Trace: [82904.219667] [] seq_read+0xfa/0x3a0 [82904.224893] [] proc_reg_read+0x3d/0x80 [82904.230468] [] vfs_read+0x9c/0x170 [82904.235689] [] SyS_read+0x7f/0xe0 [82904.240816] [] system_call_fastpath+0x16/0x1b [82904.246991] Code: 30 a0 e8 0c 6f ef e0 5b 5d c3 66 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 8b 47 78 55 48 c7 c6 04 34 31 a0 48 89 e5 48 8b 40 50 <0f> b6 90 d4 02 00 00 31 c0 89 d1 83 e2 0f c0 e9 04 0f b6 c9 e8 [82904.267710] RIP [] smi_version_proc_show+0x18/0x40 [ipmi_msghandler] [82904.276079] RSP [82904.279734] CR2: 00000000000002d4 [82904.283731] ---[ end trace a69e4328b49dd7c4 ]--- [82904.328118] Kernel panic - not syncing: Fatal exception Reading versin from /proc need bmc device struct available. So in this patch we move add/remove_proc_entries between ipmi_bmc_register and ipmi_bmc_unregister. Cc: Kefeng Wang Signed-off-by: Xie XiuQi Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index d8619998cfb57..fcdd886819f5c 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2891,11 +2891,11 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, intf->curr_channel = IPMI_MAX_CHANNELS; } + rv = ipmi_bmc_register(intf, i); + if (rv == 0) rv = add_proc_entries(intf, i); - rv = ipmi_bmc_register(intf, i); - out: if (rv) { if (intf->proc_dir) @@ -2982,8 +2982,6 @@ int ipmi_unregister_smi(ipmi_smi_t intf) int intf_num = intf->intf_num; ipmi_user_t user; - ipmi_bmc_unregister(intf); - mutex_lock(&smi_watchers_mutex); mutex_lock(&ipmi_interfaces_mutex); intf->intf_num = -1; @@ -3007,6 +3005,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf) mutex_unlock(&ipmi_interfaces_mutex); remove_proc_entries(intf); + ipmi_bmc_unregister(intf); /* * Call all the watcher interfaces to tell them that -- GitLab From 0e97cd4e4632e385b3bf7edcf0c803de0487212a Mon Sep 17 00:00:00 2001 From: lipeng Date: Thu, 29 Sep 2016 18:09:09 +0100 Subject: [PATCH 0155/1167] net: hns: fix port unavailable after hnae_reserve_buffer_map fail When hnae_reserve_buffer_map fail, it will break cycle and some buffer description has no available memory, therefore the port will be unavailable. Signed-off-by: Peng Li Reviewed-by: Yisen Zhuang Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index d7e1f8c7ae924..32ff270286875 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -747,6 +747,14 @@ static void hns_nic_rx_up_pro(struct hns_nic_ring_data *ring_data, ndev->last_rx = jiffies; } +static int hns_desc_unused(struct hnae_ring *ring) +{ + int ntc = ring->next_to_clean; + int ntu = ring->next_to_use; + + return ((ntc >= ntu) ? 0 : ring->desc_num) + ntc - ntu; +} + static int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data, int budget, void *v) { @@ -755,17 +763,21 @@ static int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data, int num, bnum, ex_num; #define RCB_NOF_ALLOC_RX_BUFF_ONCE 16 int recv_pkts, recv_bds, clean_count, err; + int unused_count = hns_desc_unused(ring); num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM); rmb(); /* make sure num taken effect before the other data is touched */ recv_pkts = 0, recv_bds = 0, clean_count = 0; + num -= unused_count; recv: while (recv_pkts < budget && recv_bds < num) { /* reuse or realloc buffers */ - if (clean_count >= RCB_NOF_ALLOC_RX_BUFF_ONCE) { - hns_nic_alloc_rx_buffers(ring_data, clean_count); + if (clean_count + unused_count >= RCB_NOF_ALLOC_RX_BUFF_ONCE) { + hns_nic_alloc_rx_buffers(ring_data, + clean_count + unused_count); clean_count = 0; + unused_count = hns_desc_unused(ring); } /* poll one pkt */ @@ -789,7 +801,7 @@ static int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data, /* make all data has been write before submit */ if (recv_pkts < budget) { ex_num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM); - + ex_num -= unused_count; if (ex_num > clean_count) { num += ex_num - clean_count; rmb(); /*complete read rx ring bd number*/ @@ -799,8 +811,9 @@ static int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data, out: /* make all data has been write before submit */ - if (clean_count > 0) - hns_nic_alloc_rx_buffers(ring_data, clean_count); + if (clean_count + unused_count > 0) + hns_nic_alloc_rx_buffers(ring_data, + clean_count + unused_count); return recv_pkts; } -- GitLab From 6771cbf9446121cb7b64810395391712a03b899d Mon Sep 17 00:00:00 2001 From: Daode Huang Date: Thu, 29 Sep 2016 18:09:10 +0100 Subject: [PATCH 0156/1167] net: hns: bug fix about setting coalsecs-usecs to 0 When set rx/tx coalesce usecs to 0, the interrupt coalesce will be disabled, but there is a interrupt rate limit which set to 1us, it will cause no interrupt occurs. This patch disable interrupt limit when sets coalsecs usecs to 0, and restores it to 1 in other case. Signed-off-by: Daode Huang Reviewed-by: Yisen Zhuang Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- .../net/ethernet/hisilicon/hns/hns_dsaf_rcb.c | 16 ++++++++++++++++ .../net/ethernet/hisilicon/hns/hns_dsaf_reg.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c index ef1107777c08d..f0ed80d6ef9cd 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c @@ -543,6 +543,22 @@ int hns_rcb_set_coalesce_usecs( "error: coalesce_usecs setting supports 0~1023us\n"); return -EINVAL; } + + if (!AE_IS_VER1(rcb_common->dsaf_dev->dsaf_ver)) { + if (timeout == 0) + /* set timeout to 0, Disable gap time */ + dsaf_set_reg_field(rcb_common->io_base, + RCB_INT_GAP_TIME_REG + port_idx * 4, + PPE_INT_GAPTIME_M, PPE_INT_GAPTIME_B, + 0); + else + /* set timeout non 0, restore gap time to 1 */ + dsaf_set_reg_field(rcb_common->io_base, + RCB_INT_GAP_TIME_REG + port_idx * 4, + PPE_INT_GAPTIME_M, PPE_INT_GAPTIME_B, + 1); + } + hns_rcb_set_port_timeout(rcb_common, port_idx, timeout); return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h index 4b8b803822d1b..878950a42e6c2 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h @@ -417,6 +417,7 @@ #define RCB_CFG_OVERTIME_REG 0x9300 #define RCB_CFG_PKTLINE_INT_NUM_REG 0x9304 #define RCB_CFG_OVERTIME_INT_NUM_REG 0x9308 +#define RCB_INT_GAP_TIME_REG 0x9400 #define RCB_PORT_CFG_OVERTIME_REG 0x9430 #define RCB_RING_RX_RING_BASEADDR_L_REG 0x00000 @@ -898,6 +899,9 @@ #define PPE_CNT_CLR_CE_B 0 #define PPE_CNT_CLR_SNAP_EN_B 1 +#define PPE_INT_GAPTIME_B 0 +#define PPE_INT_GAPTIME_M 0x3ff + #define PPE_COMMON_CNT_CLR_CE_B 0 #define PPE_COMMON_CNT_CLR_SNAP_EN_B 1 #define RCB_COM_TSO_MODE_B 0 -- GitLab From cee5add45853ed9e6bbb6ad203602be6c42d3e16 Mon Sep 17 00:00:00 2001 From: Daode Huang Date: Thu, 29 Sep 2016 18:09:11 +0100 Subject: [PATCH 0157/1167] net: hns: add fini_process for v2 napi process This patch adds fini_process for v2, it handles the packets recevied by the hardware in the napi porcess. With this patch, the hardware irq numbers will drop 50% per sec. Signed-off-by: Daode Huang Reviewed-by: Yisen Zhuang Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 32ff270286875..e6bfc51f80225 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -823,6 +823,8 @@ static void hns_nic_rx_fini_pro(struct hns_nic_ring_data *ring_data) struct hnae_ring *ring = ring_data->ring; int num = 0; + ring_data->ring->q->handle->dev->ops->toggle_ring_irq(ring, 0); + /* for hardware bug fixed */ num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM); @@ -834,6 +836,20 @@ static void hns_nic_rx_fini_pro(struct hns_nic_ring_data *ring_data) } } +static void hns_nic_rx_fini_pro_v2(struct hns_nic_ring_data *ring_data) +{ + struct hnae_ring *ring = ring_data->ring; + int num = 0; + + num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM); + + if (num == 0) + ring_data->ring->q->handle->dev->ops->toggle_ring_irq( + ring, 0); + else + napi_schedule(&ring_data->napi); +} + static inline void hns_nic_reclaim_one_desc(struct hnae_ring *ring, int *bytes, int *pkts) { @@ -935,7 +951,11 @@ static int hns_nic_tx_poll_one(struct hns_nic_ring_data *ring_data, static void hns_nic_tx_fini_pro(struct hns_nic_ring_data *ring_data) { struct hnae_ring *ring = ring_data->ring; - int head = readl_relaxed(ring->io_base + RCB_REG_HEAD); + int head; + + ring_data->ring->q->handle->dev->ops->toggle_ring_irq(ring, 0); + + head = readl_relaxed(ring->io_base + RCB_REG_HEAD); if (head != ring->next_to_clean) { ring_data->ring->q->handle->dev->ops->toggle_ring_irq( @@ -945,6 +965,18 @@ static void hns_nic_tx_fini_pro(struct hns_nic_ring_data *ring_data) } } +static void hns_nic_tx_fini_pro_v2(struct hns_nic_ring_data *ring_data) +{ + struct hnae_ring *ring = ring_data->ring; + int head = readl_relaxed(ring->io_base + RCB_REG_HEAD); + + if (head == ring->next_to_clean) + ring_data->ring->q->handle->dev->ops->toggle_ring_irq( + ring, 0); + else + napi_schedule(&ring_data->napi); +} + static void hns_nic_tx_clr_all_bufs(struct hns_nic_ring_data *ring_data) { struct hnae_ring *ring = ring_data->ring; @@ -976,10 +1008,7 @@ static int hns_nic_common_poll(struct napi_struct *napi, int budget) if (clean_complete >= 0 && clean_complete < budget) { napi_complete(napi); - ring_data->ring->q->handle->dev->ops->toggle_ring_irq( - ring_data->ring, 0); - if (ring_data->fini_process) - ring_data->fini_process(ring_data); + ring_data->fini_process(ring_data); return 0; } @@ -1755,7 +1784,8 @@ static int hns_nic_init_ring_data(struct hns_nic_priv *priv) rd->queue_index = i; rd->ring = &h->qs[i]->tx_ring; rd->poll_one = hns_nic_tx_poll_one; - rd->fini_process = is_ver1 ? hns_nic_tx_fini_pro : NULL; + rd->fini_process = is_ver1 ? hns_nic_tx_fini_pro : + hns_nic_tx_fini_pro_v2; netif_napi_add(priv->netdev, &rd->napi, hns_nic_common_poll, NIC_TX_CLEAN_MAX_NUM); @@ -1767,7 +1797,8 @@ static int hns_nic_init_ring_data(struct hns_nic_priv *priv) rd->ring = &h->qs[i - h->q_num]->rx_ring; rd->poll_one = hns_nic_rx_poll_one; rd->ex_process = hns_nic_rx_up_pro; - rd->fini_process = is_ver1 ? hns_nic_rx_fini_pro : NULL; + rd->fini_process = is_ver1 ? hns_nic_rx_fini_pro : + hns_nic_rx_fini_pro_v2; netif_napi_add(priv->netdev, &rd->napi, hns_nic_common_poll, NIC_RX_CLEAN_MAX_NUM); -- GitLab From 34447271dc10302a9aaee273a3ed354aefeaef7c Mon Sep 17 00:00:00 2001 From: Daode Huang Date: Thu, 29 Sep 2016 18:09:12 +0100 Subject: [PATCH 0158/1167] net: hns: delete repeat read fbd num after while Because we handle the received packets after napi, so delete the checking before submitting. It delete the code of read the fbd number register, which reduces the cpu usages while receiving packets Signed-off-by: Daode Huang Reviewed-by: Yisen Zhuang Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index e6bfc51f80225..09ed237f4b4c7 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -760,7 +760,7 @@ static int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data, { struct hnae_ring *ring = ring_data->ring; struct sk_buff *skb; - int num, bnum, ex_num; + int num, bnum; #define RCB_NOF_ALLOC_RX_BUFF_ONCE 16 int recv_pkts, recv_bds, clean_count, err; int unused_count = hns_desc_unused(ring); @@ -770,7 +770,7 @@ static int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data, recv_pkts = 0, recv_bds = 0, clean_count = 0; num -= unused_count; -recv: + while (recv_pkts < budget && recv_bds < num) { /* reuse or realloc buffers */ if (clean_count + unused_count >= RCB_NOF_ALLOC_RX_BUFF_ONCE) { @@ -798,17 +798,6 @@ static int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data, recv_pkts++; } - /* make all data has been write before submit */ - if (recv_pkts < budget) { - ex_num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM); - ex_num -= unused_count; - if (ex_num > clean_count) { - num += ex_num - clean_count; - rmb(); /*complete read rx ring bd number*/ - goto recv; - } - } - out: /* make all data has been write before submit */ if (clean_count + unused_count > 0) -- GitLab From ea870bf93c5cd3635a07a0570cb7fe61436b0c3d Mon Sep 17 00:00:00 2001 From: Kejian Yan Date: Thu, 29 Sep 2016 18:09:13 +0100 Subject: [PATCH 0159/1167] net: hns: fix port not available after testing loopback After running command "ethtool -t eth0", eth0 can not be connected to network. It is caused by the changing the inner loopback register and this register cannot be changed when hns connected to network. The routine of setting this register needs to be removed and using promisc mode to let the packet looped back pass by dsaf mode. Reported-by: Jun He Signed-off-by: Kejian Yan Reviewed-by: Yisen Zhaung Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 3 --- drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c | 10 ---------- drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h | 1 - drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 7 +++++++ 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c index e28d960997af3..e0f9cdc54f40d 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c @@ -678,9 +678,6 @@ static int hns_ae_config_loopback(struct hnae_handle *handle, ret = -EINVAL; } - if (!ret) - hns_dsaf_set_inner_lb(mac_cb->dsaf_dev, mac_cb->mac_id, en); - return ret; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index 9283bc60bb240..827d8fb723707 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -768,16 +768,6 @@ void hns_dsaf_set_promisc_mode(struct dsaf_device *dsaf_dev, u32 en) DSAF_CFG_MIX_MODE_S, !!en); } -void hns_dsaf_set_inner_lb(struct dsaf_device *dsaf_dev, u32 mac_id, u32 en) -{ - if (AE_IS_VER1(dsaf_dev->dsaf_ver) || - dsaf_dev->mac_cb[mac_id]->mac_type == HNAE_PORT_DEBUG) - return; - - dsaf_set_dev_bit(dsaf_dev, DSAFV2_SERDES_LBK_0_REG + 4 * mac_id, - DSAFV2_SERDES_LBK_EN_B, !!en); -} - /** * hns_dsaf_tbl_stat_en - tbl * @dsaf_id: dsa fabric id diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h index 35df187e66f19..c494fc52be749 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h @@ -466,6 +466,5 @@ void hns_dsaf_get_rx_mac_pause_en(struct dsaf_device *dsaf_dev, int mac_id, u32 *en); int hns_dsaf_set_rx_mac_pause_en(struct dsaf_device *dsaf_dev, int mac_id, u32 en); -void hns_dsaf_set_inner_lb(struct dsaf_device *dsaf_dev, u32 mac_id, u32 en); #endif /* __HNS_DSAF_MAIN_H__ */ diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index ab33487a5321d..fa91ce32199ea 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -342,6 +342,13 @@ static int __lb_setup(struct net_device *ndev, break; } + if (!ret) { + if (loop == MAC_LOOP_NONE) + h->dev->ops->set_promisc_mode( + h, ndev->flags & IFF_PROMISC); + else + h->dev->ops->set_promisc_mode(h, 1); + } return ret; } -- GitLab From 58035fd92dcd54c8954c0813f229346b8febd5c0 Mon Sep 17 00:00:00 2001 From: Daode Huang Date: Thu, 29 Sep 2016 18:09:14 +0100 Subject: [PATCH 0160/1167] net: hns: fix the bug of forwarding table As the sub queue id in the broadcast forwarding table is always set to absolute queue 0 rather than the interface's relative queue 0, this will cause the received broadcast packets loopback to rcb. This patch sets the sub queue id to relative queue 0 of each port. Signed-off-by: Daode Huang Reviewed-by: Yisen Zhuang Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 8 ++++++-- drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 13 ++++++++++--- drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h | 2 ++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c index e0f9cdc54f40d..2d0cb609adc33 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c @@ -207,6 +207,7 @@ static int hns_ae_set_multicast_one(struct hnae_handle *handle, void *addr) int ret; char *mac_addr = (char *)addr; struct hns_mac_cb *mac_cb = hns_get_mac_cb(handle); + u8 port_num; assert(mac_cb); @@ -221,8 +222,11 @@ static int hns_ae_set_multicast_one(struct hnae_handle *handle, void *addr) return ret; } - ret = hns_mac_set_multi(mac_cb, DSAF_BASE_INNER_PORT_NUM, - mac_addr, true); + ret = hns_mac_get_inner_port_num(mac_cb, handle->vf_id, &port_num); + if (ret) + return ret; + + ret = hns_mac_set_multi(mac_cb, port_num, mac_addr, true); if (ret) dev_err(handle->owner_dev, "mac add mul_mac:%pM port%d fail, ret = %#x!\n", diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c index a68eef0ee65ff..151fd6e107e51 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c @@ -141,9 +141,10 @@ void hns_mac_adjust_link(struct hns_mac_cb *mac_cb, int speed, int duplex) *@port_num:port number * */ -static int hns_mac_get_inner_port_num(struct hns_mac_cb *mac_cb, - u8 vmid, u8 *port_num) +int hns_mac_get_inner_port_num(struct hns_mac_cb *mac_cb, u8 vmid, u8 *port_num) { + int q_num_per_vf, vf_num_per_port; + int vm_queue_id; u8 tmp_port; if (mac_cb->dsaf_dev->dsaf_mode <= DSAF_MODE_ENABLE) { @@ -174,6 +175,12 @@ static int hns_mac_get_inner_port_num(struct hns_mac_cb *mac_cb, return -EINVAL; } + q_num_per_vf = mac_cb->dsaf_dev->rcb_common[0]->max_q_per_vf; + vf_num_per_port = mac_cb->dsaf_dev->rcb_common[0]->max_vfn; + + vm_queue_id = vmid * q_num_per_vf + + vf_num_per_port * q_num_per_vf * mac_cb->mac_id; + switch (mac_cb->dsaf_dev->dsaf_mode) { case DSAF_MODE_ENABLE_FIX: tmp_port = 0; @@ -193,7 +200,7 @@ static int hns_mac_get_inner_port_num(struct hns_mac_cb *mac_cb, case DSAF_MODE_DISABLE_6PORT_2VM: case DSAF_MODE_DISABLE_6PORT_4VM: case DSAF_MODE_DISABLE_6PORT_16VM: - tmp_port = vmid; + tmp_port = vm_queue_id; break; default: dev_err(mac_cb->dev, "dsaf mode invalid,%s mac%d!\n", diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h index 4cbdf14f5c163..d3a1f72ece0e5 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h @@ -461,5 +461,7 @@ void hns_set_led_opt(struct hns_mac_cb *mac_cb); int hns_cpld_led_set_id(struct hns_mac_cb *mac_cb, enum hnae_led_state status); void hns_mac_set_promisc(struct hns_mac_cb *mac_cb, u8 en); +int hns_mac_get_inner_port_num(struct hns_mac_cb *mac_cb, + u8 vmid, u8 *port_num); #endif /* _HNS_DSAF_MAC_H */ -- GitLab From 2162a4a1ed8b61afed3b76137aff3ea031d9c6a6 Mon Sep 17 00:00:00 2001 From: Daode Huang Date: Thu, 29 Sep 2016 18:09:15 +0100 Subject: [PATCH 0161/1167] net: hns: bug fix about broadcast/multicast packets When the dsaf mode receives a broadcast packet, it will filter the packet by comparing the received queue number and destination queue number(get from forwarding table), if they are the same, the packet will be filtered. Otherwise, the packet will be loopback. So this patch select queue 0 to send broadcast and multicast packets. Signed-off-by: Daode Huang Reviewed-by: Yisen Zhuang Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 09ed237f4b4c7..5494e0e3fe8e6 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -1597,6 +1597,21 @@ struct rtnl_link_stats64 *hns_nic_get_stats64(struct net_device *ndev, return stats; } +static u16 +hns_nic_select_queue(struct net_device *ndev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +{ + struct ethhdr *eth_hdr = (struct ethhdr *)skb->data; + struct hns_nic_priv *priv = netdev_priv(ndev); + + /* fix hardware broadcast/multicast packets queue loopback */ + if (!AE_IS_VER1(priv->enet_ver) && + is_multicast_ether_addr(eth_hdr->h_dest)) + return 0; + else + return fallback(ndev, skb); +} + static const struct net_device_ops hns_nic_netdev_ops = { .ndo_open = hns_nic_net_open, .ndo_stop = hns_nic_net_stop, @@ -1612,6 +1627,7 @@ static const struct net_device_ops hns_nic_netdev_ops = { .ndo_poll_controller = hns_nic_poll_controller, #endif .ndo_set_rx_mode = hns_nic_set_rx_mode, + .ndo_select_queue = hns_nic_select_queue, }; static void hns_nic_update_link_status(struct net_device *netdev) -- GitLab From 5d80b3e1cf9900009d4a69a59f1c6b6114b072f4 Mon Sep 17 00:00:00 2001 From: Daode Huang Date: Thu, 29 Sep 2016 18:09:16 +0100 Subject: [PATCH 0162/1167] net: hns: delete redundant broadcast packet filter process The broadcast packets is filtered in the hardware now, so this process is no need in the driver, just delete it. Signed-off-by: Daode Huang Reviewed-by: Yisen Zhuang Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 5494e0e3fe8e6..a7abe118b5f0b 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -574,7 +574,6 @@ static int hns_nic_poll_rx_skb(struct hns_nic_ring_data *ring_data, struct sk_buff *skb; struct hnae_desc *desc; struct hnae_desc_cb *desc_cb; - struct ethhdr *eh; unsigned char *va; int bnum, length, i; int pull_len; @@ -600,7 +599,6 @@ static int hns_nic_poll_rx_skb(struct hns_nic_ring_data *ring_data, ring->stats.sw_err_cnt++; return -ENOMEM; } - skb_reset_mac_header(skb); prefetchw(skb->data); length = le16_to_cpu(desc->rx.pkt_len); @@ -682,14 +680,6 @@ static int hns_nic_poll_rx_skb(struct hns_nic_ring_data *ring_data, return -EFAULT; } - /* filter out multicast pkt with the same src mac as this port */ - eh = eth_hdr(skb); - if (unlikely(is_multicast_ether_addr(eh->h_dest) && - ether_addr_equal(ndev->dev_addr, eh->h_source))) { - dev_kfree_skb_any(skb); - return -EFAULT; - } - ring->stats.rx_pkts++; ring->stats.rx_bytes += skb->len; -- GitLab From 2eefca272275cb2eac048ddfa3f6fb30d9b24d5e Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Thu, 15 Sep 2016 23:48:06 +0100 Subject: [PATCH 0163/1167] IB/hns: Register HNS RoCE Driver get_netdev() with IB Core This patch adds get_netdev() function to the IB device. This shall be used to fetch netdev corresponding to the port number. This function would be called by IB core(Generic CM Agent) for example, when the RDMA connection is being established. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index f64f0dde9a882..39e69c31c5f25 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -372,6 +372,25 @@ static int hns_roce_query_device(struct ib_device *ib_dev, return 0; } +static struct net_device *hns_roce_get_netdev(struct ib_device *ib_dev, + u8 port_num) +{ + struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev); + struct net_device *ndev; + + if (port_num < 1 || port_num > hr_dev->caps.num_ports) + return NULL; + + rcu_read_lock(); + + ndev = hr_dev->iboe.netdevs[port_num - 1]; + if (ndev) + dev_hold(ndev); + + rcu_read_unlock(); + return ndev; +} + static int hns_roce_query_port(struct ib_device *ib_dev, u8 port_num, struct ib_port_attr *props) { @@ -618,6 +637,7 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) ib_dev->query_port = hns_roce_query_port; ib_dev->modify_port = hns_roce_modify_port; ib_dev->get_link_layer = hns_roce_get_link_layer; + ib_dev->get_netdev = hns_roce_get_netdev; ib_dev->query_gid = hns_roce_query_gid; ib_dev->query_pkey = hns_roce_query_pkey; ib_dev->alloc_ucontext = hns_roce_alloc_ucontext; -- GitLab From 31644665d41140c3961c5213350759edb24d5081 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Thu, 15 Sep 2016 23:48:07 +0100 Subject: [PATCH 0164/1167] IB/hns: Add & initialize "node_guid" parameter for RDMA CM According to the Infiniband spec, NodeGUID uniquely identifies a node. This must be initialized to some unique value. This patch adds the support to the HNS RoCE driver to fetch the NodeGUID value from DT or ACPI and then use this value to initialize the node_guid parameter of IB device. This value shall be used by RDMA CM. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_main.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index ea735800eb18e..e943b9864aa24 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -74,6 +74,7 @@ #define MR_TYPE_DMA 0x03 #define PKEY_ID 0xffff +#define GUID_LEN 8 #define NODE_DESC_SIZE 64 #define SERV_TYPE_RC 0 diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 39e69c31c5f25..f0700f4ca2c34 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -797,6 +797,15 @@ static int hns_roce_get_cfg(struct hns_roce_dev *hr_dev) if (IS_ERR(hr_dev->reg_base)) return PTR_ERR(hr_dev->reg_base); + /* read the node_guid of IB device from the DT or ACPI */ + ret = device_property_read_u8_array(dev, "node-guid", + (u8 *)&hr_dev->ib_dev.node_guid, + GUID_LEN); + if (ret) { + dev_err(dev, "couldn't get node_guid from DT or ACPI!\n"); + return ret; + } + /* get the RoCE associated ethernet ports or netdevices */ for (i = 0; i < HNS_ROCE_MAX_PORTS; i++) { if (dev_of_node(dev)) { -- GitLab From a74aab6c2fdbd9f9501638f67ebedce49d9a8195 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Thu, 15 Sep 2016 23:48:08 +0100 Subject: [PATCH 0165/1167] IB/hns: Fix the value of device_cap_flags In the latest IB core version, it has some known issues with memory registration using the local_dma_lkey. Thus RoCE don't expose support for it, and remove device->local_dma_lkey which is introduced to working systems. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index f0700f4ca2c34..a9960ba706718 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -355,8 +355,7 @@ static int hns_roce_query_device(struct ib_device *ib_dev, props->max_qp = hr_dev->caps.num_qps; props->max_qp_wr = hr_dev->caps.max_wqes; props->device_cap_flags = IB_DEVICE_PORT_ACTIVE_EVENT | - IB_DEVICE_RC_RNR_NAK_GEN | - IB_DEVICE_LOCAL_DMA_LKEY; + IB_DEVICE_RC_RNR_NAK_GEN; props->max_sge = hr_dev->caps.max_sq_sg; props->max_sge_rd = 1; props->max_cq = hr_dev->caps.num_cqs; -- GitLab From c24bf895c56157e4d0fba7717ed565f2f3fc25aa Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Thu, 15 Sep 2016 23:48:09 +0100 Subject: [PATCH 0166/1167] IB/hns: Fix two possible bugs for rdma cm Fix the length of wqe that maybe lead to an error and write the end bytes of QP1C into the register. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 399f5dedaf2dd..aaea95c99f02f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -205,8 +205,7 @@ int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, (wr->send_flags & IB_SEND_FENCE ? (cpu_to_le32(HNS_ROCE_WQE_FENCE)) : 0); - wqe = (struct hns_roce_wqe_ctrl_seg *)wqe + - sizeof(struct hns_roce_wqe_ctrl_seg); + wqe += sizeof(struct hns_roce_wqe_ctrl_seg); switch (wr->opcode) { case IB_WR_RDMA_READ: @@ -235,8 +234,7 @@ int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, break; } ctrl->flag |= cpu_to_le32(ps_opcode); - wqe = (struct hns_roce_wqe_raddr_seg *)wqe + - sizeof(struct hns_roce_wqe_raddr_seg); + wqe += sizeof(struct hns_roce_wqe_raddr_seg); dseg = wqe; if (wr->send_flags & IB_SEND_INLINE && wr->num_sge) { @@ -253,8 +251,7 @@ int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, memcpy(wqe, ((void *) (uintptr_t) wr->sg_list[i].addr), wr->sg_list[i].length); - wqe = (struct hns_roce_wqe_raddr_seg *) - wqe + wr->sg_list[i].length; + wqe += wr->sg_list[i].length; } ctrl->flag |= HNS_ROCE_WQE_INLINE; } else { @@ -1795,6 +1792,7 @@ static int hns_roce_v1_m_sqp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, writel(context->qp1c_bytes_28, addr + 6); writel(context->qp1c_bytes_32, addr + 7); writel(context->cur_sq_wqe_ba_l, addr + 8); + writel(context->qp1c_bytes_40, addr + 9); } /* Modify QP1C status */ -- GitLab From 7716809efe5727d7fbf9cbf5689ef4162d999de5 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Thu, 15 Sep 2016 23:48:10 +0100 Subject: [PATCH 0167/1167] IB/hns: Add phy_port for computing GSI/QPN This patch mainly adds phy_port to HNS RoCE QP. This shall be used in calculating the GSI QPN for the port. Initally when RDMA is being established, all IB ports share a QPN which later needs to be re-assigned to a particular GSI/QPN and which is per-port. This also fixes a bug in base driver where iboe port was being used instead of phy_port at some places. This values might not be same always. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 30 +++++++++++---------- drivers/infiniband/hw/hns/hns_roce_qp.c | 13 +++++---- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index e943b9864aa24..833742b625678 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -409,6 +409,7 @@ struct hns_roce_qp { u32 buff_size; struct mutex mutex; u8 port; + u8 phy_port; u8 sl; u8 resp_depth; u8 state; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index aaea95c99f02f..581e542464654 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -162,7 +162,7 @@ int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, roce_set_field(ud_sq_wqe->u32_36, UD_SEND_WQE_U32_36_SGID_INDEX_M, UD_SEND_WQE_U32_36_SGID_INDEX_S, - hns_get_gid_index(hr_dev, qp->port, + hns_get_gid_index(hr_dev, qp->phy_port, ah->av.gid_index)); roce_set_field(ud_sq_wqe->u32_40, @@ -282,7 +282,7 @@ int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, SQ_DOORBELL_U32_4_SQ_HEAD_S, (qp->sq.head & ((qp->sq.wqe_cnt << 1) - 1))); roce_set_field(sq_db.u32_4, SQ_DOORBELL_U32_4_PORT_M, - SQ_DOORBELL_U32_4_PORT_S, qp->port); + SQ_DOORBELL_U32_4_PORT_S, qp->phy_port); roce_set_field(sq_db.u32_8, SQ_DOORBELL_U32_8_QPN_M, SQ_DOORBELL_U32_8_QPN_S, qp->doorbell_qpn); roce_set_bit(sq_db.u32_8, SQ_DOORBELL_HW_SYNC_S, 1); @@ -362,14 +362,14 @@ int hns_roce_v1_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, /* SW update GSI rq header */ reg_val = roce_read(to_hr_dev(ibqp->device), ROCEE_QP1C_CFG3_0_REG + - QP1C_CFGN_OFFSET * hr_qp->port); + QP1C_CFGN_OFFSET * hr_qp->phy_port); roce_set_field(reg_val, ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_M, ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_S, hr_qp->rq.head); roce_write(to_hr_dev(ibqp->device), ROCEE_QP1C_CFG3_0_REG + - QP1C_CFGN_OFFSET * hr_qp->port, reg_val); + QP1C_CFGN_OFFSET * hr_qp->phy_port, reg_val); } else { rq_db.u32_4 = 0; rq_db.u32_8 = 0; @@ -1730,7 +1730,7 @@ static int hns_roce_v1_m_sqp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, roce_set_field(context->qp1c_bytes_16, QP1C_BYTES_16_RQ_HEAD_M, QP1C_BYTES_16_RQ_HEAD_S, hr_qp->rq.head); roce_set_field(context->qp1c_bytes_16, QP1C_BYTES_16_PORT_NUM_M, - QP1C_BYTES_16_PORT_NUM_S, hr_qp->port); + QP1C_BYTES_16_PORT_NUM_S, hr_qp->phy_port); roce_set_bit(context->qp1c_bytes_16, QP1C_BYTES_16_SIGNALING_TYPE_S, hr_qp->sq_signal_bits); @@ -1781,7 +1781,7 @@ static int hns_roce_v1_m_sqp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, /* Copy context to QP1C register */ addr = (u32 *)(hr_dev->reg_base + ROCEE_QP1C_CFG0_0_REG + - hr_qp->port * sizeof(*context)); + hr_qp->phy_port * sizeof(*context)); writel(context->qp1c_bytes_4, addr); writel(context->sq_rq_bt_l, addr + 1); @@ -1797,11 +1797,11 @@ static int hns_roce_v1_m_sqp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, /* Modify QP1C status */ reg_val = roce_read(hr_dev, ROCEE_QP1C_CFG0_0_REG + - hr_qp->port * sizeof(*context)); + hr_qp->phy_port * sizeof(*context)); roce_set_field(reg_val, ROCEE_QP1C_CFG0_0_ROCEE_QP1C_QP_ST_M, ROCEE_QP1C_CFG0_0_ROCEE_QP1C_QP_ST_S, new_state); roce_write(hr_dev, ROCEE_QP1C_CFG0_0_REG + - hr_qp->port * sizeof(*context), reg_val); + hr_qp->phy_port * sizeof(*context), reg_val); hr_qp->state = new_state; if (new_state == IB_QPS_RESET) { @@ -2184,7 +2184,7 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, roce_set_field(context->qpc_bytes_156, QP_CONTEXT_QPC_BYTES_156_PORT_NUM_M, QP_CONTEXT_QPC_BYTES_156_PORT_NUM_S, - hr_qp->port); + hr_qp->phy_port); roce_set_field(context->qpc_bytes_156, QP_CONTEXT_QPC_BYTES_156_SL_M, QP_CONTEXT_QPC_BYTES_156_SL_S, attr->ah_attr.sl); @@ -2290,7 +2290,7 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, roce_set_field(context->qpc_bytes_156, QP_CONTEXT_QPC_BYTES_156_PORT_NUM_M, QP_CONTEXT_QPC_BYTES_156_PORT_NUM_S, - hr_qp->port); + hr_qp->phy_port); roce_set_field(context->qpc_bytes_156, QP_CONTEXT_QPC_BYTES_156_SL_M, QP_CONTEXT_QPC_BYTES_156_SL_S, attr->ah_attr.sl); @@ -2398,13 +2398,13 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, if (hr_qp->ibqp.qp_type == IB_QPT_GSI) { /* SW update GSI rq header */ reg_val = roce_read(hr_dev, ROCEE_QP1C_CFG3_0_REG + - QP1C_CFGN_OFFSET * hr_qp->port); + QP1C_CFGN_OFFSET * hr_qp->phy_port); roce_set_field(reg_val, ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_M, ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_S, hr_qp->rq.head); roce_write(hr_dev, ROCEE_QP1C_CFG3_0_REG + - QP1C_CFGN_OFFSET * hr_qp->port, reg_val); + QP1C_CFGN_OFFSET * hr_qp->phy_port, reg_val); } else { rq_db.u32_4 = 0; rq_db.u32_8 = 0; @@ -2430,8 +2430,10 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) hr_qp->resp_depth = attr->max_dest_rd_atomic; - if (attr_mask & IB_QP_PORT) - hr_qp->port = (attr->port_num - 1); + if (attr_mask & IB_QP_PORT) { + hr_qp->port = attr->port_num - 1; + hr_qp->phy_port = hr_dev->iboe.phy_port[hr_qp->port]; + } if (new_state == IB_QPS_RESET && !ibqp->uobject) { hns_roce_v1_cq_clean(to_hr_cq(ibqp->recv_cq), hr_qp->qpn, diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 645c18d809a5d..089da7f39ed02 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -617,21 +617,20 @@ struct ib_qp *hns_roce_create_qp(struct ib_pd *pd, return ERR_PTR(-ENOMEM); hr_qp = &hr_sqp->hr_qp; + hr_qp->port = init_attr->port_num - 1; + hr_qp->phy_port = hr_dev->iboe.phy_port[hr_qp->port]; + hr_qp->ibqp.qp_num = hr_dev->caps.sqp_start + + HNS_ROCE_MAX_PORTS + + hr_dev->iboe.phy_port[hr_qp->port]; ret = hns_roce_create_qp_common(hr_dev, pd, init_attr, udata, - hr_dev->caps.sqp_start + - hr_dev->caps.num_ports + - init_attr->port_num - 1, hr_qp); + hr_qp->ibqp.qp_num, hr_qp); if (ret) { dev_err(dev, "Create GSI QP failed!\n"); kfree(hr_sqp); return ERR_PTR(ret); } - hr_qp->port = (init_attr->port_num - 1); - hr_qp->ibqp.qp_num = hr_dev->caps.sqp_start + - hr_dev->caps.num_ports + - init_attr->port_num - 1; break; } default:{ -- GitLab From b280db52cc71a0cb135c2ab9adc0592af6440812 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Thu, 15 Sep 2016 23:48:11 +0100 Subject: [PATCH 0168/1167] IB/hns: Change the logic for allocating uar registers This patch mainly modifies the logic for allocating uar registers. In HiP06 SoC, HW has 8 group of uar registers for kernel and user space application. The uar index is assigned as follows: 0 ------ for kernel 1~7 ------ for user space application Signed-off-by: Lijun Ou Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_pd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c index 16271b5bd1701..4109f74a4ceb4 100644 --- a/drivers/infiniband/hw/hns/hns_roce_pd.c +++ b/drivers/infiniband/hw/hns/hns_roce_pd.c @@ -117,7 +117,9 @@ int hns_roce_uar_alloc(struct hns_roce_dev *hr_dev, struct hns_roce_uar *uar) if (ret == -1) return -ENOMEM; - uar->index = (uar->index - 1) % hr_dev->caps.phy_num_uars + 1; + if (uar->index > 0) + uar->index = (uar->index - 1) % + (hr_dev->caps.phy_num_uars - 1) + 1; res = platform_get_resource(hr_dev->pdev, IORESOURCE_MEM, 0); uar->pfn = ((res->start) >> PAGE_SHIFT) + uar->index; -- GitLab From 509bf0c2da99f0fc22c841de1fa3d813e4932a9f Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Thu, 15 Sep 2016 23:48:12 +0100 Subject: [PATCH 0169/1167] IB/hns: Fix the bug of rdma cm connecting on user mode Fix bug of modify qp from init to init on user mode. Otherwise, it will oops when rmda cm established. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 43 +++++++-------------- drivers/infiniband/hw/hns/hns_roce_qp.c | 1 - 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 833742b625678..e8d273408fe1b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -76,6 +76,7 @@ #define PKEY_ID 0xffff #define GUID_LEN 8 #define NODE_DESC_SIZE 64 +#define DB_REG_OFFSET 0x1000 #define SERV_TYPE_RC 0 #define SERV_TYPE_RD 1 diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 581e542464654..110efd3aa7cb3 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -1834,12 +1834,10 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); struct device *dev = &hr_dev->pdev->dev; struct hns_roce_qp_context *context; - struct hns_roce_rq_db rq_db; dma_addr_t dma_handle_2 = 0; dma_addr_t dma_handle = 0; uint32_t doorbell[2] = {0}; int rq_pa_start = 0; - u32 reg_val = 0; u64 *mtts_2 = NULL; int ret = -EINVAL; u64 *mtts = NULL; @@ -2395,35 +2393,22 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, if (cur_state == IB_QPS_INIT && new_state == IB_QPS_INIT) { /* Memory barrier */ wmb(); - if (hr_qp->ibqp.qp_type == IB_QPT_GSI) { - /* SW update GSI rq header */ - reg_val = roce_read(hr_dev, ROCEE_QP1C_CFG3_0_REG + - QP1C_CFGN_OFFSET * hr_qp->phy_port); - roce_set_field(reg_val, - ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_M, - ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_S, - hr_qp->rq.head); - roce_write(hr_dev, ROCEE_QP1C_CFG3_0_REG + - QP1C_CFGN_OFFSET * hr_qp->phy_port, reg_val); - } else { - rq_db.u32_4 = 0; - rq_db.u32_8 = 0; - roce_set_field(rq_db.u32_4, RQ_DOORBELL_U32_4_RQ_HEAD_M, - RQ_DOORBELL_U32_4_RQ_HEAD_S, - hr_qp->rq.head); - roce_set_field(rq_db.u32_8, RQ_DOORBELL_U32_8_QPN_M, - RQ_DOORBELL_U32_8_QPN_S, hr_qp->qpn); - roce_set_field(rq_db.u32_8, RQ_DOORBELL_U32_8_CMD_M, - RQ_DOORBELL_U32_8_CMD_S, 1); - roce_set_bit(rq_db.u32_8, RQ_DOORBELL_U32_8_HW_SYNC_S, - 1); - - doorbell[0] = rq_db.u32_4; - doorbell[1] = rq_db.u32_8; - - hns_roce_write64_k(doorbell, hr_qp->rq.db_reg_l); + roce_set_field(doorbell[0], RQ_DOORBELL_U32_4_RQ_HEAD_M, + RQ_DOORBELL_U32_4_RQ_HEAD_S, hr_qp->rq.head); + roce_set_field(doorbell[1], RQ_DOORBELL_U32_8_QPN_M, + RQ_DOORBELL_U32_8_QPN_S, hr_qp->qpn); + roce_set_field(doorbell[1], RQ_DOORBELL_U32_8_CMD_M, + RQ_DOORBELL_U32_8_CMD_S, 1); + roce_set_bit(doorbell[1], RQ_DOORBELL_U32_8_HW_SYNC_S, 1); + + if (ibqp->uobject) { + hr_qp->rq.db_reg_l = hr_dev->reg_base + + ROCEE_DB_OTHERS_L_0_REG + + DB_REG_OFFSET * hr_dev->priv_uar.index; } + + hns_roce_write64_k(doorbell, hr_qp->rq.db_reg_l); } hr_qp->state = new_state; diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 089da7f39ed02..dd94e4156a59d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -38,7 +38,6 @@ #include "hns_roce_hem.h" #include "hns_roce_user.h" -#define DB_REG_OFFSET 0x1000 #define SQP_NUM 12 void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type) -- GitLab From ac11125bfd63a87d29838d0a1cd66b92c1997c03 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Thu, 15 Sep 2016 23:48:13 +0100 Subject: [PATCH 0170/1167] IB/hns: Fix two bugs for rdma cm connecting This patch mainly modify the value of HNS_ROCE_SL_SHIFT and delete the lines for assigning for the field of local_enable_e2e_credit in QP1C. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_device.h | 2 +- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index e8d273408fe1b..4d02bcfdf2947 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -62,7 +62,7 @@ #define HNS_ROCE_AEQE_OF_VEC_NUM 1 /* 4G/4K = 1M */ -#define HNS_ROCE_SL_SHIFT 29 +#define HNS_ROCE_SL_SHIFT 28 #define HNS_ROCE_TCLASS_SHIFT 20 #define HNS_ROCE_FLOW_LABLE_MASK 0xfffff diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 110efd3aa7cb3..5ffdf7a3e6e35 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -1734,9 +1734,6 @@ static int hns_roce_v1_m_sqp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, roce_set_bit(context->qp1c_bytes_16, QP1C_BYTES_16_SIGNALING_TYPE_S, hr_qp->sq_signal_bits); - roce_set_bit(context->qp1c_bytes_16, - QP1C_BYTES_16_LOCAL_ENABLE_E2E_CREDIT_S, - hr_qp->sq_signal_bits); roce_set_bit(context->qp1c_bytes_16, QP1C_BYTES_16_RQ_BA_FLG_S, 1); roce_set_bit(context->qp1c_bytes_16, QP1C_BYTES_16_SQ_BA_FLG_S, -- GitLab From 1cfbfdd84274fcfb922d814acf3c709e9ae5fa00 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Thu, 15 Sep 2016 23:48:14 +0100 Subject: [PATCH 0171/1167] IB/hns: Add node_guid definition to the bindings document This patch adds node_guid definition in bindings document. The value of node_guid will be used during RDMA connection. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- .../devicetree/bindings/infiniband/hisilicon-hns-roce.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt b/Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt index f97993be2dcbd..d3b273e4336a7 100644 --- a/Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt +++ b/Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt @@ -14,6 +14,7 @@ length of memory mapped region. representing a ethernet device. - dsaf-handle: phandle, specifies a reference to a node representing a dsaf device. +- node_guid: a number that uniquely identifies a device or component - #address-cells: must be 2 - #size-cells: must be 2 Optional properties: @@ -32,6 +33,7 @@ Example: dma-coherent; eth-handle = <ð2 ð3 ð4 ð5 ð6 ð7>; dsaf-handle = <&soc0_dsa>; + node-guid = [00 9A CD 00 00 01 02 03]; #address-cells = <2>; #size-cells = <2>; interrupt-parent = <&mbigen_dsa>; -- GitLab From a4be892e834e8a5a38279c2ebca747b5c7a68f75 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:06:54 +0100 Subject: [PATCH 0172/1167] IB/hns: Remove unused parameters in some functions The parameter named collapsed unused in hns_roce_cq_alloc. Also, parameter named doorbell_lock unsed in hns_roce_v1_cq_set_ci. This patch optimize these parameters. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_cq.c | 7 +++---- drivers/infiniband/hw/hns/hns_roce_device.h | 1 - drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 13 ++++--------- drivers/infiniband/hw/hns/hns_roce_main.c | 1 - 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index 875597b0e69c5..10fd2093ca184 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -83,8 +83,7 @@ static int hns_roce_sw2hw_cq(struct hns_roce_dev *dev, static int hns_roce_cq_alloc(struct hns_roce_dev *hr_dev, int nent, struct hns_roce_mtt *hr_mtt, struct hns_roce_uar *hr_uar, - struct hns_roce_cq *hr_cq, int vector, - int collapsed) + struct hns_roce_cq *hr_cq, int vector) { struct hns_roce_cmd_mailbox *mailbox = NULL; struct hns_roce_cq_table *cq_table = NULL; @@ -338,8 +337,8 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev, } /* Allocate cq index, fill cq_context */ - ret = hns_roce_cq_alloc(hr_dev, cq_entries, &hr_cq->hr_buf.hr_mtt, - uar, hr_cq, vector, 0); + ret = hns_roce_cq_alloc(hr_dev, cq_entries, &hr_cq->hr_buf.hr_mtt, uar, + hr_cq, vector); if (ret) { dev_err(dev, "Creat CQ .Failed to cq_alloc.\n"); goto err_mtt; diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 4d02bcfdf2947..db974e4008182 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -536,7 +536,6 @@ struct hns_roce_dev { struct hns_roce_uar priv_uar; const char *irq_names[HNS_ROCE_MAX_IRQ_NUM]; spinlock_t sm_lock; - spinlock_t cq_db_lock; spinlock_t bt_cmd_lock; struct hns_roce_ib_iboe iboe; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 5ffdf7a3e6e35..48c08627faf1a 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -1189,9 +1189,7 @@ static struct hns_roce_cqe *next_cqe_sw(struct hns_roce_cq *hr_cq) return get_sw_cqe(hr_cq, hr_cq->cons_index); } -void hns_roce_v1_cq_set_ci(struct hns_roce_cq *hr_cq, u32 cons_index, - spinlock_t *doorbell_lock) - +void hns_roce_v1_cq_set_ci(struct hns_roce_cq *hr_cq, u32 cons_index) { u32 doorbell[2]; @@ -1251,8 +1249,7 @@ static void __hns_roce_v1_cq_clean(struct hns_roce_cq *hr_cq, u32 qpn, */ wmb(); - hns_roce_v1_cq_set_ci(hr_cq, hr_cq->cons_index, - &to_hr_dev(hr_cq->ib_cq.device)->cq_db_lock); + hns_roce_v1_cq_set_ci(hr_cq, hr_cq->cons_index); } } @@ -1588,10 +1585,8 @@ int hns_roce_v1_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) break; } - if (npolled) { - hns_roce_v1_cq_set_ci(hr_cq, hr_cq->cons_index, - &to_hr_dev(ibcq->device)->cq_db_lock); - } + if (npolled) + hns_roce_v1_cq_set_ci(hr_cq, hr_cq->cons_index); spin_unlock_irqrestore(&hr_cq->lock, flags); diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index a9960ba706718..4b44998a039ea 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -951,7 +951,6 @@ static int hns_roce_setup_hca(struct hns_roce_dev *hr_dev) struct device *dev = &hr_dev->pdev->dev; spin_lock_init(&hr_dev->sm_lock); - spin_lock_init(&hr_dev->cq_db_lock); spin_lock_init(&hr_dev->bt_cmd_lock); ret = hns_roce_init_uar_table(hr_dev); -- GitLab From 622b85f9f7fbe1255649894d03e9e077b1a97e6c Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:06:55 +0100 Subject: [PATCH 0173/1167] IB/hns: Remove parameters of resize cq In old version of RoCE, it doesn't support to resize cq. So, we remove parameters related to resize cq. Signed-off-by: Lijun Ou Signed-off-by: Dongdong Huang(Donald) Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_cq.c | 3 --- drivers/infiniband/hw/hns/hns_roce_device.h | 9 --------- 2 files changed, 12 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index 10fd2093ca184..a52306f9c1de0 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -299,10 +299,7 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev, cq_entries = roundup_pow_of_two((unsigned int)cq_entries); hr_cq->ib_cq.cqe = cq_entries - 1; - mutex_init(&hr_cq->resize_mutex); spin_lock_init(&hr_cq->lock); - hr_cq->hr_resize_buf = NULL; - hr_cq->resize_umem = NULL; if (context) { if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index db974e4008182..15bc229041c70 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -284,20 +284,11 @@ struct hns_roce_cq_buf { struct hns_roce_mtt hr_mtt; }; -struct hns_roce_cq_resize { - struct hns_roce_cq_buf hr_buf; - int cqe; -}; - struct hns_roce_cq { struct ib_cq ib_cq; struct hns_roce_cq_buf hr_buf; - /* pointer to store information after resize*/ - struct hns_roce_cq_resize *hr_resize_buf; spinlock_t lock; - struct mutex resize_mutex; struct ib_umem *umem; - struct ib_umem *resize_umem; void (*comp)(struct hns_roce_cq *); void (*event)(struct hns_roce_cq *, enum hns_roce_event); -- GitLab From ed3e6d01138eb26634abb519bc66e0b0dc473d0e Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:06:56 +0100 Subject: [PATCH 0174/1167] IB/hns: Fix bug of using uninit refcount and free In current version, it uses uninitialized parameters named refcount and free in hns_roce_cq_event. This patch initializes these parameter in cq alloc and add correspond process in cq free. Signed-off-by: Lijun Ou Signed-off-by: Dongdong Huang(Donald) Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_cq.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index a52306f9c1de0..3095f06099e68 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -152,6 +152,9 @@ static int hns_roce_cq_alloc(struct hns_roce_dev *hr_dev, int nent, hr_cq->cons_index = 0; hr_cq->uar = hr_uar; + atomic_set(&hr_cq->refcount, 1); + init_completion(&hr_cq->free); + return 0; err_radix: @@ -191,6 +194,11 @@ static void hns_roce_free_cq(struct hns_roce_dev *hr_dev, /* Waiting interrupt process procedure carried out */ synchronize_irq(hr_dev->eq_table.eq[hr_cq->vector].irq); + /* wait for all interrupt processed */ + if (atomic_dec_and_test(&hr_cq->refcount)) + complete(&hr_cq->free); + wait_for_completion(&hr_cq->free); + spin_lock_irq(&cq_table->lock); radix_tree_delete(&cq_table->tree, hr_cq->cqn); spin_unlock_irq(&cq_table->lock); -- GitLab From a598c6f4c5a838f3141a739aa0f6799c5bf0afa9 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:06:57 +0100 Subject: [PATCH 0175/1167] IB/hns: Simplify function of pd alloc and qp alloc Hns_roce_pd_alloc and hns_roce_reserve_range_qp use unnecessary transformation of parameters. This patch simplify these two functions. Signed-off-by: Lijun Ou Signed-off-by: Dongdong Huang(Donald) Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_pd.c | 14 +------------- drivers/infiniband/hw/hns/hns_roce_qp.c | 10 +--------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c index 4109f74a4ceb4..0cd6132b75f04 100644 --- a/drivers/infiniband/hw/hns/hns_roce_pd.c +++ b/drivers/infiniband/hw/hns/hns_roce_pd.c @@ -35,19 +35,7 @@ static int hns_roce_pd_alloc(struct hns_roce_dev *hr_dev, unsigned long *pdn) { - struct device *dev = &hr_dev->pdev->dev; - unsigned long pd_number; - int ret = 0; - - ret = hns_roce_bitmap_alloc(&hr_dev->pd_bitmap, &pd_number); - if (ret == -1) { - dev_err(dev, "alloc pdn from pdbitmap failed\n"); - return -ENOMEM; - } - - *pdn = pd_number; - - return 0; + return hns_roce_bitmap_alloc(&hr_dev->pd_bitmap, pdn); } static void hns_roce_pd_free(struct hns_roce_dev *hr_dev, unsigned long pdn) diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index dd94e4156a59d..73de1d3dbb323 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -112,16 +112,8 @@ static int hns_roce_reserve_range_qp(struct hns_roce_dev *hr_dev, int cnt, int align, unsigned long *base) { struct hns_roce_qp_table *qp_table = &hr_dev->qp_table; - int ret = 0; - unsigned long qpn; - - ret = hns_roce_bitmap_alloc_range(&qp_table->bitmap, cnt, align, &qpn); - if (ret == -1) - return -ENOMEM; - *base = qpn; - - return 0; + return hns_roce_bitmap_alloc_range(&qp_table->bitmap, cnt, align, base); } enum hns_roce_qp_state to_hns_roce_state(enum ib_qp_state state) -- GitLab From 76445703e54326f9039d6302b78ad6e8dab17777 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:06:58 +0100 Subject: [PATCH 0176/1167] IB/hns: Remove unused parameter named qp_type This patch removes the qp_type parameter in hns_roce_set_kernel_sq_size(). Signed-off-by: Lijun Ou Signed-off-by: Ping Zhang Reviewed-by: Wei Hu Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_qp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 73de1d3dbb323..177f48f081ab8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -336,12 +336,10 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev, static int hns_roce_set_kernel_sq_size(struct hns_roce_dev *hr_dev, struct ib_qp_cap *cap, - enum ib_qp_type type, struct hns_roce_qp *hr_qp) { struct device *dev = &hr_dev->pdev->dev; u32 max_cnt; - (void)type; if (cap->max_send_wr > hr_dev->caps.max_wqes || cap->max_send_sge > hr_dev->caps.max_sq_sg || @@ -467,7 +465,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev, /* Set SQ size */ ret = hns_roce_set_kernel_sq_size(hr_dev, &init_attr->cap, - init_attr->qp_type, hr_qp); + hr_qp); if (ret) { dev_err(dev, "hns_roce_set_kernel_sq_size error!\n"); goto err_out; -- GitLab From 97f0e39fa51406e7d73b37e635c04c85829ce9ab Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Tue, 20 Sep 2016 17:06:59 +0100 Subject: [PATCH 0177/1167] IB/hns: Fix bug of clear hem In hip06, there's no interface to release hem memory. So, hardware can't identify whether hem memory released or not. If all context in a hem memory released, the related hem memory will be released by driver and reused by others. But, hardware don't know that this memory can't be used already. In order to fix this bug, hns roce driver reserved 128K memory for each type of hem(QPC/CQC/MTPT). While unmap hem memory, hns roce driver will write base address of reserved memory according to hem type. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Dongdong Huang(Donald) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_device.h | 2 + drivers/infiniband/hw/hns/hns_roce_hem.c | 76 +---------- drivers/infiniband/hw/hns/hns_roce_hem.h | 4 + drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 140 ++++++++++++++++++++ drivers/infiniband/hw/hns/hns_roce_hw_v1.h | 9 ++ 5 files changed, 157 insertions(+), 74 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 15bc229041c70..3058599d0404c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -506,6 +506,8 @@ struct hns_roce_hw { void (*write_cqc)(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq, void *mb_buf, u64 *mtts, dma_addr_t dma_handle, int nent, u32 vector); + int (*clear_hem)(struct hns_roce_dev *hr_dev, + struct hns_roce_hem_table *table, int obj); int (*query_qp)(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr); int (*modify_qp)(struct ib_qp *ibqp, const struct ib_qp_attr *attr, diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c index d53d643623899..250d8f2803908 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hem.c +++ b/drivers/infiniband/hw/hns/hns_roce_hem.c @@ -36,14 +36,10 @@ #include "hns_roce_hem.h" #include "hns_roce_common.h" -#define HW_SYNC_TIMEOUT_MSECS 500 -#define HW_SYNC_SLEEP_TIME_INTERVAL 20 - #define HNS_ROCE_HEM_ALLOC_SIZE (1 << 17) #define HNS_ROCE_TABLE_CHUNK_SIZE (1 << 17) #define DMA_ADDR_T_SHIFT 12 -#define BT_CMD_SYNC_SHIFT 31 #define BT_BA_SHIFT 32 struct hns_roce_hem *hns_roce_alloc_hem(struct hns_roce_dev *hr_dev, int npages, @@ -213,74 +209,6 @@ static int hns_roce_set_hem(struct hns_roce_dev *hr_dev, return ret; } -static int hns_roce_clear_hem(struct hns_roce_dev *hr_dev, - struct hns_roce_hem_table *table, - unsigned long obj) -{ - struct device *dev = &hr_dev->pdev->dev; - unsigned long end = 0; - unsigned long flags; - void __iomem *bt_cmd; - uint32_t bt_cmd_val[2]; - u32 bt_cmd_h_val = 0; - int ret = 0; - - switch (table->type) { - case HEM_TYPE_QPC: - roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, - ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_QPC); - break; - case HEM_TYPE_MTPT: - roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, - ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, - HEM_TYPE_MTPT); - break; - case HEM_TYPE_CQC: - roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, - ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_CQC); - break; - case HEM_TYPE_SRQC: - roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, - ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, - HEM_TYPE_SRQC); - break; - default: - return ret; - } - roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_M, - ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_S, obj); - roce_set_bit(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_S, 0); - roce_set_bit(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_HW_SYNS_S, 1); - roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_M, - ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_S, 0); - - spin_lock_irqsave(&hr_dev->bt_cmd_lock, flags); - - bt_cmd = hr_dev->reg_base + ROCEE_BT_CMD_H_REG; - - end = msecs_to_jiffies(HW_SYNC_TIMEOUT_MSECS) + jiffies; - while (1) { - if (readl(bt_cmd) >> BT_CMD_SYNC_SHIFT) { - if (!(time_before(jiffies, end))) { - dev_err(dev, "Write bt_cmd err,hw_sync is not zero.\n"); - spin_unlock_irqrestore(&hr_dev->bt_cmd_lock, - flags); - return -EBUSY; - } - } else { - break; - } - msleep(HW_SYNC_SLEEP_TIME_INTERVAL); - } - - bt_cmd_val[0] = 0; - bt_cmd_val[1] = bt_cmd_h_val; - hns_roce_write64_k(bt_cmd_val, hr_dev->reg_base + ROCEE_BT_CMD_L_REG); - spin_unlock_irqrestore(&hr_dev->bt_cmd_lock, flags); - - return ret; -} - int hns_roce_table_get(struct hns_roce_dev *hr_dev, struct hns_roce_hem_table *table, unsigned long obj) { @@ -333,7 +261,7 @@ void hns_roce_table_put(struct hns_roce_dev *hr_dev, if (--table->hem[i]->refcount == 0) { /* Clear HEM base address */ - if (hns_roce_clear_hem(hr_dev, table, obj)) + if (hr_dev->hw->clear_hem(hr_dev, table, obj)) dev_warn(dev, "Clear HEM base address failed.\n"); hns_roce_free_hem(hr_dev, table->hem[i]); @@ -456,7 +384,7 @@ void hns_roce_cleanup_hem_table(struct hns_roce_dev *hr_dev, for (i = 0; i < table->num_hem; ++i) if (table->hem[i]) { - if (hns_roce_clear_hem(hr_dev, table, + if (hr_dev->hw->clear_hem(hr_dev, table, i * HNS_ROCE_TABLE_CHUNK_SIZE / table->obj_size)) dev_err(dev, "Clear HEM base address failed.\n"); diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.h b/drivers/infiniband/hw/hns/hns_roce_hem.h index ad6617588fba9..435748858252d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hem.h +++ b/drivers/infiniband/hw/hns/hns_roce_hem.h @@ -34,6 +34,10 @@ #ifndef _HNS_ROCE_HEM_H #define _HNS_ROCE_HEM_H +#define HW_SYNC_TIMEOUT_MSECS 500 +#define HW_SYNC_SLEEP_TIME_INTERVAL 20 +#define BT_CMD_SYNC_SHIFT 31 + enum { /* MAP HEM(Hardware Entry Memory) */ HEM_TYPE_QPC = 0, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 48c08627faf1a..d767ebebd27e6 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -786,6 +786,66 @@ static void hns_roce_port_enable(struct hns_roce_dev *hr_dev, int enable_flag) } } +static int hns_roce_bt_init(struct hns_roce_dev *hr_dev) +{ + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_v1_priv *priv; + int ret; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + + priv->bt_table.qpc_buf.buf = dma_alloc_coherent(dev, + HNS_ROCE_BT_RSV_BUF_SIZE, &priv->bt_table.qpc_buf.map, + GFP_KERNEL); + if (!priv->bt_table.qpc_buf.buf) + return -ENOMEM; + + priv->bt_table.mtpt_buf.buf = dma_alloc_coherent(dev, + HNS_ROCE_BT_RSV_BUF_SIZE, &priv->bt_table.mtpt_buf.map, + GFP_KERNEL); + if (!priv->bt_table.mtpt_buf.buf) { + ret = -ENOMEM; + goto err_failed_alloc_mtpt_buf; + } + + priv->bt_table.cqc_buf.buf = dma_alloc_coherent(dev, + HNS_ROCE_BT_RSV_BUF_SIZE, &priv->bt_table.cqc_buf.map, + GFP_KERNEL); + if (!priv->bt_table.cqc_buf.buf) { + ret = -ENOMEM; + goto err_failed_alloc_cqc_buf; + } + + return 0; + +err_failed_alloc_cqc_buf: + dma_free_coherent(dev, HNS_ROCE_BT_RSV_BUF_SIZE, + priv->bt_table.mtpt_buf.buf, priv->bt_table.mtpt_buf.map); + +err_failed_alloc_mtpt_buf: + dma_free_coherent(dev, HNS_ROCE_BT_RSV_BUF_SIZE, + priv->bt_table.qpc_buf.buf, priv->bt_table.qpc_buf.map); + + return ret; +} + +static void hns_roce_bt_free(struct hns_roce_dev *hr_dev) +{ + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_v1_priv *priv; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + + dma_free_coherent(dev, HNS_ROCE_BT_RSV_BUF_SIZE, + priv->bt_table.cqc_buf.buf, priv->bt_table.cqc_buf.map); + + dma_free_coherent(dev, HNS_ROCE_BT_RSV_BUF_SIZE, + priv->bt_table.mtpt_buf.buf, priv->bt_table.mtpt_buf.map); + + dma_free_coherent(dev, HNS_ROCE_BT_RSV_BUF_SIZE, + priv->bt_table.qpc_buf.buf, priv->bt_table.qpc_buf.map); +} + /** * hns_roce_v1_reset - reset RoCE * @hr_dev: RoCE device struct pointer @@ -941,8 +1001,18 @@ int hns_roce_v1_init(struct hns_roce_dev *hr_dev) hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_UP); + ret = hns_roce_bt_init(hr_dev); + if (ret) { + dev_err(dev, "bt init failed!\n"); + goto error_failed_bt_init; + } + return 0; +error_failed_bt_init: + hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_DOWN); + hns_roce_raq_free(hr_dev); + error_failed_raq_init: hns_roce_db_free(hr_dev); return ret; @@ -950,6 +1020,7 @@ int hns_roce_v1_init(struct hns_roce_dev *hr_dev) void hns_roce_v1_exit(struct hns_roce_dev *hr_dev) { + hns_roce_bt_free(hr_dev); hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_DOWN); hns_roce_raq_free(hr_dev); hns_roce_db_free(hr_dev); @@ -1596,6 +1667,74 @@ int hns_roce_v1_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) return ret; } +int hns_roce_v1_clear_hem(struct hns_roce_dev *hr_dev, + struct hns_roce_hem_table *table, int obj) +{ + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_v1_priv *priv; + unsigned long end = 0, flags = 0; + uint32_t bt_cmd_val[2] = {0}; + void __iomem *bt_cmd; + u64 bt_ba = 0; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + + switch (table->type) { + case HEM_TYPE_QPC: + roce_set_field(bt_cmd_val[1], ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, + ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_QPC); + bt_ba = priv->bt_table.qpc_buf.map >> 12; + break; + case HEM_TYPE_MTPT: + roce_set_field(bt_cmd_val[1], ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, + ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_MTPT); + bt_ba = priv->bt_table.mtpt_buf.map >> 12; + break; + case HEM_TYPE_CQC: + roce_set_field(bt_cmd_val[1], ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, + ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_CQC); + bt_ba = priv->bt_table.cqc_buf.map >> 12; + break; + case HEM_TYPE_SRQC: + dev_dbg(dev, "HEM_TYPE_SRQC not support.\n"); + return -EINVAL; + default: + return 0; + } + roce_set_field(bt_cmd_val[1], ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_M, + ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_S, obj); + roce_set_bit(bt_cmd_val[1], ROCEE_BT_CMD_H_ROCEE_BT_CMD_S, 0); + roce_set_bit(bt_cmd_val[1], ROCEE_BT_CMD_H_ROCEE_BT_CMD_HW_SYNS_S, 1); + + spin_lock_irqsave(&hr_dev->bt_cmd_lock, flags); + + bt_cmd = hr_dev->reg_base + ROCEE_BT_CMD_H_REG; + + end = msecs_to_jiffies(HW_SYNC_TIMEOUT_MSECS) + jiffies; + while (1) { + if (readl(bt_cmd) >> BT_CMD_SYNC_SHIFT) { + if (!(time_before(jiffies, end))) { + dev_err(dev, "Write bt_cmd err,hw_sync is not zero.\n"); + spin_unlock_irqrestore(&hr_dev->bt_cmd_lock, + flags); + return -EBUSY; + } + } else { + break; + } + msleep(HW_SYNC_SLEEP_TIME_INTERVAL); + } + + bt_cmd_val[0] = (uint32_t)bt_ba; + roce_set_field(bt_cmd_val[1], ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_M, + ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_S, bt_ba >> 32); + hns_roce_write64_k(bt_cmd_val, hr_dev->reg_base + ROCEE_BT_CMD_L_REG); + + spin_unlock_irqrestore(&hr_dev->bt_cmd_lock, flags); + + return 0; +} + static int hns_roce_v1_qp_modify(struct hns_roce_dev *hr_dev, struct hns_roce_mtt *mtt, enum hns_roce_qp_state cur_state, @@ -2766,6 +2905,7 @@ struct hns_roce_hw hns_roce_hw_v1 = { .set_mtu = hns_roce_v1_set_mtu, .write_mtpt = hns_roce_v1_write_mtpt, .write_cqc = hns_roce_v1_write_cqc, + .clear_hem = hns_roce_v1_clear_hem, .modify_qp = hns_roce_v1_modify_qp, .query_qp = hns_roce_v1_query_qp, .destroy_qp = hns_roce_v1_destroy_qp, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h index 316b592b1636d..539b0a3b92b09 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h @@ -102,6 +102,8 @@ #define HNS_ROCE_V1_EXT_ODB_ALFUL \ (HNS_ROCE_V1_EXT_ODB_DEPTH - HNS_ROCE_V1_DB_RSVD) +#define HNS_ROCE_BT_RSV_BUF_SIZE (1 << 17) + #define HNS_ROCE_ODB_POLL_MODE 0 #define HNS_ROCE_SDB_NORMAL_MODE 0 @@ -971,9 +973,16 @@ struct hns_roce_db_table { struct hns_roce_ext_db *ext_db; }; +struct hns_roce_bt_table { + struct hns_roce_buf_list qpc_buf; + struct hns_roce_buf_list mtpt_buf; + struct hns_roce_buf_list cqc_buf; +}; + struct hns_roce_v1_priv { struct hns_roce_db_table db_table; struct hns_roce_raq_table raq_table; + struct hns_roce_bt_table bt_table; }; int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool dereset); -- GitLab From 1ca5b253adbf7da514475f24151fb700062795c0 Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Tue, 20 Sep 2016 17:07:00 +0100 Subject: [PATCH 0178/1167] IB/hns: Delete the sqp_start from the structure hns_roce_caps This patch deleted the sqp_start from the structure hns_roce_caps, and modified the calculation of the qp number. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 - drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 1 - drivers/infiniband/hw/hns/hns_roce_qp.c | 10 ++++------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 3058599d0404c..341731553a601 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -465,7 +465,6 @@ struct hns_roce_caps { u32 max_rq_desc_sz; /* 64 */ int max_qp_init_rdma; int max_qp_dest_rdma; - int sqp_start; int num_cqs; int max_cqes; int reserved_cqs; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index d767ebebd27e6..65c3192c2f00b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -936,7 +936,6 @@ void hns_roce_v1_profile(struct hns_roce_dev *hr_dev) caps->mtt_entry_sz = HNS_ROCE_V1_MTT_ENTRY_SIZE; caps->cq_entry_sz = HNS_ROCE_V1_CQE_ENTRY_SIZE; caps->page_size_cap = HNS_ROCE_V1_PAGE_SIZE_SUPPORT; - caps->sqp_start = 0; caps->reserved_lkey = 0; caps->reserved_pds = 0; caps->reserved_mrws = 1; diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 177f48f081ab8..dd1b2140d8dbd 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -38,7 +38,7 @@ #include "hns_roce_hem.h" #include "hns_roce_user.h" -#define SQP_NUM 12 +#define SQP_NUM (2 * HNS_ROCE_MAX_PORTS) void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type) { @@ -246,7 +246,7 @@ void hns_roce_release_range_qp(struct hns_roce_dev *hr_dev, int base_qpn, { struct hns_roce_qp_table *qp_table = &hr_dev->qp_table; - if (base_qpn < (hr_dev->caps.sqp_start + 2 * hr_dev->caps.num_ports)) + if (base_qpn < SQP_NUM) return; hns_roce_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt); @@ -608,8 +608,7 @@ struct ib_qp *hns_roce_create_qp(struct ib_pd *pd, hr_qp = &hr_sqp->hr_qp; hr_qp->port = init_attr->port_num - 1; hr_qp->phy_port = hr_dev->iboe.phy_port[hr_qp->port]; - hr_qp->ibqp.qp_num = hr_dev->caps.sqp_start + - HNS_ROCE_MAX_PORTS + + hr_qp->ibqp.qp_num = HNS_ROCE_MAX_PORTS + hr_dev->iboe.phy_port[hr_qp->port]; ret = hns_roce_create_qp_common(hr_dev, pd, init_attr, udata, @@ -825,8 +824,7 @@ int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev) /* A port include two SQP, six port total 12 */ ret = hns_roce_bitmap_init(&qp_table->bitmap, hr_dev->caps.num_qps, - hr_dev->caps.num_qps - 1, - hr_dev->caps.sqp_start + SQP_NUM, + hr_dev->caps.num_qps - 1, SQP_NUM, reserved_from_top); if (ret) { dev_err(&hr_dev->pdev->dev, "qp bitmap init failed!error=%d\n", -- GitLab From c4a193d3a84766ce01d2cfdf3afaf0252db1ddf4 Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Tue, 20 Sep 2016 17:07:01 +0100 Subject: [PATCH 0179/1167] IB/hns: Optimize code of aeq and ceq interrupt handle and fix the bug of qpn This patch optimized the codes of aeq and ceq interrupt handle and fixed the bug in the calculation of qpn. For the special qp(GSI or SMI), calculated the qp number according to physical port and the qpn reported in the event of async event queue. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_eq.c | 146 ++++++++++++------------ drivers/infiniband/hw/hns/hns_roce_eq.h | 4 + 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_eq.c b/drivers/infiniband/hw/hns/hns_roce_eq.c index 98af7fecf2f1e..21e21b03cfb52 100644 --- a/drivers/infiniband/hw/hns/hns_roce_eq.c +++ b/drivers/infiniband/hw/hns/hns_roce_eq.c @@ -66,9 +66,6 @@ static void hns_roce_wq_catas_err_handle(struct hns_roce_dev *hr_dev, { struct device *dev = &hr_dev->pdev->dev; - qpn = roce_get_field(aeqe->event.qp_event.qp, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S); dev_warn(dev, "Local Work Queue Catastrophic Error.\n"); switch (roce_get_field(aeqe->asyn, HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_M, HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_S)) { @@ -96,13 +93,6 @@ static void hns_roce_wq_catas_err_handle(struct hns_roce_dev *hr_dev, default: break; } - - hns_roce_qp_event(hr_dev, roce_get_field(aeqe->event.qp_event.qp, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S), - roce_get_field(aeqe->asyn, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S)); } static void hns_roce_local_wq_access_err_handle(struct hns_roce_dev *hr_dev, @@ -111,9 +101,6 @@ static void hns_roce_local_wq_access_err_handle(struct hns_roce_dev *hr_dev, { struct device *dev = &hr_dev->pdev->dev; - qpn = roce_get_field(aeqe->event.qp_event.qp, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S); dev_warn(dev, "Local Access Violation Work Queue Error.\n"); switch (roce_get_field(aeqe->asyn, HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_M, HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_S)) { @@ -141,13 +128,69 @@ static void hns_roce_local_wq_access_err_handle(struct hns_roce_dev *hr_dev, default: break; } +} + +static void hns_roce_qp_err_handle(struct hns_roce_dev *hr_dev, + struct hns_roce_aeqe *aeqe, + int event_type) +{ + struct device *dev = &hr_dev->pdev->dev; + int phy_port; + int qpn; + + qpn = roce_get_field(aeqe->event.qp_event.qp, + HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M, + HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S); + phy_port = roce_get_field(aeqe->event.qp_event.qp, + HNS_ROCE_AEQE_EVENT_QP_EVENT_PORT_NUM_M, + HNS_ROCE_AEQE_EVENT_QP_EVENT_PORT_NUM_S); + if (qpn <= 1) + qpn = HNS_ROCE_MAX_PORTS * qpn + phy_port; + + switch (event_type) { + case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR: + dev_warn(dev, "Invalid Req Local Work Queue Error.\n" + "QP %d, phy_port %d.\n", qpn, phy_port); + break; + case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR: + hns_roce_wq_catas_err_handle(hr_dev, aeqe, qpn); + break; + case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR: + hns_roce_local_wq_access_err_handle(hr_dev, aeqe, qpn); + break; + default: + break; + } + + hns_roce_qp_event(hr_dev, qpn, event_type); +} + +static void hns_roce_cq_err_handle(struct hns_roce_dev *hr_dev, + struct hns_roce_aeqe *aeqe, + int event_type) +{ + struct device *dev = &hr_dev->pdev->dev; + u32 cqn; + + cqn = le32_to_cpu(roce_get_field(aeqe->event.cq_event.cq, + HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M, + HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S)); + + switch (event_type) { + case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR: + dev_warn(dev, "CQ 0x%x access err.\n", cqn); + break; + case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW: + dev_warn(dev, "CQ 0x%x overflow\n", cqn); + break; + case HNS_ROCE_EVENT_TYPE_CQ_ID_INVALID: + dev_warn(dev, "CQ 0x%x ID invalid.\n", cqn); + break; + default: + break; + } - hns_roce_qp_event(hr_dev, roce_get_field(aeqe->event.qp_event.qp, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S), - roce_get_field(aeqe->asyn, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S)); + hns_roce_cq_event(hr_dev, cqn, event_type); } static void hns_roce_db_overflow_handle(struct hns_roce_dev *hr_dev, @@ -185,7 +228,7 @@ static int hns_roce_aeq_int(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq) struct device *dev = &hr_dev->pdev->dev; struct hns_roce_aeqe *aeqe; int aeqes_found = 0; - int qpn = 0; + int event_type; while ((aeqe = next_aeqe_sw(eq))) { dev_dbg(dev, "aeqe = %p, aeqe->asyn.event_type = 0x%lx\n", aeqe, @@ -195,9 +238,10 @@ static int hns_roce_aeq_int(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq) /* Memory barrier */ rmb(); - switch (roce_get_field(aeqe->asyn, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S)) { + event_type = roce_get_field(aeqe->asyn, + HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M, + HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S); + switch (event_type) { case HNS_ROCE_EVENT_TYPE_PATH_MIG: dev_warn(dev, "PATH MIG not supported\n"); break; @@ -211,23 +255,9 @@ static int hns_roce_aeq_int(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq) dev_warn(dev, "PATH MIG failed\n"); break; case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR: - dev_warn(dev, "qpn = 0x%lx\n", - roce_get_field(aeqe->event.qp_event.qp, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S)); - hns_roce_qp_event(hr_dev, - roce_get_field(aeqe->event.qp_event.qp, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M, - HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S), - roce_get_field(aeqe->asyn, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S)); - break; case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR: - hns_roce_wq_catas_err_handle(hr_dev, aeqe, qpn); - break; case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR: - hns_roce_local_wq_access_err_handle(hr_dev, aeqe, qpn); + hns_roce_qp_err_handle(hr_dev, aeqe, event_type); break; case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH: case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR: @@ -235,40 +265,9 @@ static int hns_roce_aeq_int(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq) dev_warn(dev, "SRQ not support!\n"); break; case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR: - dev_warn(dev, "CQ 0x%lx access err.\n", - roce_get_field(aeqe->event.cq_event.cq, - HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M, - HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S)); - hns_roce_cq_event(hr_dev, - le32_to_cpu(roce_get_field(aeqe->event.cq_event.cq, - HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M, - HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S)), - roce_get_field(aeqe->asyn, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S)); - break; case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW: - dev_warn(dev, "CQ 0x%lx overflow\n", - roce_get_field(aeqe->event.cq_event.cq, - HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M, - HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S)); - hns_roce_cq_event(hr_dev, - le32_to_cpu(roce_get_field(aeqe->event.cq_event.cq, - HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M, - HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S)), - roce_get_field(aeqe->asyn, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S)); - break; case HNS_ROCE_EVENT_TYPE_CQ_ID_INVALID: - dev_warn(dev, "CQ ID invalid.\n"); - hns_roce_cq_event(hr_dev, - le32_to_cpu(roce_get_field(aeqe->event.cq_event.cq, - HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M, - HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S)), - roce_get_field(aeqe->asyn, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S)); + hns_roce_cq_err_handle(hr_dev, aeqe, event_type); break; case HNS_ROCE_EVENT_TYPE_PORT_CHANGE: dev_warn(dev, "port change.\n"); @@ -290,11 +289,8 @@ static int hns_roce_aeq_int(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq) HNS_ROCE_AEQE_EVENT_CE_EVENT_CEQE_CEQN_S)); break; default: - dev_warn(dev, "Unhandled event 0x%lx on EQ %d at index %u\n", - roce_get_field(aeqe->asyn, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M, - HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S), - eq->eqn, eq->cons_index); + dev_warn(dev, "Unhandled event %d on EQ %d at index %u\n", + event_type, eq->eqn, eq->cons_index); break; }; diff --git a/drivers/infiniband/hw/hns/hns_roce_eq.h b/drivers/infiniband/hw/hns/hns_roce_eq.h index fe4388191a3c2..c6d212d12e033 100644 --- a/drivers/infiniband/hw/hns/hns_roce_eq.h +++ b/drivers/infiniband/hw/hns/hns_roce_eq.h @@ -107,6 +107,10 @@ struct hns_roce_aeqe { #define HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M \ (((1UL << 24) - 1) << HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S) +#define HNS_ROCE_AEQE_EVENT_QP_EVENT_PORT_NUM_S 25 +#define HNS_ROCE_AEQE_EVENT_QP_EVENT_PORT_NUM_M \ + (((1UL << 3) - 1) << HNS_ROCE_AEQE_EVENT_QP_EVENT_PORT_NUM_S) + #define HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S 0 #define HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M \ (((1UL << 16) - 1) << HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S) -- GitLab From 49fdf6bb0a172a8fe631d89a421857336efc4382 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:07:02 +0100 Subject: [PATCH 0180/1167] IB/hns: Modify the init of iboe lock This lock will be used in query port interface, and will be called while IB device was registered to OFED framework/IB Core. So, the lock of iboe must be initiated before IB device was registered. Signed-off-by: Lijun Ou Signed-off-by: Dongdong Huang(Donald) Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 4b44998a039ea..764e35a54457e 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -602,6 +602,7 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) struct device *dev = &hr_dev->pdev->dev; iboe = &hr_dev->iboe; + spin_lock_init(&iboe->lock); ib_dev = &hr_dev->ib_dev; strlcpy(ib_dev->name, "hisi_%d", IB_DEVICE_NAME_MAX); @@ -686,8 +687,6 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) goto error_failed_setup_mtu_gids; } - spin_lock_init(&iboe->lock); - iboe->nb.notifier_call = hns_roce_netdev_event; ret = register_netdevice_notifier(&iboe->nb); if (ret) { -- GitLab From 1cd11064da4b0bca992ca0f9594adbf53df25879 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:07:03 +0100 Subject: [PATCH 0181/1167] IB/hns: Fix bug of memory leakage for registering user mr While the page size attribute of umem is illegal, we should release umem that get by ib_umem_get interface. Also, we should return a non-zero value while pbl number is wrong. Signed-off-by: Lijun Ou Signed-off-by: Dongdong Huang(Donald) Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_mr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index 59f5e2be046b3..fb87883ead340 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -564,11 +564,14 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (mr->umem->page_size != HNS_ROCE_HEM_PAGE_SIZE) { dev_err(dev, "Just support 4K page size but is 0x%x now!\n", mr->umem->page_size); + ret = -EINVAL; + goto err_umem; } if (n > HNS_ROCE_MAX_MTPT_PBL_NUM) { dev_err(dev, " MR len %lld err. MR is limited to 4G at most!\n", length); + ret = -EINVAL; goto err_umem; } -- GitLab From 07182fa77b3a64962aca12e8c0006646316bd26d Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:07:04 +0100 Subject: [PATCH 0182/1167] IB/hns: Return bad wr while post send failed While post failed, hns roce should return the wr failed to user. We omitted this while qp type is wrong and fixed it. Signed-off-by: Lijun Ou Signed-off-by: Dongdong Huang(Donald) Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 65c3192c2f00b..1205d1af4db02 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -73,8 +73,14 @@ int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, u32 ind = 0; int ret = 0; - spin_lock_irqsave(&qp->sq.lock, flags); + if (unlikely(ibqp->qp_type != IB_QPT_GSI && + ibqp->qp_type != IB_QPT_RC)) { + dev_err(dev, "un-supported QP type\n"); + *bad_wr = NULL; + return -EOPNOTSUPP; + } + spin_lock_irqsave(&qp->sq.lock, flags); ind = qp->sq_next_wqe; for (nreq = 0; wr; ++nreq, wr = wr->next) { if (hns_roce_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) { @@ -263,9 +269,6 @@ int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, HNS_ROCE_WQE_SGE_NUM_BIT); } ind++; - } else { - dev_dbg(dev, "unSupported QP type\n"); - break; } } -- GitLab From c6c3bfea82be60c3d60144b980ea25f1252a6eb5 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:07:05 +0100 Subject: [PATCH 0183/1167] IB/hns: The Ack timeout need a lower limit value The Ack timeout of qpc need a lower limit value,otherwise the read performance will be very lower. Signed-off-by: Lijun Ou Signed-off-by: Dongdong Huang(Donald) Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 1205d1af4db02..5110a18642846 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -2410,10 +2410,19 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, QP_CONTEXT_QPC_BYTES_156_RETRY_COUNT_INIT_M, QP_CONTEXT_QPC_BYTES_156_RETRY_COUNT_INIT_S, attr->retry_cnt); - roce_set_field(context->qpc_bytes_156, - QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_M, - QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_S, - attr->timeout); + if (attr->timeout < 0x12) { + dev_info(dev, "ack timeout value(0x%x) must bigger than 0x12.\n", + attr->timeout); + roce_set_field(context->qpc_bytes_156, + QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_M, + QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_S, + 0x12); + } else { + roce_set_field(context->qpc_bytes_156, + QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_M, + QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_S, + attr->timeout); + } roce_set_field(context->qpc_bytes_156, QP_CONTEXT_QPC_BYTES_156_RNR_RETRY_COUNT_INIT_M, QP_CONTEXT_QPC_BYTES_156_RNR_RETRY_COUNT_INIT_S, -- GitLab From 7c7a4ea145a5dc914402678d0299a81c3f5b38b6 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:07:06 +0100 Subject: [PATCH 0184/1167] IB/hns: Some items of qpc need to take user param Some items of qpc need to take user param when modified qp state. Signed-off-by: Lijun Ou Signed-off-by: Dongdong Huang(Donald) Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 5110a18642846..bc06004ae67dd 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -2396,10 +2396,12 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, QP_CONTEXT_QPC_BYTES_148_CHECK_FLAG_S, 0); roce_set_field(context->qpc_bytes_148, QP_CONTEXT_QPC_BYTES_148_RETRY_COUNT_M, - QP_CONTEXT_QPC_BYTES_148_RETRY_COUNT_S, 0); + QP_CONTEXT_QPC_BYTES_148_RETRY_COUNT_S, + attr->retry_cnt); roce_set_field(context->qpc_bytes_148, QP_CONTEXT_QPC_BYTES_148_RNR_RETRY_COUNT_M, - QP_CONTEXT_QPC_BYTES_148_RNR_RETRY_COUNT_S, 0); + QP_CONTEXT_QPC_BYTES_148_RNR_RETRY_COUNT_S, + attr->rnr_retry); roce_set_field(context->qpc_bytes_148, QP_CONTEXT_QPC_BYTES_148_LSN_M, QP_CONTEXT_QPC_BYTES_148_LSN_S, 0x100); -- GitLab From cb814642e7e3e67f6a7c24b14531e95ccdb7c3cc Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:07:07 +0100 Subject: [PATCH 0185/1167] IB/hns: Validate mtu when modified qp The mtu should be validated when modify qp,so we check it. Signed-off-by: Lijun Ou Signed-off-by: Peter Chen Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_qp.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index dd1b2140d8dbd..6a38909929cdb 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -32,6 +32,7 @@ */ #include +#include #include #include "hns_roce_common.h" #include "hns_roce_device.h" @@ -657,6 +658,7 @@ int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, struct device *dev = &hr_dev->pdev->dev; int ret = -EINVAL; int p; + enum ib_mtu active_mtu; mutex_lock(&hr_qp->mutex); @@ -687,6 +689,19 @@ int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, } } + if (attr_mask & IB_QP_PATH_MTU) { + p = attr_mask & IB_QP_PORT ? (attr->port_num - 1) : hr_qp->port; + active_mtu = iboe_get_mtu(hr_dev->iboe.netdevs[p]->mtu); + + if (attr->path_mtu > IB_MTU_2048 || + attr->path_mtu < IB_MTU_256 || + attr->path_mtu > active_mtu) { + dev_err(dev, "attr path_mtu(%d)invalid while modify qp", + attr->path_mtu); + goto out; + } + } + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && attr->max_rd_atomic > hr_dev->caps.max_qp_init_rdma) { dev_err(dev, "attr max_rd_atomic invalid.attr->max_rd_atomic=%d\n", -- GitLab From 24f0c9c0ff0955c5849dfb40403a21c8c11b9d2a Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:07:08 +0100 Subject: [PATCH 0186/1167] IB/hns: Cq has not been freed Cq has not been freed when fail to ib_copy_to_udata, so need to free it. Signed-off-by: Lijun Ou Signed-off-by: Peter Chen Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_cq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index 3095f06099e68..097365932b096 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -357,12 +357,15 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev, if (context) { if (ib_copy_to_udata(udata, &hr_cq->cqn, sizeof(u64))) { ret = -EFAULT; - goto err_mtt; + goto err_cqc; } } return &hr_cq->ib_cq; +err_cqc: + hns_roce_free_cq(hr_dev, hr_cq); + err_mtt: hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt); if (context) -- GitLab From 1fad5fab782c18a90865f61bff1bde3a0dba1678 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:07:09 +0100 Subject: [PATCH 0187/1167] IB/hns: Update the rq head when modify qp state The rq head in qpc was zero will miss the rq wqes which have be sent, so here we should take the real value. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index bc06004ae67dd..2070e9ee0474d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -2248,7 +2248,8 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, roce_set_field(context->qpc_bytes_68, QP_CONTEXT_QPC_BYTES_68_RQ_HEAD_M, - QP_CONTEXT_QPC_BYTES_68_RQ_HEAD_S, 0); + QP_CONTEXT_QPC_BYTES_68_RQ_HEAD_S, + hr_qp->rq.head); roce_set_field(context->qpc_bytes_68, QP_CONTEXT_QPC_BYTES_68_RQ_CUR_INDEX_M, QP_CONTEXT_QPC_BYTES_68_RQ_CUR_INDEX_S, 0); -- GitLab From 3e413872b1832e1cf6de037ec01b2c4c992f0136 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:07:10 +0100 Subject: [PATCH 0188/1167] IB/hns: Fix the bug when platform_get_resource() exec fail This patch mainly fixes the bug with platform_get_resource(). It should return NULL when platform_get_resource() exec fail. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_pd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c index 0cd6132b75f04..05db7d59812a6 100644 --- a/drivers/infiniband/hw/hns/hns_roce_pd.c +++ b/drivers/infiniband/hw/hns/hns_roce_pd.c @@ -110,6 +110,10 @@ int hns_roce_uar_alloc(struct hns_roce_dev *hr_dev, struct hns_roce_uar *uar) (hr_dev->caps.phy_num_uars - 1) + 1; res = platform_get_resource(hr_dev->pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&hr_dev->pdev->dev, "memory resource not found!\n"); + return -EINVAL; + } uar->pfn = ((res->start) >> PAGE_SHIFT) + uar->index; return 0; -- GitLab From deb17f6f826708e46af538048b2af508215c3dc5 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 20 Sep 2016 17:07:11 +0100 Subject: [PATCH 0189/1167] IB/hns: Delete the redundant lines in hns_roce_v1_m_qp() It doesn't need to assign for the filed of qp state in qpc separately when qp happen to migrate state which supported in RoCE engine v1. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 2070e9ee0474d..d52eeda2ef3ce 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -2387,11 +2387,6 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, roce_set_bit(context->qpc_bytes_140, QP_CONTEXT_QPC_BYTES_140_RNR_RETRY_FLG_S, 0); - roce_set_field(context->qpc_bytes_144, - QP_CONTEXT_QPC_BYTES_144_QP_STATE_M, - QP_CONTEXT_QPC_BYTES_144_QP_STATE_S, - attr->qp_state); - roce_set_field(context->qpc_bytes_148, QP_CONTEXT_QPC_BYTES_148_CHECK_FLAG_M, QP_CONTEXT_QPC_BYTES_148_CHECK_FLAG_S, 0); @@ -2498,21 +2493,15 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, QP_CONTEXT_QPC_BYTES_188_TX_RETRY_CUR_INDEX_M, QP_CONTEXT_QPC_BYTES_188_TX_RETRY_CUR_INDEX_S, 0); - } else if ((cur_state == IB_QPS_INIT && new_state == IB_QPS_RESET) || + } else if (!((cur_state == IB_QPS_INIT && new_state == IB_QPS_RESET) || (cur_state == IB_QPS_INIT && new_state == IB_QPS_ERR) || (cur_state == IB_QPS_RTR && new_state == IB_QPS_RESET) || (cur_state == IB_QPS_RTR && new_state == IB_QPS_ERR) || (cur_state == IB_QPS_RTS && new_state == IB_QPS_RESET) || (cur_state == IB_QPS_RTS && new_state == IB_QPS_ERR) || (cur_state == IB_QPS_ERR && new_state == IB_QPS_RESET) || - (cur_state == IB_QPS_ERR && new_state == IB_QPS_ERR)) { - roce_set_field(context->qpc_bytes_144, - QP_CONTEXT_QPC_BYTES_144_QP_STATE_M, - QP_CONTEXT_QPC_BYTES_144_QP_STATE_S, - attr->qp_state); - - } else { - dev_err(dev, "not support this modify\n"); + (cur_state == IB_QPS_ERR && new_state == IB_QPS_ERR))) { + dev_err(dev, "not support this status migration\n"); goto out; } -- GitLab From 1bdab400af5954932714e68ab3df0187a92916cb Mon Sep 17 00:00:00 2001 From: Salil Date: Tue, 20 Sep 2016 17:07:12 +0100 Subject: [PATCH 0190/1167] IB/hns: Fix for removal of redundant code This patch removes the redundant code lines present in the functions get_send_wqe() and get_recv_wqe(). This also fixes the error in calculating the SQ WQE. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 3 ++- drivers/infiniband/hw/hns/hns_roce_qp.c | 18 ------------------ 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index d52eeda2ef3ce..71232e5fabf6a 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -1552,7 +1552,8 @@ static int hns_roce_v1_poll_one(struct hns_roce_cq *hr_cq, /* SQ conrespond to CQE */ sq_wqe = get_send_wqe(*cur_qp, roce_get_field(cqe->cqe_byte_4, CQE_BYTE_4_WQE_INDEX_M, - CQE_BYTE_4_WQE_INDEX_S)); + CQE_BYTE_4_WQE_INDEX_S)& + ((*cur_qp)->sq.wqe_cnt-1)); switch (sq_wqe->flag & HNS_ROCE_WQE_OPCODE_MASK) { case HNS_ROCE_WQE_OPCODE_SEND: wc->opcode = IB_WC_SEND; diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 6a38909929cdb..e86dd8d067776 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -784,29 +784,11 @@ static void *get_wqe(struct hns_roce_qp *hr_qp, int offset) void *get_recv_wqe(struct hns_roce_qp *hr_qp, int n) { - struct ib_qp *ibqp = &hr_qp->ibqp; - struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); - - if ((n < 0) || (n > hr_qp->rq.wqe_cnt)) { - dev_err(&hr_dev->pdev->dev, "rq wqe index:%d,rq wqe cnt:%d\r\n", - n, hr_qp->rq.wqe_cnt); - return NULL; - } - return get_wqe(hr_qp, hr_qp->rq.offset + (n << hr_qp->rq.wqe_shift)); } void *get_send_wqe(struct hns_roce_qp *hr_qp, int n) { - struct ib_qp *ibqp = &hr_qp->ibqp; - struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); - - if ((n < 0) || (n > hr_qp->sq.wqe_cnt)) { - dev_err(&hr_dev->pdev->dev, "sq wqe index:%d,sq wqe cnt:%d\r\n", - n, hr_qp->sq.wqe_cnt); - return NULL; - } - return get_wqe(hr_qp, hr_qp->sq.offset + (n << hr_qp->sq.wqe_shift)); } -- GitLab From 2fe1d55134fce05c17ea118a2e37a4af771887bc Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Thu, 22 Sep 2016 17:24:20 -0700 Subject: [PATCH 0191/1167] Btrfs: fix free space tree bitmaps on big-endian systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In convert_free_space_to_{bitmaps,extents}(), we buffer the free space bitmaps in memory and copy them directly to/from the extent buffers with {read,write}_extent_buffer(). The extent buffer bitmap helpers use byte granularity, which is equivalent to a little-endian bitmap. This means that on big-endian systems, the in-memory bitmaps will be written to disk byte-swapped. To fix this, use byte-granularity for the bitmaps in memory. Fixes: a5ed91828518 ("Btrfs: implement the free space B-tree") Cc: stable@vger.kernel.org # 4.5+ Tested-by: Holger Hoffstätte Tested-by: Chandan Rajendra Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 64 +++++++++++++++++++++++++++----------- fs/btrfs/extent_io.h | 22 +++++++++++++ fs/btrfs/free-space-tree.c | 17 +++++----- 3 files changed, 76 insertions(+), 27 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 44fe66b53c8b4..c3ec30dea9a53 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -5524,17 +5524,45 @@ void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src, } } -/* - * The extent buffer bitmap operations are done with byte granularity because - * bitmap items are not guaranteed to be aligned to a word and therefore a - * single word in a bitmap may straddle two pages in the extent buffer. - */ -#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE) -#define BYTE_MASK ((1 << BITS_PER_BYTE) - 1) -#define BITMAP_FIRST_BYTE_MASK(start) \ - ((BYTE_MASK << ((start) & (BITS_PER_BYTE - 1))) & BYTE_MASK) -#define BITMAP_LAST_BYTE_MASK(nbits) \ - (BYTE_MASK >> (-(nbits) & (BITS_PER_BYTE - 1))) +void le_bitmap_set(u8 *map, unsigned int start, int len) +{ + u8 *p = map + BIT_BYTE(start); + const unsigned int size = start + len; + int bits_to_set = BITS_PER_BYTE - (start % BITS_PER_BYTE); + u8 mask_to_set = BITMAP_FIRST_BYTE_MASK(start); + + while (len - bits_to_set >= 0) { + *p |= mask_to_set; + len -= bits_to_set; + bits_to_set = BITS_PER_BYTE; + mask_to_set = ~(u8)0; + p++; + } + if (len) { + mask_to_set &= BITMAP_LAST_BYTE_MASK(size); + *p |= mask_to_set; + } +} + +void le_bitmap_clear(u8 *map, unsigned int start, int len) +{ + u8 *p = map + BIT_BYTE(start); + const unsigned int size = start + len; + int bits_to_clear = BITS_PER_BYTE - (start % BITS_PER_BYTE); + u8 mask_to_clear = BITMAP_FIRST_BYTE_MASK(start); + + while (len - bits_to_clear >= 0) { + *p &= ~mask_to_clear; + len -= bits_to_clear; + bits_to_clear = BITS_PER_BYTE; + mask_to_clear = ~(u8)0; + p++; + } + if (len) { + mask_to_clear &= BITMAP_LAST_BYTE_MASK(size); + *p &= ~mask_to_clear; + } +} /* * eb_bitmap_offset() - calculate the page and offset of the byte containing the @@ -5578,7 +5606,7 @@ static inline void eb_bitmap_offset(struct extent_buffer *eb, int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start, unsigned long nr) { - char *kaddr; + u8 *kaddr; struct page *page; unsigned long i; size_t offset; @@ -5600,13 +5628,13 @@ int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start, void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start, unsigned long pos, unsigned long len) { - char *kaddr; + u8 *kaddr; struct page *page; unsigned long i; size_t offset; const unsigned int size = pos + len; int bits_to_set = BITS_PER_BYTE - (pos % BITS_PER_BYTE); - unsigned int mask_to_set = BITMAP_FIRST_BYTE_MASK(pos); + u8 mask_to_set = BITMAP_FIRST_BYTE_MASK(pos); eb_bitmap_offset(eb, start, pos, &i, &offset); page = eb->pages[i]; @@ -5617,7 +5645,7 @@ void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start, kaddr[offset] |= mask_to_set; len -= bits_to_set; bits_to_set = BITS_PER_BYTE; - mask_to_set = ~0U; + mask_to_set = ~(u8)0; if (++offset >= PAGE_SIZE && len > 0) { offset = 0; page = eb->pages[++i]; @@ -5642,13 +5670,13 @@ void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start, void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start, unsigned long pos, unsigned long len) { - char *kaddr; + u8 *kaddr; struct page *page; unsigned long i; size_t offset; const unsigned int size = pos + len; int bits_to_clear = BITS_PER_BYTE - (pos % BITS_PER_BYTE); - unsigned int mask_to_clear = BITMAP_FIRST_BYTE_MASK(pos); + u8 mask_to_clear = BITMAP_FIRST_BYTE_MASK(pos); eb_bitmap_offset(eb, start, pos, &i, &offset); page = eb->pages[i]; @@ -5659,7 +5687,7 @@ void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start, kaddr[offset] &= ~mask_to_clear; len -= bits_to_clear; bits_to_clear = BITS_PER_BYTE; - mask_to_clear = ~0U; + mask_to_clear = ~(u8)0; if (++offset >= PAGE_SIZE && len > 0) { offset = 0; page = eb->pages[++i]; diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 28cd88fccc7ea..1cf4e4226fc86 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -59,6 +59,28 @@ */ #define EXTENT_PAGE_PRIVATE 1 +/* + * The extent buffer bitmap operations are done with byte granularity instead of + * word granularity for two reasons: + * 1. The bitmaps must be little-endian on disk. + * 2. Bitmap items are not guaranteed to be aligned to a word and therefore a + * single word in a bitmap may straddle two pages in the extent buffer. + */ +#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE) +#define BYTE_MASK ((1 << BITS_PER_BYTE) - 1) +#define BITMAP_FIRST_BYTE_MASK(start) \ + ((BYTE_MASK << ((start) & (BITS_PER_BYTE - 1))) & BYTE_MASK) +#define BITMAP_LAST_BYTE_MASK(nbits) \ + (BYTE_MASK >> (-(nbits) & (BITS_PER_BYTE - 1))) + +static inline int le_test_bit(int nr, const u8 *addr) +{ + return 1U & (addr[BIT_BYTE(nr)] >> (nr & (BITS_PER_BYTE-1))); +} + +extern void le_bitmap_set(u8 *map, unsigned int start, int len); +extern void le_bitmap_clear(u8 *map, unsigned int start, int len); + struct extent_state; struct btrfs_root; struct btrfs_io_bio; diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c index 87e7e3d3e6760..8fd85bfbe2dab 100644 --- a/fs/btrfs/free-space-tree.c +++ b/fs/btrfs/free-space-tree.c @@ -151,7 +151,7 @@ static inline u32 free_space_bitmap_size(u64 size, u32 sectorsize) return DIV_ROUND_UP((u32)div_u64(size, sectorsize), BITS_PER_BYTE); } -static unsigned long *alloc_bitmap(u32 bitmap_size) +static u8 *alloc_bitmap(u32 bitmap_size) { void *mem; @@ -180,8 +180,7 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, struct btrfs_free_space_info *info; struct btrfs_key key, found_key; struct extent_buffer *leaf; - unsigned long *bitmap; - char *bitmap_cursor; + u8 *bitmap, *bitmap_cursor; u64 start, end; u64 bitmap_range, i; u32 bitmap_size, flags, expected_extent_count; @@ -231,7 +230,7 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, block_group->sectorsize); last = div_u64(found_key.objectid + found_key.offset - start, block_group->sectorsize); - bitmap_set(bitmap, first, last - first); + le_bitmap_set(bitmap, first, last - first); extent_count++; nr++; @@ -269,7 +268,7 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, goto out; } - bitmap_cursor = (char *)bitmap; + bitmap_cursor = bitmap; bitmap_range = block_group->sectorsize * BTRFS_FREE_SPACE_BITMAP_BITS; i = start; while (i < end) { @@ -318,7 +317,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, struct btrfs_free_space_info *info; struct btrfs_key key, found_key; struct extent_buffer *leaf; - unsigned long *bitmap; + u8 *bitmap; u64 start, end; /* Initialize to silence GCC. */ u64 extent_start = 0; @@ -362,7 +361,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, break; } else if (found_key.type == BTRFS_FREE_SPACE_BITMAP_KEY) { unsigned long ptr; - char *bitmap_cursor; + u8 *bitmap_cursor; u32 bitmap_pos, data_size; ASSERT(found_key.objectid >= start); @@ -372,7 +371,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, bitmap_pos = div_u64(found_key.objectid - start, block_group->sectorsize * BITS_PER_BYTE); - bitmap_cursor = ((char *)bitmap) + bitmap_pos; + bitmap_cursor = bitmap + bitmap_pos; data_size = free_space_bitmap_size(found_key.offset, block_group->sectorsize); @@ -409,7 +408,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, offset = start; bitnr = 0; while (offset < end) { - bit = !!test_bit(bitnr, bitmap); + bit = !!le_test_bit(bitnr, bitmap); if (prev_bit == 0 && bit == 1) { extent_start = offset; } else if (prev_bit == 1 && bit == 0) { -- GitLab From f8d468a15c22b954b379aa0c74914d5068448fb1 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Thu, 22 Sep 2016 17:24:21 -0700 Subject: [PATCH 0192/1167] Btrfs: fix mount -o clear_cache,space_cache=v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We moved the code for creating the free space tree the first time that it's enabled, but didn't move the clearing code along with it. This breaks my (undocumented) intention that `mount -o clear_cache,space_cache=v2` would clear the free space tree and then recreate it. Fixes: 511711af91f2 ("btrfs: don't run delayed references while we are creating the free space tree") Cc: stable@vger.kernel.org # 4.5+ Tested-by: Holger Hoffstätte Tested-by: Chandan Rajendra Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 54bc8c7c6bcd3..c0bfc6ce5f06e 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3129,6 +3129,18 @@ int open_ctree(struct super_block *sb, if (sb->s_flags & MS_RDONLY) return 0; + if (btrfs_test_opt(fs_info, CLEAR_CACHE) && + btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { + btrfs_info(fs_info, "clearing free space tree"); + ret = btrfs_clear_free_space_tree(fs_info); + if (ret) { + btrfs_warn(fs_info, + "failed to clear free space tree: %d", ret); + close_ctree(tree_root); + return ret; + } + } + if (btrfs_test_opt(tree_root->fs_info, FREE_SPACE_TREE) && !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { btrfs_info(fs_info, "creating free space tree"); @@ -3166,18 +3178,6 @@ int open_ctree(struct super_block *sb, btrfs_qgroup_rescan_resume(fs_info); - if (btrfs_test_opt(tree_root->fs_info, CLEAR_CACHE) && - btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { - btrfs_info(fs_info, "clearing free space tree"); - ret = btrfs_clear_free_space_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, - "failed to clear free space tree: %d", ret); - close_ctree(tree_root); - return ret; - } - } - if (!fs_info->uuid_root) { btrfs_info(fs_info, "creating UUID tree"); ret = btrfs_create_uuid_tree(fs_info); -- GitLab From 6675df311db87aa2107a04ef97e19420953cbace Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Thu, 22 Sep 2016 17:24:22 -0700 Subject: [PATCH 0193/1167] Btrfs: catch invalid free space trees MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two separate issues that can lead to corrupted free space trees. 1. The free space tree bitmaps had an endianness issue on big-endian systems which is fixed by an earlier patch in this series. 2. btrfs-progs before v4.7.3 modified filesystems without updating the free space tree. To catch both of these issues at once, we need to force the free space tree to be rebuilt. To do so, add a FREE_SPACE_TREE_VALID compat_ro bit. If the bit isn't set, we know that it was either produced by a broken big-endian kernel or may have been corrupted by btrfs-progs. This also provides us with a way to add rudimentary read-write support for the free space tree to btrfs-progs: it can just clear this bit and have the kernel rebuild the free space tree. Cc: stable@vger.kernel.org # 4.5+ Tested-by: Holger Hoffstätte Tested-by: Chandan Rajendra Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 3 ++- fs/btrfs/disk-io.c | 9 +++++++++ fs/btrfs/free-space-tree.c | 2 ++ include/uapi/linux/btrfs.h | 12 +++++++++++- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 33fe035511055..791e47ce9d275 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -251,7 +251,8 @@ struct btrfs_super_block { #define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL #define BTRFS_FEATURE_COMPAT_RO_SUPP \ - (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE) + (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE | \ + BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID) #define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL #define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c0bfc6ce5f06e..3dede6d53badb 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2566,6 +2566,7 @@ int open_ctree(struct super_block *sb, int num_backups_tried = 0; int backup_index = 0; int max_active; + int clear_free_space_tree = 0; tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL); chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL); @@ -3131,6 +3132,14 @@ int open_ctree(struct super_block *sb, if (btrfs_test_opt(fs_info, CLEAR_CACHE) && btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { + clear_free_space_tree = 1; + } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) && + !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) { + btrfs_warn(fs_info, "free space tree is invalid"); + clear_free_space_tree = 1; + } + + if (clear_free_space_tree) { btrfs_info(fs_info, "clearing free space tree"); ret = btrfs_clear_free_space_tree(fs_info); if (ret) { diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c index 8fd85bfbe2dab..ea605ffd0e030 100644 --- a/fs/btrfs/free-space-tree.c +++ b/fs/btrfs/free-space-tree.c @@ -1182,6 +1182,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) } btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE); + btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); fs_info->creating_free_space_tree = 0; ret = btrfs_commit_transaction(trans, tree_root); @@ -1250,6 +1251,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) return PTR_ERR(trans); btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); + btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); fs_info->free_space_root = NULL; ret = clear_free_space_tree(trans, free_space_root); diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index ac5eacd3055b5..db4c253f8011b 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -239,7 +239,17 @@ struct btrfs_ioctl_fs_info_args { * Used by: * struct btrfs_ioctl_feature_flags */ -#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0) +#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0) +/* + * Older kernels (< 4.9) on big-endian systems produced broken free space tree + * bitmaps, and btrfs-progs also used to corrupt the free space tree (versions + * < 4.7.3). If this bit is clear, then the free space tree cannot be trusted. + * btrfs-progs can also intentionally clear this bit to ask the kernel to + * rebuild the free space tree, however this might not work on older kernels + * that do not know about this bit. If not sure, clear the cache manually on + * first mount when booting older kernel versions. + */ +#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID (1ULL << 1) #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) -- GitLab From 9426ce754fab0f02a45b61402119c57de446ffa3 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Thu, 22 Sep 2016 17:24:23 -0700 Subject: [PATCH 0194/1167] Btrfs: fix extent buffer bitmap tests on big-endian systems The in-memory bitmap code manipulates words and is therefore sensitive to endianness, while the extent buffer bitmap code addresses bytes and is byte-order agnostic. Because the byte addressing of the extent buffer bitmaps is equivalent to a little-endian in-memory bitmap, the extent buffer bitmap tests fail on big-endian systems. 34b3e6c92af1 ("Btrfs: self-tests: Fix extent buffer bitmap test fail on BE system") worked around another endianness bug in the tests but missed this one because ed9e4afdb055 ("Btrfs: self-tests: Execute page straddling test only when nodesize < PAGE_SIZE") disables this part of the test on ppc64. That change lost the original meaning of the test, however. We really want to test that an equivalent series of operations using the in-memory bitmap API and the extent buffer bitmap API produces equivalent results. To fix this, don't use memcmp_extent_buffer() or write_extent_buffer(); do everything bit-by-bit. Reported-by: Anatoly Pugachev Tested-by: Anatoly Pugachev Tested-by: Feifei Xu Tested-by: Chandan Rajendra Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/tests/extent-io-tests.c | 87 +++++++++++++++++++------------- 1 file changed, 51 insertions(+), 36 deletions(-) diff --git a/fs/btrfs/tests/extent-io-tests.c b/fs/btrfs/tests/extent-io-tests.c index d19ab0317283c..caad80bb9bd01 100644 --- a/fs/btrfs/tests/extent-io-tests.c +++ b/fs/btrfs/tests/extent-io-tests.c @@ -273,20 +273,37 @@ static int test_find_delalloc(u32 sectorsize) return ret; } -/** - * test_bit_in_byte - Determine whether a bit is set in a byte - * @nr: bit number to test - * @addr: Address to start counting from - */ -static inline int test_bit_in_byte(int nr, const u8 *addr) +static int check_eb_bitmap(unsigned long *bitmap, struct extent_buffer *eb, + unsigned long len) { - return 1UL & (addr[nr / BITS_PER_BYTE] >> (nr & (BITS_PER_BYTE - 1))); + unsigned long i; + + for (i = 0; i < len * BITS_PER_BYTE; i++) { + int bit, bit1; + + bit = !!test_bit(i, bitmap); + bit1 = !!extent_buffer_test_bit(eb, 0, i); + if (bit1 != bit) { + test_msg("Bits do not match\n"); + return -EINVAL; + } + + bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE, + i % BITS_PER_BYTE); + if (bit1 != bit) { + test_msg("Offset bits do not match\n"); + return -EINVAL; + } + } + return 0; } static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, unsigned long len) { - unsigned long i, x; + unsigned long i, j; + u32 x; + int ret; memset(bitmap, 0, len); memset_extent_buffer(eb, 0, 0, len); @@ -297,16 +314,18 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, bitmap_set(bitmap, 0, len * BITS_PER_BYTE); extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE); - if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) { + ret = check_eb_bitmap(bitmap, eb, len); + if (ret) { test_msg("Setting all bits failed\n"); - return -EINVAL; + return ret; } bitmap_clear(bitmap, 0, len * BITS_PER_BYTE); extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE); - if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) { + ret = check_eb_bitmap(bitmap, eb, len); + if (ret) { test_msg("Clearing all bits failed\n"); - return -EINVAL; + return ret; } /* Straddling pages test */ @@ -316,9 +335,10 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, sizeof(long) * BITS_PER_BYTE); extent_buffer_bitmap_set(eb, PAGE_SIZE - sizeof(long) / 2, 0, sizeof(long) * BITS_PER_BYTE); - if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) { + ret = check_eb_bitmap(bitmap, eb, len); + if (ret) { test_msg("Setting straddling pages failed\n"); - return -EINVAL; + return ret; } bitmap_set(bitmap, 0, len * BITS_PER_BYTE); @@ -328,9 +348,10 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE); extent_buffer_bitmap_clear(eb, PAGE_SIZE - sizeof(long) / 2, 0, sizeof(long) * BITS_PER_BYTE); - if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) { + ret = check_eb_bitmap(bitmap, eb, len); + if (ret) { test_msg("Clearing straddling pages failed\n"); - return -EINVAL; + return ret; } } @@ -339,28 +360,22 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, * something repetitive that could miss some hypothetical off-by-n bug. */ x = 0; - for (i = 0; i < len / sizeof(long); i++) { - x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffUL; - bitmap[i] = x; - } - write_extent_buffer(eb, bitmap, 0, len); - - for (i = 0; i < len * BITS_PER_BYTE; i++) { - int bit, bit1; - - bit = !!test_bit_in_byte(i, (u8 *)bitmap); - bit1 = !!extent_buffer_test_bit(eb, 0, i); - if (bit1 != bit) { - test_msg("Testing bit pattern failed\n"); - return -EINVAL; + bitmap_clear(bitmap, 0, len * BITS_PER_BYTE); + extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE); + for (i = 0; i < len * BITS_PER_BYTE / 32; i++) { + x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffU; + for (j = 0; j < 32; j++) { + if (x & (1U << j)) { + bitmap_set(bitmap, i * 32 + j, 1); + extent_buffer_bitmap_set(eb, 0, i * 32 + j, 1); + } } + } - bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE, - i % BITS_PER_BYTE); - if (bit1 != bit) { - test_msg("Testing bit pattern with offset failed\n"); - return -EINVAL; - } + ret = check_eb_bitmap(bitmap, eb, len); + if (ret) { + test_msg("Random bit pattern failed\n"); + return ret; } return 0; -- GitLab From 781e3bcf0e7632736d7562b52451a2d4fdfa231c Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Thu, 22 Sep 2016 17:24:24 -0700 Subject: [PATCH 0195/1167] Btrfs: expand free space tree sanity tests to catch endianness bug The free space tree format conversion functions were broken on big-endian systems, but the sanity tests didn't catch it because all of the operations were aligned to multiple words. This was meant to catch any bugs in the extent buffer code's handling of high memory, but it ended up hiding the endianness bug. Expand the tests to do both sector-aligned and page-aligned operations. Tested-by: Chandan Rajendra Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/tests/free-space-tree-tests.c | 164 +++++++++++++++---------- 1 file changed, 96 insertions(+), 68 deletions(-) diff --git a/fs/btrfs/tests/free-space-tree-tests.c b/fs/btrfs/tests/free-space-tree-tests.c index 7508d3b427804..c449da4d77b97 100644 --- a/fs/btrfs/tests/free-space-tree-tests.c +++ b/fs/btrfs/tests/free-space-tree-tests.c @@ -27,12 +27,6 @@ struct free_space_extent { u64 start, length; }; -/* - * The test cases align their operations to this in order to hit some of the - * edge cases in the bitmap code. - */ -#define BITMAP_RANGE (BTRFS_FREE_SPACE_BITMAP_BITS * PAGE_SIZE) - static int __check_free_space_extents(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, @@ -168,7 +162,8 @@ static int check_free_space_extents(struct btrfs_trans_handle *trans, static int test_empty_block_group(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, - struct btrfs_path *path) + struct btrfs_path *path, + u32 alignment) { struct free_space_extent extents[] = { {cache->key.objectid, cache->key.offset}, @@ -181,7 +176,8 @@ static int test_empty_block_group(struct btrfs_trans_handle *trans, static int test_remove_all(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, - struct btrfs_path *path) + struct btrfs_path *path, + u32 alignment) { struct free_space_extent extents[] = {}; int ret; @@ -201,16 +197,17 @@ static int test_remove_all(struct btrfs_trans_handle *trans, static int test_remove_beginning(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, - struct btrfs_path *path) + struct btrfs_path *path, + u32 alignment) { struct free_space_extent extents[] = { - {cache->key.objectid + BITMAP_RANGE, - cache->key.offset - BITMAP_RANGE}, + {cache->key.objectid + alignment, + cache->key.offset - alignment}, }; int ret; ret = __remove_from_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid, BITMAP_RANGE); + cache->key.objectid, alignment); if (ret) { test_msg("Could not remove free space\n"); return ret; @@ -224,17 +221,18 @@ static int test_remove_beginning(struct btrfs_trans_handle *trans, static int test_remove_end(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, - struct btrfs_path *path) + struct btrfs_path *path, + u32 alignment) { struct free_space_extent extents[] = { - {cache->key.objectid, cache->key.offset - BITMAP_RANGE}, + {cache->key.objectid, cache->key.offset - alignment}, }; int ret; ret = __remove_from_free_space_tree(trans, fs_info, cache, path, cache->key.objectid + - cache->key.offset - BITMAP_RANGE, - BITMAP_RANGE); + cache->key.offset - alignment, + alignment); if (ret) { test_msg("Could not remove free space\n"); return ret; @@ -247,18 +245,19 @@ static int test_remove_end(struct btrfs_trans_handle *trans, static int test_remove_middle(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, - struct btrfs_path *path) + struct btrfs_path *path, + u32 alignment) { struct free_space_extent extents[] = { - {cache->key.objectid, BITMAP_RANGE}, - {cache->key.objectid + 2 * BITMAP_RANGE, - cache->key.offset - 2 * BITMAP_RANGE}, + {cache->key.objectid, alignment}, + {cache->key.objectid + 2 * alignment, + cache->key.offset - 2 * alignment}, }; int ret; ret = __remove_from_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid + BITMAP_RANGE, - BITMAP_RANGE); + cache->key.objectid + alignment, + alignment); if (ret) { test_msg("Could not remove free space\n"); return ret; @@ -271,10 +270,11 @@ static int test_remove_middle(struct btrfs_trans_handle *trans, static int test_merge_left(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, - struct btrfs_path *path) + struct btrfs_path *path, + u32 alignment) { struct free_space_extent extents[] = { - {cache->key.objectid, 2 * BITMAP_RANGE}, + {cache->key.objectid, 2 * alignment}, }; int ret; @@ -287,15 +287,15 @@ static int test_merge_left(struct btrfs_trans_handle *trans, } ret = __add_to_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid, BITMAP_RANGE); + cache->key.objectid, alignment); if (ret) { test_msg("Could not add free space\n"); return ret; } ret = __add_to_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid + BITMAP_RANGE, - BITMAP_RANGE); + cache->key.objectid + alignment, + alignment); if (ret) { test_msg("Could not add free space\n"); return ret; @@ -308,10 +308,11 @@ static int test_merge_left(struct btrfs_trans_handle *trans, static int test_merge_right(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, - struct btrfs_path *path) + struct btrfs_path *path, + u32 alignment) { struct free_space_extent extents[] = { - {cache->key.objectid + BITMAP_RANGE, 2 * BITMAP_RANGE}, + {cache->key.objectid + alignment, 2 * alignment}, }; int ret; @@ -324,16 +325,16 @@ static int test_merge_right(struct btrfs_trans_handle *trans, } ret = __add_to_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid + 2 * BITMAP_RANGE, - BITMAP_RANGE); + cache->key.objectid + 2 * alignment, + alignment); if (ret) { test_msg("Could not add free space\n"); return ret; } ret = __add_to_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid + BITMAP_RANGE, - BITMAP_RANGE); + cache->key.objectid + alignment, + alignment); if (ret) { test_msg("Could not add free space\n"); return ret; @@ -346,10 +347,11 @@ static int test_merge_right(struct btrfs_trans_handle *trans, static int test_merge_both(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, - struct btrfs_path *path) + struct btrfs_path *path, + u32 alignment) { struct free_space_extent extents[] = { - {cache->key.objectid, 3 * BITMAP_RANGE}, + {cache->key.objectid, 3 * alignment}, }; int ret; @@ -362,23 +364,23 @@ static int test_merge_both(struct btrfs_trans_handle *trans, } ret = __add_to_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid, BITMAP_RANGE); + cache->key.objectid, alignment); if (ret) { test_msg("Could not add free space\n"); return ret; } ret = __add_to_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid + 2 * BITMAP_RANGE, - BITMAP_RANGE); + cache->key.objectid + 2 * alignment, + alignment); if (ret) { test_msg("Could not add free space\n"); return ret; } ret = __add_to_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid + BITMAP_RANGE, - BITMAP_RANGE); + cache->key.objectid + alignment, + alignment); if (ret) { test_msg("Could not add free space\n"); return ret; @@ -391,12 +393,13 @@ static int test_merge_both(struct btrfs_trans_handle *trans, static int test_merge_none(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, - struct btrfs_path *path) + struct btrfs_path *path, + u32 alignment) { struct free_space_extent extents[] = { - {cache->key.objectid, BITMAP_RANGE}, - {cache->key.objectid + 2 * BITMAP_RANGE, BITMAP_RANGE}, - {cache->key.objectid + 4 * BITMAP_RANGE, BITMAP_RANGE}, + {cache->key.objectid, alignment}, + {cache->key.objectid + 2 * alignment, alignment}, + {cache->key.objectid + 4 * alignment, alignment}, }; int ret; @@ -409,23 +412,23 @@ static int test_merge_none(struct btrfs_trans_handle *trans, } ret = __add_to_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid, BITMAP_RANGE); + cache->key.objectid, alignment); if (ret) { test_msg("Could not add free space\n"); return ret; } ret = __add_to_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid + 4 * BITMAP_RANGE, - BITMAP_RANGE); + cache->key.objectid + 4 * alignment, + alignment); if (ret) { test_msg("Could not add free space\n"); return ret; } ret = __add_to_free_space_tree(trans, fs_info, cache, path, - cache->key.objectid + 2 * BITMAP_RANGE, - BITMAP_RANGE); + cache->key.objectid + 2 * alignment, + alignment); if (ret) { test_msg("Could not add free space\n"); return ret; @@ -438,10 +441,11 @@ static int test_merge_none(struct btrfs_trans_handle *trans, typedef int (*test_func_t)(struct btrfs_trans_handle *, struct btrfs_fs_info *, struct btrfs_block_group_cache *, - struct btrfs_path *); + struct btrfs_path *, + u32 alignment); -static int run_test(test_func_t test_func, int bitmaps, - u32 sectorsize, u32 nodesize) +static int run_test(test_func_t test_func, int bitmaps, u32 sectorsize, + u32 nodesize, u32 alignment) { struct btrfs_fs_info *fs_info; struct btrfs_root *root = NULL; @@ -480,7 +484,7 @@ static int run_test(test_func_t test_func, int bitmaps, btrfs_set_header_nritems(root->node, 0); root->alloc_bytenr += 2 * nodesize; - cache = btrfs_alloc_dummy_block_group(8 * BITMAP_RANGE, sectorsize); + cache = btrfs_alloc_dummy_block_group(8 * alignment, sectorsize); if (!cache) { test_msg("Couldn't allocate dummy block group cache\n"); ret = -ENOMEM; @@ -514,7 +518,7 @@ static int run_test(test_func_t test_func, int bitmaps, } } - ret = test_func(&trans, root->fs_info, cache, path); + ret = test_func(&trans, root->fs_info, cache, path, alignment); if (ret) goto out; @@ -539,15 +543,27 @@ static int run_test(test_func_t test_func, int bitmaps, return ret; } -static int run_test_both_formats(test_func_t test_func, - u32 sectorsize, u32 nodesize) +static int run_test_both_formats(test_func_t test_func, u32 sectorsize, + u32 nodesize, u32 alignment) { + int test_ret = 0; int ret; - ret = run_test(test_func, 0, sectorsize, nodesize); - if (ret) - return ret; - return run_test(test_func, 1, sectorsize, nodesize); + ret = run_test(test_func, 0, sectorsize, nodesize, alignment); + if (ret) { + test_msg("%pf failed with extents, sectorsize=%u, nodesize=%u, alignment=%u\n", + test_func, sectorsize, nodesize, alignment); + test_ret = ret; + } + + ret = run_test(test_func, 1, sectorsize, nodesize, alignment); + if (ret) { + test_msg("%pf failed with bitmaps, sectorsize=%u, nodesize=%u, alignment=%u\n", + test_func, sectorsize, nodesize, alignment); + test_ret = ret; + } + + return test_ret; } int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize) @@ -563,18 +579,30 @@ int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize) test_merge_both, test_merge_none, }; + u32 bitmap_alignment; + int test_ret = 0; int i; + /* + * Align some operations to a page to flush out bugs in the extent + * buffer bitmap handling of highmem. + */ + bitmap_alignment = BTRFS_FREE_SPACE_BITMAP_BITS * PAGE_SIZE; + test_msg("Running free space tree tests\n"); for (i = 0; i < ARRAY_SIZE(tests); i++) { - int ret = run_test_both_formats(tests[i], sectorsize, - nodesize); - if (ret) { - test_msg("%pf : sectorsize %u failed\n", - tests[i], sectorsize); - return ret; - } + int ret; + + ret = run_test_both_formats(tests[i], sectorsize, nodesize, + sectorsize); + if (ret) + test_ret = ret; + + ret = run_test_both_formats(tests[i], sectorsize, nodesize, + bitmap_alignment); + if (ret) + test_ret = ret; } - return 0; + return test_ret; } -- GitLab From d2d9ac6aae1b743d729b2e4027d5666b2bc93003 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 23 Sep 2016 13:54:09 +0200 Subject: [PATCH 0196/1167] btrfs: tests: constify free space extent specs We don't change the given extent ranges, mark them const to catch accidental changes. Signed-off-by: David Sterba --- fs/btrfs/tests/free-space-tree-tests.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/tests/free-space-tree-tests.c b/fs/btrfs/tests/free-space-tree-tests.c index c449da4d77b97..061b4d5315c4a 100644 --- a/fs/btrfs/tests/free-space-tree-tests.c +++ b/fs/btrfs/tests/free-space-tree-tests.c @@ -31,7 +31,7 @@ static int __check_free_space_extents(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, struct btrfs_path *path, - struct free_space_extent *extents, + const struct free_space_extent * const extents, unsigned int num_extents) { struct btrfs_free_space_info *info; @@ -120,7 +120,7 @@ static int check_free_space_extents(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *cache, struct btrfs_path *path, - struct free_space_extent *extents, + const struct free_space_extent * const extents, unsigned int num_extents) { struct btrfs_free_space_info *info; @@ -165,7 +165,7 @@ static int test_empty_block_group(struct btrfs_trans_handle *trans, struct btrfs_path *path, u32 alignment) { - struct free_space_extent extents[] = { + const struct free_space_extent extents[] = { {cache->key.objectid, cache->key.offset}, }; @@ -179,7 +179,7 @@ static int test_remove_all(struct btrfs_trans_handle *trans, struct btrfs_path *path, u32 alignment) { - struct free_space_extent extents[] = {}; + const struct free_space_extent extents[] = {}; int ret; ret = __remove_from_free_space_tree(trans, fs_info, cache, path, @@ -200,7 +200,7 @@ static int test_remove_beginning(struct btrfs_trans_handle *trans, struct btrfs_path *path, u32 alignment) { - struct free_space_extent extents[] = { + const struct free_space_extent extents[] = { {cache->key.objectid + alignment, cache->key.offset - alignment}, }; @@ -224,7 +224,7 @@ static int test_remove_end(struct btrfs_trans_handle *trans, struct btrfs_path *path, u32 alignment) { - struct free_space_extent extents[] = { + const struct free_space_extent extents[] = { {cache->key.objectid, cache->key.offset - alignment}, }; int ret; @@ -248,7 +248,7 @@ static int test_remove_middle(struct btrfs_trans_handle *trans, struct btrfs_path *path, u32 alignment) { - struct free_space_extent extents[] = { + const struct free_space_extent extents[] = { {cache->key.objectid, alignment}, {cache->key.objectid + 2 * alignment, cache->key.offset - 2 * alignment}, @@ -273,7 +273,7 @@ static int test_merge_left(struct btrfs_trans_handle *trans, struct btrfs_path *path, u32 alignment) { - struct free_space_extent extents[] = { + const struct free_space_extent extents[] = { {cache->key.objectid, 2 * alignment}, }; int ret; @@ -311,7 +311,7 @@ static int test_merge_right(struct btrfs_trans_handle *trans, struct btrfs_path *path, u32 alignment) { - struct free_space_extent extents[] = { + const struct free_space_extent extents[] = { {cache->key.objectid + alignment, 2 * alignment}, }; int ret; @@ -350,7 +350,7 @@ static int test_merge_both(struct btrfs_trans_handle *trans, struct btrfs_path *path, u32 alignment) { - struct free_space_extent extents[] = { + const struct free_space_extent extents[] = { {cache->key.objectid, 3 * alignment}, }; int ret; @@ -396,7 +396,7 @@ static int test_merge_none(struct btrfs_trans_handle *trans, struct btrfs_path *path, u32 alignment) { - struct free_space_extent extents[] = { + const struct free_space_extent extents[] = { {cache->key.objectid, alignment}, {cache->key.objectid + 2 * alignment, alignment}, {cache->key.objectid + 4 * alignment, alignment}, -- GitLab From 0e6757859efea6ed919fc37e4ee468634220b2d2 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 23 Sep 2016 13:57:06 +0200 Subject: [PATCH 0197/1167] btrfs: tests: uninline member definitions in free_space_extent The recommended way is to put all members on separate lines. Signed-off-by: David Sterba --- fs/btrfs/tests/free-space-tree-tests.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/tests/free-space-tree-tests.c b/fs/btrfs/tests/free-space-tree-tests.c index 061b4d5315c4a..6e144048a72ee 100644 --- a/fs/btrfs/tests/free-space-tree-tests.c +++ b/fs/btrfs/tests/free-space-tree-tests.c @@ -24,7 +24,8 @@ #include "../transaction.h" struct free_space_extent { - u64 start, length; + u64 start; + u64 length; }; static int __check_free_space_extents(struct btrfs_trans_handle *trans, -- GitLab From ad3cce0641161301b3702bf2d69c0109fa92e8ec Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Mon, 3 Oct 2016 16:45:55 -0700 Subject: [PATCH 0198/1167] Input: elantech - fix Lenovo version typo Signed-off-by: Marcos Paulo de Souza Reviewed-by: Ulrik De Bie Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 08e252a424802..1b51961f90cbd 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1134,7 +1134,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, * System76 Pangolin 0x250f01 ? 2 hw buttons * (*) + 3 trackpoint buttons * (**) + 0 trackpoint buttons - * Note: Lenovo L430 and Lenovo L430 have the same fw_version/caps + * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps */ static void elantech_set_buttonpad_prop(struct psmouse *psmouse) { -- GitLab From f9a703a54d16ba2470391c4b12236ee56591d50c Mon Sep 17 00:00:00 2001 From: Matti Kurkela Date: Mon, 3 Oct 2016 16:48:17 -0700 Subject: [PATCH 0199/1167] Input: elantech - force needed quirks on Fujitsu H760 Just like Fujitsu CELSIUS H730, the H760 also has an Elantech touchpad with the same quirks. Without this patch, the touchpad is useless out-of-the-box as the mouse pointer won't move. This patch makes the driver aware of both the crc_enabled=1 requirement and the middle button, making the touchpad fully functional out-of-the-box. Signed-off-by: Matti Kurkela Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 1b51961f90cbd..37b52f150664e 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1159,6 +1159,13 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = { DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"), }, }, + { + /* Fujitsu H760 also has a middle button */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"), + }, + }, #endif { } }; @@ -1502,6 +1509,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"), }, }, + { + /* Fujitsu H760 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"), + }, + }, { /* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */ .matches = { -- GitLab From 80b7978c6014c65e3ee66cb31e6ba0167f2a59b7 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 3 Aug 2016 15:03:59 -0400 Subject: [PATCH 0200/1167] MIPS: Don't specify STACKPROTECTOR in defconfigs Only one defconfig has a STACKPROTECTOR value. And it asks for the strong variant, which isn't supported by older toolchains. Due to the nature of MIPS having more platform specific code than say x86, the allyesconfig and allmodconfig aren't as effective for build coverage. So, in addition, I like to use a trivial script to walk all the defconfigs and build each one. However I will get false positives on unsupported stackprotector values with an older toolchain like gcc-4.6.3. As in this instance I am just using the compiler as a glorified syntax checker on a machine where I build a bunch of other arch for the same reason, there is no real motivation to get a newer toolchain for improved optimization etc. Since there is only one of them, and there is nothing about these settings that are board/platform specific, I propose we just eliminate the existing instance and take the default. Signed-off-by: Paul Gortmaker Acked-by: James Hartley Cc: Ionela Voinescu Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13846/ Signed-off-by: Ralf Baechle --- arch/mips/configs/pistachio_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/configs/pistachio_defconfig b/arch/mips/configs/pistachio_defconfig index 8b7429127a1d1..698631327c8c6 100644 --- a/arch/mips/configs/pistachio_defconfig +++ b/arch/mips/configs/pistachio_defconfig @@ -29,7 +29,6 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y -- GitLab From 5035dd83cc57c7789ad38e0fe46b1e5796ca9079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 3 Aug 2016 11:58:24 +0200 Subject: [PATCH 0201/1167] MIPS: BMIPS: add missing bcm97435svmb to DT_NONE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 380e4270 added support for bcm97435svmb.dtb but missed adding it to DT_NONE. Also refactor DT_NONE dtbs in order to add larger names in the future. Signed-off-by: Álvaro Fernández Rojas Cc: f.fainelli@gmail.com Cc: jogo@openwrt.org Cc: cernekee@gmail.com Cc: robh@kernel.org Cc: simon@fire.lp0.eu Cc: john@phrozen.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13839/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/brcm/Makefile | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/arch/mips/boot/dts/brcm/Makefile b/arch/mips/boot/dts/brcm/Makefile index fda9d387cc086..87e07e26730bc 100644 --- a/arch/mips/boot/dts/brcm/Makefile +++ b/arch/mips/boot/dts/brcm/Makefile @@ -12,19 +12,20 @@ dtb-$(CONFIG_DT_BCM97420C) += bcm97420c.dtb dtb-$(CONFIG_DT_BCM97425SVMB) += bcm97425svmb.dtb dtb-$(CONFIG_DT_BCM97435SVMB) += bcm97435svmb.dtb -dtb-$(CONFIG_DT_NONE) += \ - bcm93384wvg.dtb \ - bcm93384wvg_viper.dtb \ - bcm96358nb4ser.dtb \ - bcm96368mvwg.dtb \ - bcm9ejtagprb.dtb \ - bcm97125cbmb.dtb \ - bcm97346dbsmb.dtb \ - bcm97358svmb.dtb \ - bcm97360svmb.dtb \ - bcm97362svmb.dtb \ - bcm97420c.dtb \ - bcm97425svmb.dtb +dtb-$(CONFIG_DT_NONE) += \ + bcm93384wvg.dtb \ + bcm93384wvg_viper.dtb \ + bcm96358nb4ser.dtb \ + bcm96368mvwg.dtb \ + bcm9ejtagprb.dtb \ + bcm97125cbmb.dtb \ + bcm97346dbsmb.dtb \ + bcm97358svmb.dtb \ + bcm97360svmb.dtb \ + bcm97362svmb.dtb \ + bcm97420c.dtb \ + bcm97425svmb.dtb \ + bcm97435svmb.dtb obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y)) -- GitLab From 695835511f96599911f5ab28329e75a598a1116b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 3 Aug 2016 11:58:25 +0200 Subject: [PATCH 0202/1167] MIPS: BMIPS: rename bcm96358nb4ser to bcm6358-neufbox4-sercom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prefix bcm9* should only be used for reference and evaluation boards from Broadcom. Also adds missing console output to bootargs. Signed-off-by: Álvaro Fernández Rojas Cc: f.fainelli@gmail.com Cc: jogo@openwrt.org Cc: cernekee@gmail.com Cc: robh@kernel.org Cc: simon@fire.lp0.eu Cc: john@phrozen.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13841/ Signed-off-by: Ralf Baechle --- arch/mips/bmips/Kconfig | 8 ++++---- arch/mips/boot/dts/brcm/Makefile | 3 ++- .../{bcm96358nb4ser.dts => bcm6358-neufbox4-sercomm.dts} | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) rename arch/mips/boot/dts/brcm/{bcm96358nb4ser.dts => bcm6358-neufbox4-sercomm.dts} (94%) diff --git a/arch/mips/bmips/Kconfig b/arch/mips/bmips/Kconfig index 264328d528c72..c8f1427b1d9c2 100644 --- a/arch/mips/bmips/Kconfig +++ b/arch/mips/bmips/Kconfig @@ -21,10 +21,6 @@ config DT_BCM93384WVG_VIPER bool "BCM93384WVG Viper CPU (EXPERIMENTAL)" select BUILTIN_DTB -config DT_BCM96358NB4SER - bool "BCM96358NB4SER" - select BUILTIN_DTB - config DT_BCM96368MVWG bool "BCM96368MVWG" select BUILTIN_DTB @@ -65,6 +61,10 @@ config DT_BCM97435SVMB bool "BCM97435SVMB" select BUILTIN_DTB +config DT_SFR_NEUFBOX4_SERCOMM + bool "SFR Neufbox 4 (Sercomm)" + select BUILTIN_DTB + endchoice endif diff --git a/arch/mips/boot/dts/brcm/Makefile b/arch/mips/boot/dts/brcm/Makefile index 87e07e26730bc..0abe298b6a5d8 100644 --- a/arch/mips/boot/dts/brcm/Makefile +++ b/arch/mips/boot/dts/brcm/Makefile @@ -1,6 +1,5 @@ dtb-$(CONFIG_DT_BCM93384WVG) += bcm93384wvg.dtb dtb-$(CONFIG_DT_BCM93384WVG_VIPER) += bcm93384wvg_viper.dtb -dtb-$(CONFIG_DT_BCM96358NB4SER) += bcm96358nb4ser.dtb dtb-$(CONFIG_DT_BCM96368MVWG) += bcm96368mvwg.dtb dtb-$(CONFIG_DT_BCM9EJTAGPRB) += bcm9ejtagprb.dtb dtb-$(CONFIG_DT_BCM97125CBMB) += bcm97125cbmb.dtb @@ -11,8 +10,10 @@ dtb-$(CONFIG_DT_BCM97362SVMB) += bcm97362svmb.dtb dtb-$(CONFIG_DT_BCM97420C) += bcm97420c.dtb dtb-$(CONFIG_DT_BCM97425SVMB) += bcm97425svmb.dtb dtb-$(CONFIG_DT_BCM97435SVMB) += bcm97435svmb.dtb +dtb-$(CONFIG_DT_SFR_NEUFBOX4_SERCOMM) += bcm6358-neufbox4-sercomm.dtb dtb-$(CONFIG_DT_NONE) += \ + bcm6358-neufbox4-sercomm.dtb \ bcm93384wvg.dtb \ bcm93384wvg_viper.dtb \ bcm96358nb4ser.dtb \ diff --git a/arch/mips/boot/dts/brcm/bcm96358nb4ser.dts b/arch/mips/boot/dts/brcm/bcm6358-neufbox4-sercomm.dts similarity index 94% rename from arch/mips/boot/dts/brcm/bcm96358nb4ser.dts rename to arch/mips/boot/dts/brcm/bcm6358-neufbox4-sercomm.dts index f412117972e6b..702eae2a22a0b 100644 --- a/arch/mips/boot/dts/brcm/bcm96358nb4ser.dts +++ b/arch/mips/boot/dts/brcm/bcm6358-neufbox4-sercomm.dts @@ -12,6 +12,7 @@ }; chosen { + bootargs = "console=ttyS0,115200"; stdout-path = &uart0; }; }; -- GitLab From 786e19a88895b6401313adfd5bc72789dc44f631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 3 Aug 2016 11:58:26 +0200 Subject: [PATCH 0203/1167] MIPS: BMIPS: Add device tree example for BCM63268 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a device tree example for Comtrend VR-3032u, which also serves as a real example for brcm,bcm6328-leds. Signed-off-by: Álvaro Fernández Rojas Cc: f.fainelli@gmail.com Cc: jogo@openwrt.org Cc: cernekee@gmail.com Cc: robh@kernel.org Cc: simon@fire.lp0.eu Cc: john@phrozen.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13842/ Signed-off-by: Ralf Baechle --- arch/mips/bmips/Kconfig | 4 + arch/mips/boot/dts/brcm/Makefile | 2 + .../dts/brcm/bcm63268-comtrend-vr-3032u.dts | 108 ++++++++++++++ arch/mips/boot/dts/brcm/bcm63268.dtsi | 134 ++++++++++++++++++ 4 files changed, 248 insertions(+) create mode 100644 arch/mips/boot/dts/brcm/bcm63268-comtrend-vr-3032u.dts create mode 100644 arch/mips/boot/dts/brcm/bcm63268.dtsi diff --git a/arch/mips/bmips/Kconfig b/arch/mips/bmips/Kconfig index c8f1427b1d9c2..6a0946c443c0b 100644 --- a/arch/mips/bmips/Kconfig +++ b/arch/mips/bmips/Kconfig @@ -61,6 +61,10 @@ config DT_BCM97435SVMB bool "BCM97435SVMB" select BUILTIN_DTB +config DT_COMTREND_VR3032U + bool "Comtrend VR-3032u" + select BUILTIN_DTB + config DT_SFR_NEUFBOX4_SERCOMM bool "SFR Neufbox 4 (Sercomm)" select BUILTIN_DTB diff --git a/arch/mips/boot/dts/brcm/Makefile b/arch/mips/boot/dts/brcm/Makefile index 0abe298b6a5d8..8281ec65d4369 100644 --- a/arch/mips/boot/dts/brcm/Makefile +++ b/arch/mips/boot/dts/brcm/Makefile @@ -10,10 +10,12 @@ dtb-$(CONFIG_DT_BCM97362SVMB) += bcm97362svmb.dtb dtb-$(CONFIG_DT_BCM97420C) += bcm97420c.dtb dtb-$(CONFIG_DT_BCM97425SVMB) += bcm97425svmb.dtb dtb-$(CONFIG_DT_BCM97435SVMB) += bcm97435svmb.dtb +dtb-$(CONFIG_DT_COMTREND_VR3032U) += bcm63268-comtrend-vr-3032u.dtb dtb-$(CONFIG_DT_SFR_NEUFBOX4_SERCOMM) += bcm6358-neufbox4-sercomm.dtb dtb-$(CONFIG_DT_NONE) += \ bcm6358-neufbox4-sercomm.dtb \ + bcm63268-comtrend-vr-3032u.dtb \ bcm93384wvg.dtb \ bcm93384wvg_viper.dtb \ bcm96358nb4ser.dtb \ diff --git a/arch/mips/boot/dts/brcm/bcm63268-comtrend-vr-3032u.dts b/arch/mips/boot/dts/brcm/bcm63268-comtrend-vr-3032u.dts new file mode 100644 index 0000000000000..430d35ca33d59 --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm63268-comtrend-vr-3032u.dts @@ -0,0 +1,108 @@ +/dts-v1/; + +/include/ "bcm63268.dtsi" + +/ { + compatible = "comtrend,vr-3032u", "brcm,bcm63268"; + model = "Comtrend VR-3032u"; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x04000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200"; + stdout-path = &uart0; + }; +}; + +&leds0 { + status = "ok"; + brcm,serial-leds; + brcm,serial-dat-low; + brcm,serial-shift-inv; + + led@0 { + reg = <0>; + brcm,hardware-controlled; + brcm,link-signal-sources = <0>; + /* GPHY0 Speed 0 */ + }; + led@1 { + reg = <1>; + brcm,hardware-controlled; + brcm,link-signal-sources = <1>; + /* GPHY0 Speed 1 */ + }; + led@2 { + reg = <2>; + active-low; + label = "vr-3032u:red:inet"; + }; + led@3 { + reg = <3>; + active-low; + label = "vr-3032u:green:dsl"; + }; + led@4 { + reg = <4>; + active-low; + label = "vr-3032u:green:usb"; + }; + led@7 { + reg = <7>; + active-low; + label = "vr-3032u:green:wps"; + }; + led@8 { + reg = <8>; + active-low; + label = "vr-3032u:green:inet"; + }; + led@9 { + reg = <9>; + brcm,hardware-controlled; + /* EPHY0 Activity */ + }; + led@10 { + reg = <10>; + brcm,hardware-controlled; + /* EPHY1 Activity */ + }; + led@11 { + reg = <11>; + brcm,hardware-controlled; + /* EPHY2 Activity */ + }; + led@12 { + reg = <12>; + brcm,hardware-controlled; + /* GPHY0 Activity */ + }; + led@13 { + reg = <13>; + brcm,hardware-controlled; + /* EPHY0 Speed */ + }; + led@14 { + reg = <14>; + brcm,hardware-controlled; + /* EPHY1 Speed */ + }; + led@15 { + reg = <15>; + brcm,hardware-controlled; + /* EPHY2 Speed */ + }; + led@20 { + reg = <20>; + active-low; + label = "vr-3032u:green:power"; + default-state = "on"; + }; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm63268.dtsi b/arch/mips/boot/dts/brcm/bcm63268.dtsi new file mode 100644 index 0000000000000..7e6bf2cc0287f --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm63268.dtsi @@ -0,0 +1,134 @@ +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "brcm,bcm63268"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + mips-hpt-frequency = <200000000>; + + cpu@0 { + compatible = "brcm,bmips4350"; + device_type = "cpu"; + reg = <0>; + }; + + cpu@1 { + compatible = "brcm,bmips4350"; + device_type = "cpu"; + reg = <1>; + }; + }; + + clocks { + periph_clk: periph-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + }; + }; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + cpu_intc: interrupt-controller { + #address-cells = <0>; + compatible = "mti,cpu-interrupt-controller"; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + ubus { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "simple-bus"; + ranges; + + periph_cntl: syscon@10000000 { + compatible = "syscon"; + reg = <0x10000000 0x14>; + native-endian; + }; + + reboot: syscon-reboot@10000008 { + compatible = "syscon-reboot"; + regmap = <&periph_cntl>; + offset = <0x8>; + mask = <0x1>; + }; + + periph_intc: interrupt-controller@10000020 { + compatible = "brcm,bcm6345-l1-intc"; + reg = <0x10000020 0x20>, + <0x10000040 0x20>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; + }; + + uart0: serial@10000180 { + compatible = "brcm,bcm6345-uart"; + reg = <0x10000180 0x18>; + + interrupt-parent = <&periph_intc>; + interrupts = <5>; + + clocks = <&periph_clk>; + + status = "disabled"; + }; + + uart1: serial@100001a0 { + compatible = "brcm,bcm6345-uart"; + reg = <0x100001a0 0x18>; + + interrupt-parent = <&periph_intc>; + interrupts = <34>; + + clocks = <&periph_clk>; + + status = "disabled"; + }; + + leds0: led-controller@10001900 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6328-leds"; + reg = <0x10001900 0x24>; + + status = "disabled"; + }; + + ehci: usb@10002500 { + compatible = "brcm,bcm63268-ehci", "generic-ehci"; + reg = <0x10002500 0x100>; + big-endian; + + interrupt-parent = <&periph_intc>; + interrupts = <10>; + + status = "disabled"; + }; + + ohci: usb@10002600 { + compatible = "brcm,bcm63268-ohci", "generic-ohci"; + reg = <0x10002600 0x100>; + big-endian; + no-big-frame-no; + + interrupt-parent = <&periph_intc>; + interrupts = <9>; + + status = "disabled"; + }; + }; +}; -- GitLab From 4bac0e2afc7b7603c1781733629254d7a6b9a83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 3 Aug 2016 11:58:27 +0200 Subject: [PATCH 0204/1167] MIPS: BMIPS: Add BCM3368 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCM3368 has a shared TLB which conflicts with current SMP support, so it must be disabled for now. Signed-off-by: Álvaro Fernández Rojas Cc: f.fainelli@gmail.com Cc: jogo@openwrt.org Cc: cernekee@gmail.com Cc: robh@kernel.org Cc: simon@fire.lp0.eu Cc: john@phrozen.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13840/ Signed-off-by: Ralf Baechle --- Documentation/devicetree/bindings/mips/brcm/soc.txt | 2 +- arch/mips/bmips/setup.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mips/brcm/soc.txt b/Documentation/devicetree/bindings/mips/brcm/soc.txt index 4a7e030e4f9ba..65bc572ef5363 100644 --- a/Documentation/devicetree/bindings/mips/brcm/soc.txt +++ b/Documentation/devicetree/bindings/mips/brcm/soc.txt @@ -2,7 +2,7 @@ Required properties: -- compatible: "brcm,bcm3384", "brcm,bcm33843" +- compatible: "brcm,bcm3368", "brcm,bcm3384", "brcm,bcm33843" "brcm,bcm3384-viper", "brcm,bcm33843-viper" "brcm,bcm6328", "brcm,bcm6358", "brcm,bcm6368", "brcm,bcm63168", "brcm,bcm63268", diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index 6776042679dd2..e219bc4b51293 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c @@ -98,7 +98,7 @@ static void bcm6328_quirks(void) static void bcm6358_quirks(void) { /* - * BCM6358 needs special handling for its shared TLB, so + * BCM3368/BCM6358 need special handling for their shared TLB, so * disable SMP for now */ bmips_smp_enabled = 0; @@ -110,6 +110,7 @@ static void bcm6368_quirks(void) } static const struct bmips_quirk bmips_quirk_list[] = { + { "brcm,bcm3368", &bcm6358_quirks }, { "brcm,bcm3384-viper", &bcm3384_viper_quirks }, { "brcm,bcm33843-viper", &bcm3384_viper_quirks }, { "brcm,bcm6328", &bcm6328_quirks }, -- GitLab From 484d83b3d6a0b49b5f26bd9a375b9a1575e09682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 3 Aug 2016 11:58:28 +0200 Subject: [PATCH 0205/1167] MIPS: BMIPS: Add device tree example for BCM3368 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a device tree example for Netgear CVG834G. Signed-off-by: Álvaro Fernández Rojas Cc: f.fainelli@gmail.com Cc: jogo@openwrt.org Cc: cernekee@gmail.com Cc: robh@kernel.org Cc: simon@fire.lp0.eu Cc: john@phrozen.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13843/ Signed-off-by: Ralf Baechle --- arch/mips/bmips/Kconfig | 4 + arch/mips/boot/dts/brcm/Makefile | 2 + .../boot/dts/brcm/bcm3368-netgear-cvg834g.dts | 22 ++++ arch/mips/boot/dts/brcm/bcm3368.dtsi | 101 ++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 arch/mips/boot/dts/brcm/bcm3368-netgear-cvg834g.dts create mode 100644 arch/mips/boot/dts/brcm/bcm3368.dtsi diff --git a/arch/mips/bmips/Kconfig b/arch/mips/bmips/Kconfig index 6a0946c443c0b..f499fd251e3a3 100644 --- a/arch/mips/bmips/Kconfig +++ b/arch/mips/bmips/Kconfig @@ -65,6 +65,10 @@ config DT_COMTREND_VR3032U bool "Comtrend VR-3032u" select BUILTIN_DTB +config DT_NETGEAR_CVG834G + bool "NETGEAR CVG834G" + select BUILTIN_DTB + config DT_SFR_NEUFBOX4_SERCOMM bool "SFR Neufbox 4 (Sercomm)" select BUILTIN_DTB diff --git a/arch/mips/boot/dts/brcm/Makefile b/arch/mips/boot/dts/brcm/Makefile index 8281ec65d4369..a698e845ec53e 100644 --- a/arch/mips/boot/dts/brcm/Makefile +++ b/arch/mips/boot/dts/brcm/Makefile @@ -11,9 +11,11 @@ dtb-$(CONFIG_DT_BCM97420C) += bcm97420c.dtb dtb-$(CONFIG_DT_BCM97425SVMB) += bcm97425svmb.dtb dtb-$(CONFIG_DT_BCM97435SVMB) += bcm97435svmb.dtb dtb-$(CONFIG_DT_COMTREND_VR3032U) += bcm63268-comtrend-vr-3032u.dtb +dtb-$(CONFIG_DT_NETGEAR_CVG834G) += bcm3368-netgear-cvg834g.dtb dtb-$(CONFIG_DT_SFR_NEUFBOX4_SERCOMM) += bcm6358-neufbox4-sercomm.dtb dtb-$(CONFIG_DT_NONE) += \ + bcm3368-netgear-cvg834g.dtb \ bcm6358-neufbox4-sercomm.dtb \ bcm63268-comtrend-vr-3032u.dtb \ bcm93384wvg.dtb \ diff --git a/arch/mips/boot/dts/brcm/bcm3368-netgear-cvg834g.dts b/arch/mips/boot/dts/brcm/bcm3368-netgear-cvg834g.dts new file mode 100644 index 0000000000000..2f2e80fdcde87 --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm3368-netgear-cvg834g.dts @@ -0,0 +1,22 @@ +/dts-v1/; + +/include/ "bcm3368.dtsi" + +/ { + compatible = "netgear,cvg834g", "brcm,bcm3368"; + model = "NETGEAR CVG834G"; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x02000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200"; + stdout-path = &uart0; + }; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm3368.dtsi b/arch/mips/boot/dts/brcm/bcm3368.dtsi new file mode 100644 index 0000000000000..bee855cb80735 --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm3368.dtsi @@ -0,0 +1,101 @@ +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "brcm,bcm3368"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + mips-hpt-frequency = <150000000>; + + cpu@0 { + compatible = "brcm,bmips4350"; + device_type = "cpu"; + reg = <0>; + }; + + cpu@1 { + compatible = "brcm,bmips4350"; + device_type = "cpu"; + reg = <1>; + }; + }; + + clocks { + periph_clk: periph-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + }; + }; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + cpu_intc: interrupt-controller { + #address-cells = <0>; + compatible = "mti,cpu-interrupt-controller"; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + ubus { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "simple-bus"; + ranges; + + periph_cntl: syscon@fff8c000 { + compatible = "syscon"; + reg = <0xfff8c000 0xc>; + native-endian; + }; + + reboot: syscon-reboot@fff8c008 { + compatible = "syscon-reboot"; + regmap = <&periph_cntl>; + offset = <0x8>; + mask = <0x1>; + }; + + periph_intc: interrupt-controller@fff8c00c { + compatible = "brcm,bcm6345-l1-intc"; + reg = <0xfff8c00c 0x8>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>; + }; + + uart0: serial@fff8c100 { + compatible = "brcm,bcm6345-uart"; + reg = <0xfff8c100 0x18>; + + interrupt-parent = <&periph_intc>; + interrupts = <2>; + + clocks = <&periph_clk>; + + status = "disabled"; + }; + + uart1: serial@fff8c120 { + compatible = "brcm,bcm6345-uart"; + reg = <0xfff8c120 0x18>; + + interrupt-parent = <&periph_intc>; + interrupts = <3>; + + clocks = <&periph_clk>; + + status = "disabled"; + }; + }; +}; -- GitLab From 8e385a66d7db14599457fdc7898403c1fa24acb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 3 Aug 2016 11:58:29 +0200 Subject: [PATCH 0206/1167] MIPS: BMIPS: Add BCM6362 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCM6362 is a BMIPS4350 SoC which needs the same fixup as BCM6368 in order to enable SMP support. Signed-off-by: Álvaro Fernández Rojas Cc: f.fainelli@gmail.com Cc: jogo@openwrt.org Cc: cernekee@gmail.com Cc: robh@kernel.org Cc: simon@fire.lp0.eu Cc: john@phrozen.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13845/ Signed-off-by: Ralf Baechle --- Documentation/devicetree/bindings/mips/brcm/soc.txt | 2 +- arch/mips/bmips/setup.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mips/brcm/soc.txt b/Documentation/devicetree/bindings/mips/brcm/soc.txt index 65bc572ef5363..e4e1cd91fb1f2 100644 --- a/Documentation/devicetree/bindings/mips/brcm/soc.txt +++ b/Documentation/devicetree/bindings/mips/brcm/soc.txt @@ -4,7 +4,7 @@ Required properties: - compatible: "brcm,bcm3368", "brcm,bcm3384", "brcm,bcm33843" "brcm,bcm3384-viper", "brcm,bcm33843-viper" - "brcm,bcm6328", "brcm,bcm6358", "brcm,bcm6368", + "brcm,bcm6328", "brcm,bcm6358", "brcm,bcm6362", "brcm,bcm6368", "brcm,bcm63168", "brcm,bcm63268", "brcm,bcm7125", "brcm,bcm7346", "brcm,bcm7358", "brcm,bcm7360", "brcm,bcm7362", "brcm,bcm7420", "brcm,bcm7425" diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index e219bc4b51293..edf1b31df10b5 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c @@ -115,6 +115,7 @@ static const struct bmips_quirk bmips_quirk_list[] = { { "brcm,bcm33843-viper", &bcm3384_viper_quirks }, { "brcm,bcm6328", &bcm6328_quirks }, { "brcm,bcm6358", &bcm6358_quirks }, + { "brcm,bcm6362", &bcm6368_quirks }, { "brcm,bcm6368", &bcm6368_quirks }, { "brcm,bcm63168", &bcm6368_quirks }, { "brcm,bcm63268", &bcm6368_quirks }, -- GitLab From ef0c592ad099fd443d8aad36719f26f62acea18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 3 Aug 2016 11:58:30 +0200 Subject: [PATCH 0207/1167] MIPS: BMIPS: Add device tree example for BCM6362 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a device tree example for SFR NeufBox 6. Signed-off-by: Álvaro Fernández Rojas Cc: f.fainelli@gmail.com Cc: jogo@openwrt.org Cc: cernekee@gmail.com Cc: robh@kernel.org Cc: simon@fire.lp0.eu Cc: john@phrozen.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13844/ Signed-off-by: Ralf Baechle --- arch/mips/bmips/Kconfig | 4 + arch/mips/boot/dts/brcm/Makefile | 2 + .../dts/brcm/bcm6362-neufbox6-sercomm.dts | 22 +++ arch/mips/boot/dts/brcm/bcm6362.dtsi | 134 ++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 arch/mips/boot/dts/brcm/bcm6362-neufbox6-sercomm.dts create mode 100644 arch/mips/boot/dts/brcm/bcm6362.dtsi diff --git a/arch/mips/bmips/Kconfig b/arch/mips/bmips/Kconfig index f499fd251e3a3..2d60f25403de1 100644 --- a/arch/mips/bmips/Kconfig +++ b/arch/mips/bmips/Kconfig @@ -73,6 +73,10 @@ config DT_SFR_NEUFBOX4_SERCOMM bool "SFR Neufbox 4 (Sercomm)" select BUILTIN_DTB +config DT_SFR_NEUFBOX6_SERCOMM + bool "SFR Neufbox 6 (Sercomm)" + select BUILTIN_DTB + endchoice endif diff --git a/arch/mips/boot/dts/brcm/Makefile b/arch/mips/boot/dts/brcm/Makefile index a698e845ec53e..d61bc2aebf69b 100644 --- a/arch/mips/boot/dts/brcm/Makefile +++ b/arch/mips/boot/dts/brcm/Makefile @@ -13,10 +13,12 @@ dtb-$(CONFIG_DT_BCM97435SVMB) += bcm97435svmb.dtb dtb-$(CONFIG_DT_COMTREND_VR3032U) += bcm63268-comtrend-vr-3032u.dtb dtb-$(CONFIG_DT_NETGEAR_CVG834G) += bcm3368-netgear-cvg834g.dtb dtb-$(CONFIG_DT_SFR_NEUFBOX4_SERCOMM) += bcm6358-neufbox4-sercomm.dtb +dtb-$(CONFIG_DT_SFR_NEUFBOX6_SERCOMM) += bcm6362-neufbox6-sercomm.dtb dtb-$(CONFIG_DT_NONE) += \ bcm3368-netgear-cvg834g.dtb \ bcm6358-neufbox4-sercomm.dtb \ + bcm6362-neufbox6-sercomm.dtb \ bcm63268-comtrend-vr-3032u.dtb \ bcm93384wvg.dtb \ bcm93384wvg_viper.dtb \ diff --git a/arch/mips/boot/dts/brcm/bcm6362-neufbox6-sercomm.dts b/arch/mips/boot/dts/brcm/bcm6362-neufbox6-sercomm.dts new file mode 100644 index 0000000000000..480f2a5bf1da4 --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm6362-neufbox6-sercomm.dts @@ -0,0 +1,22 @@ +/dts-v1/; + +/include/ "bcm6362.dtsi" + +/ { + compatible = "sfr,nb6-ser", "brcm,bcm6362"; + model = "SFR NeufBox 6 (Sercomm)"; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x08000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200"; + stdout-path = &uart0; + }; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm6362.dtsi b/arch/mips/boot/dts/brcm/bcm6362.dtsi new file mode 100644 index 0000000000000..c507da594f2fb --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm6362.dtsi @@ -0,0 +1,134 @@ +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "brcm,bcm6362"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + mips-hpt-frequency = <200000000>; + + cpu@0 { + compatible = "brcm,bmips4350"; + device_type = "cpu"; + reg = <0>; + }; + + cpu@1 { + compatible = "brcm,bmips4350"; + device_type = "cpu"; + reg = <1>; + }; + }; + + clocks { + periph_clk: periph-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + }; + }; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + cpu_intc: interrupt-controller { + #address-cells = <0>; + compatible = "mti,cpu-interrupt-controller"; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + ubus { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "simple-bus"; + ranges; + + periph_cntl: syscon@10000000 { + compatible = "syscon"; + reg = <0x10000000 0x14>; + native-endian; + }; + + reboot: syscon-reboot@10000008 { + compatible = "syscon-reboot"; + regmap = <&periph_cntl>; + offset = <0x8>; + mask = <0x1>; + }; + + periph_intc: interrupt-controller@10000020 { + compatible = "brcm,bcm6345-l1-intc"; + reg = <0x10000020 0x10>, + <0x10000030 0x10>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; + }; + + uart0: serial@10000100 { + compatible = "brcm,bcm6345-uart"; + reg = <0x10000100 0x18>; + + interrupt-parent = <&periph_intc>; + interrupts = <3>; + + clocks = <&periph_clk>; + + status = "disabled"; + }; + + uart1: serial@10000120 { + compatible = "brcm,bcm6345-uart"; + reg = <0x10000120 0x18>; + + interrupt-parent = <&periph_intc>; + interrupts = <4>; + + clocks = <&periph_clk>; + + status = "disabled"; + }; + + leds0: led-controller@10001900 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6328-leds"; + reg = <0x10001900 0x24>; + + status = "disabled"; + }; + + ehci: usb@10002500 { + compatible = "brcm,bcm6362-ehci", "generic-ehci"; + reg = <0x10002500 0x100>; + big-endian; + + interrupt-parent = <&periph_intc>; + interrupts = <10>; + + status = "disabled"; + }; + + ohci: usb@10002600 { + compatible = "brcm,bcm6362-ohci", "generic-ohci"; + reg = <0x10002600 0x100>; + big-endian; + no-big-frame-no; + + interrupt-parent = <&periph_intc>; + interrupts = <9>; + + status = "disabled"; + }; + }; +}; -- GitLab From 4c0f5a7124aa74b1a99035ca3d12f83c734e7fe8 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Tue, 24 May 2016 17:09:30 +0300 Subject: [PATCH 0208/1167] MIPS: Octeon: Take all memory into use by default. Take all memory into use by default, instead of limiting to 512 MB. Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: Sivasubramanian Palanisamy Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13353/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index cb16fcc5f8f05..15c923dcb98e8 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -65,7 +65,7 @@ EXPORT_SYMBOL(octeon_should_swizzle_table); extern void pci_console_init(const char *arg); #endif -static unsigned long long MAX_MEMORY = 512ull << 20; +static unsigned long long MAX_MEMORY = ULLONG_MAX; DEFINE_SEMAPHORE(octeon_bootbus_sem); EXPORT_SYMBOL(octeon_bootbus_sem); -- GitLab From fd6ecf42fb345e5a53fa2edc91162022e31cee41 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Tue, 24 May 2016 17:09:31 +0300 Subject: [PATCH 0209/1167] MIPS: Octeon: Rename upper case variables at setup time. Rename upper case variables. Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: Sivasubramanian Palanisamy Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13352/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/setup.c | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 15c923dcb98e8..89be31ba70ed5 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -65,7 +65,8 @@ EXPORT_SYMBOL(octeon_should_swizzle_table); extern void pci_console_init(const char *arg); #endif -static unsigned long long MAX_MEMORY = ULLONG_MAX; +static unsigned long long max_memory = ULLONG_MAX; +static unsigned long long reserve_low_mem; DEFINE_SEMAPHORE(octeon_bootbus_sem); EXPORT_SYMBOL(octeon_bootbus_sem); @@ -75,7 +76,6 @@ struct octeon_boot_descriptor *octeon_boot_desc_ptr; struct cvmx_bootinfo *octeon_bootinfo; EXPORT_SYMBOL(octeon_bootinfo); -static unsigned long long RESERVE_LOW_MEM = 0ull; #ifdef CONFIG_KEXEC #ifdef CONFIG_SMP /* @@ -125,18 +125,18 @@ static void kexec_bootmem_init(uint64_t mem_size, uint32_t low_reserved_bytes) bootmem_desc->major_version = CVMX_BOOTMEM_DESC_MAJ_VER; bootmem_desc->minor_version = CVMX_BOOTMEM_DESC_MIN_VER; - addr = (OCTEON_DDR0_BASE + RESERVE_LOW_MEM + low_reserved_bytes); + addr = (OCTEON_DDR0_BASE + reserve_low_mem + low_reserved_bytes); bootmem_desc->head_addr = 0; if (mem_size <= OCTEON_DDR0_SIZE) { __cvmx_bootmem_phy_free(addr, - mem_size - RESERVE_LOW_MEM - + mem_size - reserve_low_mem - low_reserved_bytes, 0); return; } __cvmx_bootmem_phy_free(addr, - OCTEON_DDR0_SIZE - RESERVE_LOW_MEM - + OCTEON_DDR0_SIZE - reserve_low_mem - low_reserved_bytes, 0); mem_size -= OCTEON_DDR0_SIZE; @@ -846,15 +846,15 @@ void __init prom_init(void) /* Default to 64MB in the simulator to speed things up */ if (octeon_is_simulation()) - MAX_MEMORY = 64ull << 20; + max_memory = 64ull << 20; arg = strstr(arcs_cmdline, "mem="); if (arg) { - MAX_MEMORY = memparse(arg + 4, &p); - if (MAX_MEMORY == 0) - MAX_MEMORY = 32ull << 30; + max_memory = memparse(arg + 4, &p); + if (max_memory == 0) + max_memory = 32ull << 30; if (*p == '@') - RESERVE_LOW_MEM = memparse(p + 1, &p); + reserve_low_mem = memparse(p + 1, &p); } arcs_cmdline[0] = 0; @@ -864,11 +864,11 @@ void __init prom_init(void) cvmx_phys_to_ptr(octeon_boot_desc_ptr->argv[i]); if ((strncmp(arg, "MEM=", 4) == 0) || (strncmp(arg, "mem=", 4) == 0)) { - MAX_MEMORY = memparse(arg + 4, &p); - if (MAX_MEMORY == 0) - MAX_MEMORY = 32ull << 30; + max_memory = memparse(arg + 4, &p); + if (max_memory == 0) + max_memory = 32ull << 30; if (*p == '@') - RESERVE_LOW_MEM = memparse(p + 1, &p); + reserve_low_mem = memparse(p + 1, &p); #ifdef CONFIG_KEXEC } else if (strncmp(arg, "crashkernel=", 12) == 0) { crashk_size = memparse(arg+12, &p); @@ -957,13 +957,13 @@ void __init plat_mem_setup(void) * to consistently work. */ mem_alloc_size = 4 << 20; - if (mem_alloc_size > MAX_MEMORY) - mem_alloc_size = MAX_MEMORY; + if (mem_alloc_size > max_memory) + mem_alloc_size = max_memory; /* Crashkernel ignores bootmem list. It relies on mem=X@Y option */ #ifdef CONFIG_CRASH_DUMP - add_memory_region(RESERVE_LOW_MEM, MAX_MEMORY, BOOT_MEM_RAM); - total += MAX_MEMORY; + add_memory_region(reserve_low_mem, max_memory, BOOT_MEM_RAM); + total += max_memory; #else #ifdef CONFIG_KEXEC if (crashk_size > 0) { @@ -978,7 +978,7 @@ void __init plat_mem_setup(void) */ cvmx_bootmem_lock(); while ((boot_mem_map.nr_map < BOOT_MEM_MAP_MAX) - && (total < MAX_MEMORY)) { + && (total < max_memory)) { memory = cvmx_bootmem_phy_alloc(mem_alloc_size, __pa_symbol(&_end), -1, 0x100000, -- GitLab From a1ca83869d4ea65afd5a6a403d5d5ec2c41ef60e Mon Sep 17 00:00:00 2001 From: Yang Ling Date: Thu, 19 May 2016 12:22:19 +0800 Subject: [PATCH 0210/1167] MIPS: Add CPU support for Loongson1C Loongson1C is a 32-bit SoC designed by Loongson Technology Co., Ltd, with many features similar to Loongson1B. Signed-off-by: Yang Ling Cc: paul.burton@imgtec.com Cc: markos.chandras@imgtec.com Cc: james.hogan@imgtec.com Cc: kumba@gentoo.org Cc: macro@imgtec.com Cc: david.daney@cavium.com Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13303/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu-type.h | 3 ++- arch/mips/include/asm/cpu.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h index fbe1881f28fca..bdd6dc18e65c6 100644 --- a/arch/mips/include/asm/cpu-type.h +++ b/arch/mips/include/asm/cpu-type.h @@ -24,7 +24,8 @@ static inline int __pure __get_cpu_type(const int cpu_type) case CPU_LOONGSON3: #endif -#ifdef CONFIG_SYS_HAS_CPU_LOONGSON1B +#if defined(CONFIG_SYS_HAS_CPU_LOONGSON1B) || \ + defined(CONFIG_SYS_HAS_CPU_LOONGSON1C) case CPU_LOONGSON1: #endif diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index f672df8b26d01..9a8372484edc0 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -240,6 +240,7 @@ #define PRID_REV_VR4130 0x0080 #define PRID_REV_34K_V1_0_2 0x0022 #define PRID_REV_LOONGSON1B 0x0020 +#define PRID_REV_LOONGSON1C 0x0020 /* Same as Loongson-1B */ #define PRID_REV_LOONGSON2E 0x0002 #define PRID_REV_LOONGSON2F 0x0003 #define PRID_REV_LOONGSON3A_R1 0x0005 -- GitLab From 12e3280b33fe1ada85b84f67613d03e1b6d8dbf6 Mon Sep 17 00:00:00 2001 From: Yang Ling Date: Thu, 19 May 2016 12:29:30 +0800 Subject: [PATCH 0211/1167] MIPS: Loongson1C: Add board support Adds basic platform devices for Loongson1C, including serial port and ethernet. Signed-off-by: Yang Ling Cc: keguang.zhang@gmail.com Cc: chenhc@lemote.com Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13304/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 13 ++++ arch/mips/include/asm/mach-loongson32/irq.h | 41 ++++++++++++- .../include/asm/mach-loongson32/loongson1.h | 5 ++ .../include/asm/mach-loongson32/regs-clk.h | 34 +++++++++++ .../include/asm/mach-loongson32/regs-mux.h | 61 +++++++++++++++++++ arch/mips/loongson32/Kconfig | 15 +++++ arch/mips/loongson32/Makefile | 6 ++ arch/mips/loongson32/Platform | 1 + arch/mips/loongson32/common/irq.c | 55 ++++++++++++++++- arch/mips/loongson32/common/platform.c | 19 ++++++ arch/mips/loongson32/common/setup.c | 4 ++ arch/mips/loongson32/ls1c/Makefile | 5 ++ arch/mips/loongson32/ls1c/board.c | 28 +++++++++ 13 files changed, 283 insertions(+), 4 deletions(-) create mode 100644 arch/mips/loongson32/ls1c/Makefile create mode 100644 arch/mips/loongson32/ls1c/board.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 212ff92920d23..6fba0eff858e1 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1402,6 +1402,16 @@ config CPU_LOONGSON1B The Loongson 1B is a 32-bit SoC, which implements the MIPS32 release 2 instruction set. +config CPU_LOONGSON1C + bool "Loongson 1C" + depends on SYS_HAS_CPU_LOONGSON1C + select CPU_LOONGSON1 + select ARCH_WANT_OPTIONAL_GPIOLIB + select LEDS_GPIO_REGISTER + help + The Loongson 1C is a 32-bit SoC, which implements the MIPS32 + release 2 instruction set. + config CPU_MIPS32_R1 bool "MIPS32 Release 1" depends on SYS_HAS_CPU_MIPS32_R1 @@ -1851,6 +1861,9 @@ config SYS_HAS_CPU_LOONGSON2F config SYS_HAS_CPU_LOONGSON1B bool +config SYS_HAS_CPU_LOONGSON1C + bool + config SYS_HAS_CPU_MIPS32_R1 bool diff --git a/arch/mips/include/asm/mach-loongson32/irq.h b/arch/mips/include/asm/mach-loongson32/irq.h index c1c744197de49..8c01b304b7ec8 100644 --- a/arch/mips/include/asm/mach-loongson32/irq.h +++ b/arch/mips/include/asm/mach-loongson32/irq.h @@ -36,9 +36,14 @@ #define LS1X_IRQ(n, x) (LS1X_IRQ_BASE + (n << 5) + (x)) #define LS1X_UART0_IRQ LS1X_IRQ(0, 2) +#if defined(CONFIG_LOONGSON1_LS1B) #define LS1X_UART1_IRQ LS1X_IRQ(0, 3) #define LS1X_UART2_IRQ LS1X_IRQ(0, 4) #define LS1X_UART3_IRQ LS1X_IRQ(0, 5) +#elif defined(CONFIG_LOONGSON1_LS1C) +#define LS1X_UART1_IRQ LS1X_IRQ(0, 4) +#define LS1X_UART2_IRQ LS1X_IRQ(0, 5) +#endif #define LS1X_CAN0_IRQ LS1X_IRQ(0, 6) #define LS1X_CAN1_IRQ LS1X_IRQ(0, 7) #define LS1X_SPI0_IRQ LS1X_IRQ(0, 8) @@ -47,6 +52,9 @@ #define LS1X_DMA0_IRQ LS1X_IRQ(0, 13) #define LS1X_DMA1_IRQ LS1X_IRQ(0, 14) #define LS1X_DMA2_IRQ LS1X_IRQ(0, 15) +#if defined(CONFIG_LOONGSON1_LS1C) +#define LS1X_NAND_IRQ LS1X_IRQ(0, 16) +#endif #define LS1X_PWM0_IRQ LS1X_IRQ(0, 17) #define LS1X_PWM1_IRQ LS1X_IRQ(0, 18) #define LS1X_PWM2_IRQ LS1X_IRQ(0, 19) @@ -54,18 +62,49 @@ #define LS1X_RTC_INT0_IRQ LS1X_IRQ(0, 21) #define LS1X_RTC_INT1_IRQ LS1X_IRQ(0, 22) #define LS1X_RTC_INT2_IRQ LS1X_IRQ(0, 23) +#if defined(CONFIG_LOONGSON1_LS1B) #define LS1X_TOY_INT0_IRQ LS1X_IRQ(0, 24) #define LS1X_TOY_INT1_IRQ LS1X_IRQ(0, 25) #define LS1X_TOY_INT2_IRQ LS1X_IRQ(0, 26) #define LS1X_RTC_TICK_IRQ LS1X_IRQ(0, 27) #define LS1X_TOY_TICK_IRQ LS1X_IRQ(0, 28) +#define LS1X_UART4_IRQ LS1X_IRQ(0, 29) +#define LS1X_UART5_IRQ LS1X_IRQ(0, 30) +#elif defined(CONFIG_LOONGSON1_LS1C) +#define LS1X_UART3_IRQ LS1X_IRQ(0, 29) +#define LS1X_ADC_IRQ LS1X_IRQ(0, 30) +#define LS1X_SDIO_IRQ LS1X_IRQ(0, 31) +#endif #define LS1X_EHCI_IRQ LS1X_IRQ(1, 0) #define LS1X_OHCI_IRQ LS1X_IRQ(1, 1) +#if defined(CONFIG_LOONGSON1_LS1B) #define LS1X_GMAC0_IRQ LS1X_IRQ(1, 2) #define LS1X_GMAC1_IRQ LS1X_IRQ(1, 3) +#elif defined(CONFIG_LOONGSON1_LS1C) +#define LS1X_OTG_IRQ LS1X_IRQ(1, 2) +#define LS1X_GMAC0_IRQ LS1X_IRQ(1, 3) +#define LS1X_CAM_IRQ LS1X_IRQ(1, 4) +#define LS1X_UART4_IRQ LS1X_IRQ(1, 5) +#define LS1X_UART5_IRQ LS1X_IRQ(1, 6) +#define LS1X_UART6_IRQ LS1X_IRQ(1, 7) +#define LS1X_UART7_IRQ LS1X_IRQ(1, 8) +#define LS1X_UART8_IRQ LS1X_IRQ(1, 9) +#define LS1X_UART9_IRQ LS1X_IRQ(1, 13) +#define LS1X_UART10_IRQ LS1X_IRQ(1, 14) +#define LS1X_UART11_IRQ LS1X_IRQ(1, 15) +#define LS1X_I2C0_IRQ LS1X_IRQ(1, 17) +#define LS1X_I2C1_IRQ LS1X_IRQ(1, 18) +#define LS1X_I2C2_IRQ LS1X_IRQ(1, 19) +#endif -#define LS1X_IRQS (LS1X_IRQ(4, 31) + 1 - LS1X_IRQ_BASE) +#if defined(CONFIG_LOONGSON1_LS1B) +#define INTN 4 +#elif defined(CONFIG_LOONGSON1_LS1C) +#define INTN 5 +#endif + +#define LS1X_IRQS (LS1X_IRQ(INTN, 31) + 1 - LS1X_IRQ_BASE) #define NR_IRQS (MIPS_CPU_IRQS + LS1X_IRQS) diff --git a/arch/mips/include/asm/mach-loongson32/loongson1.h b/arch/mips/include/asm/mach-loongson32/loongson1.h index 978f6df8970a3..3584c40caf796 100644 --- a/arch/mips/include/asm/mach-loongson32/loongson1.h +++ b/arch/mips/include/asm/mach-loongson32/loongson1.h @@ -12,7 +12,11 @@ #ifndef __ASM_MACH_LOONGSON32_LOONGSON1_H #define __ASM_MACH_LOONGSON32_LOONGSON1_H +#if defined(CONFIG_LOONGSON1_LS1B) #define DEFAULT_MEMSIZE 256 /* If no memsize provided */ +#elif defined(CONFIG_LOONGSON1_LS1C) +#define DEFAULT_MEMSIZE 32 +#endif /* Loongson 1 Register Bases */ #define LS1X_MUX_BASE 0x1fd00420 @@ -20,6 +24,7 @@ #define LS1X_GPIO0_BASE 0x1fd010c0 #define LS1X_GPIO1_BASE 0x1fd010c4 #define LS1X_DMAC_BASE 0x1fd01160 +#define LS1X_CBUS_BASE 0x1fd011c0 #define LS1X_EHCI_BASE 0x1fe00000 #define LS1X_OHCI_BASE 0x1fe08000 #define LS1X_GMAC0_BASE 0x1fe10000 diff --git a/arch/mips/include/asm/mach-loongson32/regs-clk.h b/arch/mips/include/asm/mach-loongson32/regs-clk.h index 4d56fc38f0c47..e5e8f118f34b2 100644 --- a/arch/mips/include/asm/mach-loongson32/regs-clk.h +++ b/arch/mips/include/asm/mach-loongson32/regs-clk.h @@ -18,6 +18,7 @@ #define LS1X_CLK_PLL_FREQ LS1X_CLK_REG(0x0) #define LS1X_CLK_PLL_DIV LS1X_CLK_REG(0x4) +#if defined(CONFIG_LOONGSON1_LS1B) /* Clock PLL Divisor Register Bits */ #define DIV_DC_EN BIT(31) #define DIV_DC_RST BIT(30) @@ -48,4 +49,37 @@ #define BYPASS_DDR_WIDTH 1 #define BYPASS_CPU_WIDTH 1 +#elif defined(CONFIG_LOONGSON1_LS1C) +/* PLL/SDRAM Frequency configuration register Bits */ +#define PLL_VALID BIT(31) +#define FRAC_N GENMASK(23, 16) +#define RST_TIME GENMASK(3, 2) +#define SDRAM_DIV GENMASK(1, 0) + +/* CPU/CAMERA/DC Frequency configuration register Bits */ +#define DIV_DC_EN BIT(31) +#define DIV_DC GENMASK(30, 24) +#define DIV_CAM_EN BIT(23) +#define DIV_CAM GENMASK(22, 16) +#define DIV_CPU_EN BIT(15) +#define DIV_CPU GENMASK(14, 8) +#define DIV_DC_SEL_EN BIT(5) +#define DIV_DC_SEL BIT(4) +#define DIV_CAM_SEL_EN BIT(3) +#define DIV_CAM_SEL BIT(2) +#define DIV_CPU_SEL_EN BIT(1) +#define DIV_CPU_SEL BIT(0) + +#define DIV_DC_SHIFT 24 +#define DIV_CAM_SHIFT 16 +#define DIV_CPU_SHIFT 8 +#define DIV_DDR_SHIFT 0 + +#define DIV_DC_WIDTH 7 +#define DIV_CAM_WIDTH 7 +#define DIV_CPU_WIDTH 7 +#define DIV_DDR_WIDTH 2 + +#endif + #endif /* __ASM_MACH_LOONGSON32_REGS_CLK_H */ diff --git a/arch/mips/include/asm/mach-loongson32/regs-mux.h b/arch/mips/include/asm/mach-loongson32/regs-mux.h index 7c394f93cb9e3..4a0bdeb0eb9b9 100644 --- a/arch/mips/include/asm/mach-loongson32/regs-mux.h +++ b/arch/mips/include/asm/mach-loongson32/regs-mux.h @@ -18,6 +18,7 @@ #define LS1X_MUX_CTRL0 LS1X_MUX_REG(0x0) #define LS1X_MUX_CTRL1 LS1X_MUX_REG(0x4) +#if defined(CONFIG_LOONGSON1_LS1B) /* MUX CTRL0 Register Bits */ #define UART0_USE_PWM23 BIT(28) #define UART0_USE_PWM01 BIT(27) @@ -64,4 +65,64 @@ #define GMAC1_USE_PWM23 BIT(1) #define GMAC0_USE_PWM01 BIT(0) +#elif defined(CONFIG_LOONGSON1_LS1C) + +/* SHUT_CTRL Register Bits */ +#define UART_SPLIT GENMASK(31, 30) +#define OUTPUT_CLK GENMASK(29, 26) +#define ADC_SHUT BIT(25) +#define SDIO_SHUT BIT(24) +#define DMA2_SHUT BIT(23) +#define DMA1_SHUT BIT(22) +#define DMA0_SHUT BIT(21) +#define SPI1_SHUT BIT(20) +#define SPI0_SHUT BIT(19) +#define I2C2_SHUT BIT(18) +#define I2C1_SHUT BIT(17) +#define I2C0_SHUT BIT(16) +#define AC97_SHUT BIT(15) +#define I2S_SHUT BIT(14) +#define UART3_SHUT BIT(13) +#define UART2_SHUT BIT(12) +#define UART1_SHUT BIT(11) +#define UART0_SHUT BIT(10) +#define CAN1_SHUT BIT(9) +#define CAN0_SHUT BIT(8) +#define ECC_SHUT BIT(7) +#define GMAC_SHUT BIT(6) +#define USBHOST_SHUT BIT(5) +#define USBOTG_SHUT BIT(4) +#define SDRAM_SHUT BIT(3) +#define SRAM_SHUT BIT(2) +#define CAM_SHUT BIT(1) +#define LCD_SHUT BIT(0) + +#define UART_SPLIT_SHIFT 30 +#define OUTPUT_CLK_SHIFT 26 + +/* MISC_CTRL Register Bits */ +#define USBHOST_RSTN BIT(31) +#define PHY_INTF_SELI GENMASK(30, 28) +#define AC97_EN BIT(25) +#define SDIO_DMA_EN GENMASK(24, 23) +#define ADC_DMA_EN BIT(22) +#define SDIO_USE_SPI1 BIT(17) +#define SDIO_USE_SPI0 BIT(16) +#define SRAM_CTRL GENMASK(15, 0) + +#define PHY_INTF_SELI_SHIFT 28 +#define SDIO_DMA_EN_SHIFT 23 +#define SRAM_CTRL_SHIFT 0 + +#define LS1X_CBUS_REG(n, x) \ + ((void __iomem *)KSEG1ADDR(LS1X_CBUS_BASE + (n * 0x04) + (x))) + +#define LS1X_CBUS_FIRST(n) LS1X_CBUS_REG(n, 0x00) +#define LS1X_CBUS_SECOND(n) LS1X_CBUS_REG(n, 0x10) +#define LS1X_CBUS_THIRD(n) LS1X_CBUS_REG(n, 0x20) +#define LS1X_CBUS_FOURTHT(n) LS1X_CBUS_REG(n, 0x30) +#define LS1X_CBUS_FIFTHT(n) LS1X_CBUS_REG(n, 0x40) + +#endif + #endif /* __ASM_MACH_LOONGSON32_REGS_MUX_H */ diff --git a/arch/mips/loongson32/Kconfig b/arch/mips/loongson32/Kconfig index 7704f20529d63..3c0c2f2096cd8 100644 --- a/arch/mips/loongson32/Kconfig +++ b/arch/mips/loongson32/Kconfig @@ -19,6 +19,21 @@ config LOONGSON1_LS1B select USE_GENERIC_EARLY_PRINTK_8250 select COMMON_CLK +config LOONGSON1_LS1C + bool "Loongson LS1C board" + select CEVT_R4K if !MIPS_EXTERNAL_TIMER + select CSRC_R4K if !MIPS_EXTERNAL_TIMER + select SYS_HAS_CPU_LOONGSON1C + select DMA_NONCOHERENT + select BOOT_ELF32 + select IRQ_MIPS_CPU + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_HIGHMEM + select SYS_SUPPORTS_MIPS16 + select SYS_HAS_EARLY_PRINTK + select USE_GENERIC_EARLY_PRINTK_8250 + select COMMON_CLK endchoice menuconfig CEVT_CSRC_LS1X diff --git a/arch/mips/loongson32/Makefile b/arch/mips/loongson32/Makefile index 5f4bd6e071ca0..1ab2c5bbc0660 100644 --- a/arch/mips/loongson32/Makefile +++ b/arch/mips/loongson32/Makefile @@ -9,3 +9,9 @@ obj-$(CONFIG_MACH_LOONGSON32) += common/ # obj-$(CONFIG_LOONGSON1_LS1B) += ls1b/ + +# +# Loongson LS1C board +# + +obj-$(CONFIG_LOONGSON1_LS1C) += ls1c/ diff --git a/arch/mips/loongson32/Platform b/arch/mips/loongson32/Platform index ebb6dc290f0ab..ffe01c6d0037d 100644 --- a/arch/mips/loongson32/Platform +++ b/arch/mips/loongson32/Platform @@ -5,3 +5,4 @@ cflags-$(CONFIG_CPU_LOONGSON1) += \ platform-$(CONFIG_MACH_LOONGSON32) += loongson32/ cflags-$(CONFIG_MACH_LOONGSON32) += -I$(srctree)/arch/mips/include/asm/mach-loongson32 load-$(CONFIG_LOONGSON1_LS1B) += 0xffffffff80100000 +load-$(CONFIG_LOONGSON1_LS1C) += 0xffffffff80100000 diff --git a/arch/mips/loongson32/common/irq.c b/arch/mips/loongson32/common/irq.c index 455a7704a90f9..635a4abe1f482 100644 --- a/arch/mips/loongson32/common/irq.c +++ b/arch/mips/loongson32/common/irq.c @@ -62,12 +62,58 @@ static void ls1x_irq_unmask(struct irq_data *d) | (1 << bit), LS1X_INTC_INTIEN(n)); } +static int ls1x_irq_settype(struct irq_data *d, unsigned int type) +{ + unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; + unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; + + switch (type) { + case IRQ_TYPE_LEVEL_HIGH: + __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) + | (1 << bit), LS1X_INTC_INTPOL(n)); + __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) + & ~(1 << bit), LS1X_INTC_INTEDGE(n)); + break; + case IRQ_TYPE_LEVEL_LOW: + __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) + & ~(1 << bit), LS1X_INTC_INTPOL(n)); + __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) + & ~(1 << bit), LS1X_INTC_INTEDGE(n)); + break; + case IRQ_TYPE_EDGE_RISING: + __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) + | (1 << bit), LS1X_INTC_INTPOL(n)); + __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) + | (1 << bit), LS1X_INTC_INTEDGE(n)); + break; + case IRQ_TYPE_EDGE_FALLING: + __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) + & ~(1 << bit), LS1X_INTC_INTPOL(n)); + __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) + | (1 << bit), LS1X_INTC_INTEDGE(n)); + break; + case IRQ_TYPE_EDGE_BOTH: + __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) + & ~(1 << bit), LS1X_INTC_INTPOL(n)); + __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) + | (1 << bit), LS1X_INTC_INTEDGE(n)); + break; + case IRQ_TYPE_NONE: + break; + default: + return -EINVAL; + } + + return 0; +} + static struct irq_chip ls1x_irq_chip = { .name = "LS1X-INTC", .irq_ack = ls1x_irq_ack, .irq_mask = ls1x_irq_mask, .irq_mask_ack = ls1x_irq_mask_ack, .irq_unmask = ls1x_irq_unmask, + .irq_set_type = ls1x_irq_settype, }; static void ls1x_irq_dispatch(int n) @@ -107,7 +153,7 @@ asmlinkage void plat_irq_dispatch(void) } -struct irqaction cascade_irqaction = { +static struct irqaction cascade_irqaction = { .handler = no_action, .name = "cascade", .flags = IRQF_NO_THREAD, @@ -120,7 +166,7 @@ static void __init ls1x_irq_init(int base) /* Disable interrupts and clear pending, * setup all IRQs as high level triggered */ - for (n = 0; n < 4; n++) { + for (n = 0; n < INTN; n++) { __raw_writel(0x0, LS1X_INTC_INTIEN(n)); __raw_writel(0xffffffff, LS1X_INTC_INTCLR(n)); __raw_writel(0xffffffff, LS1X_INTC_INTPOL(n)); @@ -129,7 +175,7 @@ static void __init ls1x_irq_init(int base) } - for (n = base; n < LS1X_IRQS; n++) { + for (n = base; n < NR_IRQS; n++) { irq_set_chip_and_handler(n, &ls1x_irq_chip, handle_level_irq); } @@ -138,6 +184,9 @@ static void __init ls1x_irq_init(int base) setup_irq(INT1_IRQ, &cascade_irqaction); setup_irq(INT2_IRQ, &cascade_irqaction); setup_irq(INT3_IRQ, &cascade_irqaction); +#if defined(CONFIG_LOONGSON1_LS1C) + setup_irq(INT4_IRQ, &cascade_irqaction); +#endif } void __init arch_init_irq(void) diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c index f2c714d8fb60c..4d12e365dcb01 100644 --- a/arch/mips/loongson32/common/platform.c +++ b/arch/mips/loongson32/common/platform.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -132,6 +133,7 @@ int ls1x_eth_mux_init(struct platform_device *pdev, void *priv) val = __raw_readl(LS1X_MUX_CTRL1); +#if defined(CONFIG_LOONGSON1_LS1B) plat_dat = dev_get_platdata(&pdev->dev); if (plat_dat->bus_id) { __raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 | @@ -165,6 +167,17 @@ int ls1x_eth_mux_init(struct platform_device *pdev, void *priv) val &= ~GMAC0_SHUT; } __raw_writel(val, LS1X_MUX_CTRL1); +#elif defined(CONFIG_LOONGSON1_LS1C) + plat_dat = dev_get_platdata(&pdev->dev); + + val &= ~PHY_INTF_SELI; + if (plat_dat->interface == PHY_INTERFACE_MODE_RMII) + val |= 0x4 << PHY_INTF_SELI_SHIFT; + __raw_writel(val, LS1X_MUX_CTRL1); + + val = __raw_readl(LS1X_MUX_CTRL0); + __raw_writel(val & (~GMAC_SHUT), LS1X_MUX_CTRL0); +#endif return 0; } @@ -172,7 +185,11 @@ int ls1x_eth_mux_init(struct platform_device *pdev, void *priv) static struct plat_stmmacenet_data ls1x_eth0_pdata = { .bus_id = 0, .phy_addr = -1, +#if defined(CONFIG_LOONGSON1_LS1B) .interface = PHY_INTERFACE_MODE_MII, +#elif defined(CONFIG_LOONGSON1_LS1C) + .interface = PHY_INTERFACE_MODE_RMII, +#endif .mdio_bus_data = &ls1x_mdio_bus_data, .dma_cfg = &ls1x_eth_dma_cfg, .has_gmac = 1, @@ -203,6 +220,7 @@ struct platform_device ls1x_eth0_pdev = { }, }; +#ifdef CONFIG_LOONGSON1_LS1B static struct plat_stmmacenet_data ls1x_eth1_pdata = { .bus_id = 1, .phy_addr = -1, @@ -236,6 +254,7 @@ struct platform_device ls1x_eth1_pdev = { .platform_data = &ls1x_eth1_pdata, }, }; +#endif /* CONFIG_LOONGSON1_LS1B */ /* GPIO */ static struct resource ls1x_gpio0_resources[] = { diff --git a/arch/mips/loongson32/common/setup.c b/arch/mips/loongson32/common/setup.c index 62f41afee241e..1640744288ee0 100644 --- a/arch/mips/loongson32/common/setup.c +++ b/arch/mips/loongson32/common/setup.c @@ -22,7 +22,11 @@ const char *get_system_type(void) switch (processor_id & PRID_REV_MASK) { case PRID_REV_LOONGSON1B: +#if defined(CONFIG_LOONGSON1_LS1B) return "LOONGSON LS1B"; +#elif defined(CONFIG_LOONGSON1_LS1C) + return "LOONGSON LS1C"; +#endif default: return "LOONGSON (unknown)"; } diff --git a/arch/mips/loongson32/ls1c/Makefile b/arch/mips/loongson32/ls1c/Makefile new file mode 100644 index 0000000000000..891eac482b828 --- /dev/null +++ b/arch/mips/loongson32/ls1c/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for loongson1B based machines. +# + +obj-y += board.o diff --git a/arch/mips/loongson32/ls1c/board.c b/arch/mips/loongson32/ls1c/board.c new file mode 100644 index 0000000000000..3d69bd63ad564 --- /dev/null +++ b/arch/mips/loongson32/ls1c/board.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016 Ling Yang + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include + +static struct platform_device *ls1c_platform_devices[] __initdata = { + &ls1x_uart_pdev, + &ls1x_eth0_pdev, +}; + +static int __init ls1c_platform_init(void) +{ + int err; + + ls1x_serial_set_uartclk(&ls1x_uart_pdev); + + err = platform_add_devices(ls1c_platform_devices, + ARRAY_SIZE(ls1c_platform_devices)); + return err; +} + +arch_initcall(ls1c_platform_init); -- GitLab From 5b9a15e891b80d0ea8bdb1bb571d01af83839803 Mon Sep 17 00:00:00 2001 From: Yang Ling Date: Thu, 19 May 2016 12:31:57 +0800 Subject: [PATCH 0212/1167] MIPS: Loongson1C: Add defconfig Signed-off-by: Yang Ling Cc: keguang.zhang@gmail.com Cc: chenhc@lemote.com Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13305/ Signed-off-by: Ralf Baechle --- arch/mips/configs/loongson1c_defconfig | 126 +++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 arch/mips/configs/loongson1c_defconfig diff --git a/arch/mips/configs/loongson1c_defconfig b/arch/mips/configs/loongson1c_defconfig new file mode 100644 index 0000000000000..2304d41657730 --- /dev/null +++ b/arch/mips/configs/loongson1c_defconfig @@ -0,0 +1,126 @@ +CONFIG_MACH_LOONGSON32=y +CONFIG_LOONGSON1_LS1C=y +CONFIG_PREEMPT=y +# CONFIG_SECCOMP is not set +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_XZ=y +CONFIG_SYSVIPC=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_NAMESPACES=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EXPERT=y +CONFIG_PERF_EVENTS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_LBDAF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_SUSPEND is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_DIAG is not set +# CONFIG_IPV6 is not set +# CONFIG_WIRELESS is not set +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_LOONGSON1=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_SCSI=m +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=m +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +CONFIG_STMMAC_ETH=y +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_WLAN is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_LEGACY_PTY_COUNT=8 +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_HW_RANDOM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIO_LOONGSON1=y +# CONFIG_HWMON is not set +# CONFIG_VGA_CONSOLE is not set +CONFIG_HID_GENERIC=m +CONFIG_USB_HID=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_LOONGSON1=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_DNOTIFY is not set +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_UBIFS_ATIME_SUPPORT=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_ISO8859_1=m +CONFIG_DYNAMIC_DEBUG=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set +# CONFIG_EARLY_PRINTK is not set +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_HW is not set -- GitLab From 765b06479a47529336458598809d29d59b40ab65 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Thu, 4 Aug 2016 17:19:38 +0100 Subject: [PATCH 0213/1167] MIPS: Move identification of VP(E) into proc.c from smp-mt.c The addition of VPE information to /proc/cpuinfo used to be in smp-mt.c. This file is not used by MIPS r6 kernels, so the Virtual Processor information was not present for these CPU types. Move the code to print VPE information into proc.c, add a case for MIPS r6 CPUS, and remove the block from smp-mt.c. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Qais Yousef Cc: Zubair Lutfullah Kakakhel Cc: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13847/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/proc.c | 7 +++++++ arch/mips/kernel/smp-mt.c | 23 ----------------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 97dc01b036311..4eff2aed73601 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -135,6 +135,13 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "package\t\t\t: %d\n", cpu_data[n].package); seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) + if (cpu_has_mipsmt) + seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id); + else if (cpu_has_vp) + seq_printf(m, "VP\t\t\t: %d\n", cpu_data[n].vpe_id); +#endif + sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", cpu_has_vce ? "%u" : "not available"); seq_printf(m, fmt, 'D', vced_count); diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 4f9570a57e8d8..e077ea3e11fb3 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -289,26 +289,3 @@ struct plat_smp_ops vsmp_smp_ops = { .prepare_cpus = vsmp_prepare_cpus, }; -#ifdef CONFIG_PROC_FS -static int proc_cpuinfo_chain_call(struct notifier_block *nfb, - unsigned long action_unused, void *data) -{ - struct proc_cpuinfo_notifier_args *pcn = data; - struct seq_file *m = pcn->m; - unsigned long n = pcn->n; - - if (!cpu_has_mipsmt) - return NOTIFY_OK; - - seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id); - - return NOTIFY_OK; -} - -static int __init proc_cpuinfo_notifier_init(void) -{ - return proc_cpuinfo_notifier(proc_cpuinfo_chain_call, 0); -} - -subsys_initcall(proc_cpuinfo_notifier_init); -#endif -- GitLab From 94a2de0fdb3466f92694fcff7e494344c2a744ea Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 15 Aug 2016 19:29:09 +0200 Subject: [PATCH 0214/1167] MIPS: pci-mt7620: Delete unnecessary assignment for the field "owner" The field "owner" is set by the core. Thus delete an unneeded initialisation. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Markus Elfring Cc: John Crispin Cc: Matthias Brugger Cc: Julia Lawall Cc: Wei Yongjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-mediatek@lists.infradead.org Cc: linux-mips@linux-mips.org Cc: LKML Cc: kernel-janitors@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13929/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-mt7620.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/pci/pci-mt7620.c b/arch/mips/pci/pci-mt7620.c index 6ce8162016995..eb39826a62c3b 100644 --- a/arch/mips/pci/pci-mt7620.c +++ b/arch/mips/pci/pci-mt7620.c @@ -413,7 +413,6 @@ static struct platform_driver mt7620_pci_driver = { .probe = mt7620_pci_probe, .driver = { .name = "mt7620-pci", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(mt7620_pci_ids), }, }; -- GitLab From f715677f8f130967c34ee915e13e4bf2c924c64a Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 12 Aug 2016 23:59:19 +0200 Subject: [PATCH 0215/1167] MIPS: pistachio: Remove ANDROID_TIMED_OUTPUT from defconfig. According to commit 9f6b68774f29 ("android: remove timed output/gpio driver") Signed-off-by: Fabian Frederick Cc: Rob Herring Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13904/ Signed-off-by: Ralf Baechle --- arch/mips/configs/pistachio_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/configs/pistachio_defconfig b/arch/mips/configs/pistachio_defconfig index 698631327c8c6..7d32fbbca9626 100644 --- a/arch/mips/configs/pistachio_defconfig +++ b/arch/mips/configs/pistachio_defconfig @@ -263,7 +263,6 @@ CONFIG_DMADEVICES=y CONFIG_IMG_MDC_DMA=y CONFIG_STAGING=y CONFIG_ASHMEM=y -# CONFIG_ANDROID_TIMED_OUTPUT is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_MEMORY=y CONFIG_IIO=y -- GitLab From d2b965b24895bbeb9c3da59da64eaa67d2d54cc3 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 10 Aug 2016 17:11:03 +0100 Subject: [PATCH 0216/1167] MIPS: Delete unused file smp-gic.c Commit 7eb8c99db26c ("MIPS: Delete smp-gic.c") removed the file from the Makefile and the option to build it from KConfig, but left the file itself floating in the tree. Remove the unused source file. Signed-off-by: Matt Redfearn Cc: Qais Yousef Cc: paul.burton@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13883/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp-gic.c | 66 -------------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 arch/mips/kernel/smp-gic.c diff --git a/arch/mips/kernel/smp-gic.c b/arch/mips/kernel/smp-gic.c deleted file mode 100644 index 9b63829cf9294..0000000000000 --- a/arch/mips/kernel/smp-gic.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2013 Imagination Technologies - * Author: Paul Burton - * - * Based on smp-cmp.c: - * Copyright (C) 2007 MIPS Technologies, Inc. - * Author: Chris Dearman (chris@mips.com) - * - * 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; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include - -#include -#include - -void gic_send_ipi_single(int cpu, unsigned int action) -{ - unsigned long flags; - unsigned int intr; - unsigned int core = cpu_data[cpu].core; - - pr_debug("CPU%d: %s cpu %d action %u status %08x\n", - smp_processor_id(), __func__, cpu, action, read_c0_status()); - - local_irq_save(flags); - - switch (action) { - case SMP_CALL_FUNCTION: - intr = plat_ipi_call_int_xlate(cpu); - break; - - case SMP_RESCHEDULE_YOURSELF: - intr = plat_ipi_resched_int_xlate(cpu); - break; - - default: - BUG(); - } - - gic_send_ipi(intr); - - if (mips_cpc_present() && (core != current_cpu_data.core)) { - while (!cpumask_test_cpu(cpu, &cpu_coherent_mask)) { - mips_cm_lock_other(core, 0); - mips_cpc_lock_other(core); - write_cpc_co_cmd(CPC_Cx_CMD_PWRUP); - mips_cpc_unlock_other(); - mips_cm_unlock_other(); - } - } - - local_irq_restore(flags); -} - -void gic_send_ipi_mask(const struct cpumask *mask, unsigned int action) -{ - unsigned int i; - - for_each_cpu(i, mask) - gic_send_ipi_single(i, action); -} -- GitLab From 191084bca8312956cc96f5ef471416c8bc08cef7 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 15 Aug 2016 16:30:52 -0400 Subject: [PATCH 0217/1167] MIPS: BCM47xx: Make serial explicitly non-modular MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Makefile entry controlling compilation of this code is "obj-y" meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modular infrastructure use, so that when reading the driver there is no doubt it is builtin-only. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Signed-off-by: Paul Gortmaker Cc: Hauke Mehrtens Cc: "Rafał Miłecki" Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13933/ Signed-off-by: Ralf Baechle --- arch/mips/bcm47xx/serial.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c index df761d38f7fc9..e3c9872a4aa5d 100644 --- a/arch/mips/bcm47xx/serial.c +++ b/arch/mips/bcm47xx/serial.c @@ -1,4 +1,7 @@ /* + * 8250 UART probe driver for the BCM47XX platforms + * Author: Aurelien Jarno + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -6,7 +9,6 @@ * Copyright (C) 2007 Aurelien Jarno */ -#include #include #include #include @@ -88,9 +90,4 @@ static int __init uart8250_init(void) } return -EINVAL; } - -module_init(uart8250_init); - -MODULE_AUTHOR("Aurelien Jarno "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("8250 UART probe driver for the BCM47XX platforms"); +device_initcall(uart8250_init); -- GitLab From 62ee73d284e796d6df292b3df8c65e63a78a11a7 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 15 Aug 2016 16:30:53 -0400 Subject: [PATCH 0218/1167] MIPS: ralink: Make timer explicitly non-modular The Makefile entry controlling compilation of this code is "obj-y" meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. We don't replace module.h with init.h since the file already has that. Signed-off-by: Paul Gortmaker Cc: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13931/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/timer.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c index b0343ff336c5f..8077ff39bdeab 100644 --- a/arch/mips/ralink/timer.c +++ b/arch/mips/ralink/timer.c @@ -1,4 +1,7 @@ /* + * Ralink RT2880 timer + * Author: John Crispin + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. @@ -6,7 +9,6 @@ * Copyright (C) 2013 John Crispin */ -#include #include #include #include @@ -152,33 +154,17 @@ static int rt_timer_probe(struct platform_device *pdev) return 0; } -static int rt_timer_remove(struct platform_device *pdev) -{ - struct rt_timer *rt = platform_get_drvdata(pdev); - - rt_timer_disable(rt); - rt_timer_free(rt); - - return 0; -} - static const struct of_device_id rt_timer_match[] = { { .compatible = "ralink,rt2880-timer" }, {}, }; -MODULE_DEVICE_TABLE(of, rt_timer_match); static struct platform_driver rt_timer_driver = { .probe = rt_timer_probe, - .remove = rt_timer_remove, .driver = { - .name = "rt-timer", - .of_match_table = rt_timer_match + .name = "rt-timer", + .of_match_table = rt_timer_match, + .suppress_bind_attrs = true, }, }; - -module_platform_driver(rt_timer_driver); - -MODULE_DESCRIPTION("Ralink RT2880 timer"); -MODULE_AUTHOR("John Crispin Date: Mon, 15 Aug 2016 16:30:54 -0400 Subject: [PATCH 0219/1167] MIPS: Lantiq: Make vmmc explicitly non-modular The Makefile entry controlling compilation of this code is: arch/mips/lantiq/xway/vmmc.o ---> arch/mips/lantiq/xway/Makefile:obj-y += vmmc.o ...meaning that it currently is not being built as a module by anyone. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We replace module.h with export.h since the file does actually use EXPORT_SYMBOL. Signed-off-by: Paul Gortmaker Cc: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13930/ Signed-off-by: Ralf Baechle --- arch/mips/lantiq/xway/vmmc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/mips/lantiq/xway/vmmc.c b/arch/mips/lantiq/xway/vmmc.c index 4625495f9230a..577ec81b557dc 100644 --- a/arch/mips/lantiq/xway/vmmc.c +++ b/arch/mips/lantiq/xway/vmmc.c @@ -6,7 +6,7 @@ * Copyright (C) 2012 John Crispin */ -#include +#include #include #include #include @@ -55,7 +55,6 @@ static const struct of_device_id vmmc_match[] = { { .compatible = "lantiq,vmmc-xway" }, {}, }; -MODULE_DEVICE_TABLE(of, vmmc_match); static struct platform_driver vmmc_driver = { .probe = vmmc_probe, @@ -64,5 +63,4 @@ static struct platform_driver vmmc_driver = { .of_match_table = vmmc_match, }, }; - -module_platform_driver(vmmc_driver); +builtin_platform_driver(vmmc_driver); -- GitLab From 6f42e0e384d64b5cd308fa319c6c57044f144eca Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 15 Aug 2016 16:30:55 -0400 Subject: [PATCH 0220/1167] MIPS: Lantiq: Make xrx200_phy_fw explicitly non-modular The Kconfig currently controlling compilation of this code is: arch/mips/lantiq/Kconfig:config XRX200_PHY_FW arch/mips/lantiq/Kconfig: bool "XRX200 PHY firmware loader" ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modular infrastructure use, so that when reading the driver there is no doubt it is builtin-only. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. We don't replace module.h with init.h since the file doesn't need that. Signed-off-by: Paul Gortmaker Cc: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13932/ Signed-off-by: Ralf Baechle --- arch/mips/lantiq/xway/xrx200_phy_fw.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/mips/lantiq/xway/xrx200_phy_fw.c b/arch/mips/lantiq/xway/xrx200_phy_fw.c index 71e518c1e7e75..f0a0f2d431b23 100644 --- a/arch/mips/lantiq/xway/xrx200_phy_fw.c +++ b/arch/mips/lantiq/xway/xrx200_phy_fw.c @@ -1,4 +1,7 @@ /* + * Lantiq XRX200 PHY Firmware Loader + * Author: John Crispin + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. @@ -8,7 +11,6 @@ #include #include -#include #include #include @@ -100,7 +102,6 @@ static const struct of_device_id xway_phy_match[] = { { .compatible = "lantiq,phy-xrx200" }, {}, }; -MODULE_DEVICE_TABLE(of, xway_phy_match); static struct platform_driver xway_phy_driver = { .probe = xway_phy_fw_probe, @@ -109,9 +110,4 @@ static struct platform_driver xway_phy_driver = { .of_match_table = xway_phy_match, }, }; - -module_platform_driver(xway_phy_driver); - -MODULE_AUTHOR("John Crispin "); -MODULE_DESCRIPTION("Lantiq XRX200 PHY Firmware Loader"); -MODULE_LICENSE("GPL"); +builtin_platform_driver(xway_phy_driver); -- GitLab From 9f3b8081a4763022ccfabaffc485094be0064fa4 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 15 Aug 2016 19:11:52 -0400 Subject: [PATCH 0221/1167] MIPS: Migrate exception table users off module.h and onto extable.h These files were only including module.h for exception table related functions. We've now separated that content out into its own file "extable.h" so now move over to that and avoid all the extra header content in module.h that we don't really need to compile these files. In the case of traps.c we can't dump the module.h include since it is also used to provide "print_modules". Signed-off-by: Paul Gortmaker Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13934/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/module.c | 1 + arch/mips/kernel/traps.c | 1 + arch/mips/mm/extable.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index 79850e376ef63..94627a3a6a0d9 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c @@ -20,6 +20,7 @@ #undef DEBUG +#include #include #include #include diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 3de85be2486a4..6061d47c57c9c 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/mm/extable.c b/arch/mips/mm/extable.c index 9d25d2ba4b9ea..e474fa2efed49 100644 --- a/arch/mips/mm/extable.c +++ b/arch/mips/mm/extable.c @@ -5,7 +5,7 @@ * * Copyright (C) 1997, 99, 2001 - 2004 Ralf Baechle */ -#include +#include #include #include #include -- GitLab From 60219c563c9b62aac237631a7c9aa092e8396138 Mon Sep 17 00:00:00 2001 From: Yang Ling Date: Tue, 6 Sep 2016 10:11:38 +0800 Subject: [PATCH 0222/1167] MIPS: Add RTC support for Loongson1C board The patch adds RTC support for Loongson1C board, and enable the external crystal when the RTC is first powered up. Signed-off-by: Yang Ling Cc: keguang.zhang@gmail.com Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14214/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-loongson32/platform.h | 1 + arch/mips/loongson32/common/platform.c | 13 +++++++++++++ arch/mips/loongson32/ls1c/Makefile | 2 +- arch/mips/loongson32/ls1c/board.c | 9 ++++----- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/asm/mach-loongson32/platform.h b/arch/mips/include/asm/mach-loongson32/platform.h index 672531aa9bef0..7adc313649395 100644 --- a/arch/mips/include/asm/mach-loongson32/platform.h +++ b/arch/mips/include/asm/mach-loongson32/platform.h @@ -30,5 +30,6 @@ void __init ls1x_clk_init(void); void __init ls1x_dma_set_platdata(struct plat_ls1x_dma *pdata); void __init ls1x_nand_set_platdata(struct plat_ls1x_nand *pdata); void __init ls1x_serial_set_uartclk(struct platform_device *pdev); +void __init ls1x_rtc_set_extclk(struct platform_device *pdev); #endif /* __ASM_MACH_LOONGSON32_PLATFORM_H */ diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c index 4d12e365dcb01..beff0852c6a47 100644 --- a/arch/mips/loongson32/common/platform.c +++ b/arch/mips/loongson32/common/platform.c @@ -23,6 +23,10 @@ #include #include +#define LS1X_RTC_CTRL ((void __iomem *)KSEG1ADDR(LS1X_RTC_BASE + 0x40)) +#define RTC_EXTCLK_OK (BIT(5) | BIT(8)) +#define RTC_EXTCLK_EN BIT(8) + /* 8250/16550 compatible UART */ #define LS1X_UART(_id) \ { \ @@ -66,6 +70,15 @@ void __init ls1x_serial_set_uartclk(struct platform_device *pdev) p->uartclk = clk_get_rate(clk); } +void __init ls1x_rtc_set_extclk(struct platform_device *pdev) +{ + u32 val; + + val = __raw_readl(LS1X_RTC_CTRL); + if (!(val & RTC_EXTCLK_OK)) + __raw_writel(val | RTC_EXTCLK_EN, LS1X_RTC_CTRL); +} + /* CPUFreq */ static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = { .clk_name = "cpu_clk", diff --git a/arch/mips/loongson32/ls1c/Makefile b/arch/mips/loongson32/ls1c/Makefile index 891eac482b828..a92c6cd3418d7 100644 --- a/arch/mips/loongson32/ls1c/Makefile +++ b/arch/mips/loongson32/ls1c/Makefile @@ -1,5 +1,5 @@ # -# Makefile for loongson1B based machines. +# Makefile for loongson1C based machines. # obj-y += board.o diff --git a/arch/mips/loongson32/ls1c/board.c b/arch/mips/loongson32/ls1c/board.c index 3d69bd63ad564..a96bed5e3ea60 100644 --- a/arch/mips/loongson32/ls1c/board.c +++ b/arch/mips/loongson32/ls1c/board.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Ling Yang + * Copyright (c) 2016 Yang Ling * * 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 @@ -12,17 +12,16 @@ static struct platform_device *ls1c_platform_devices[] __initdata = { &ls1x_uart_pdev, &ls1x_eth0_pdev, + &ls1x_rtc_pdev, }; static int __init ls1c_platform_init(void) { - int err; - ls1x_serial_set_uartclk(&ls1x_uart_pdev); + ls1x_rtc_set_extclk(&ls1x_rtc_pdev); - err = platform_add_devices(ls1c_platform_devices, + return platform_add_devices(ls1c_platform_devices, ARRAY_SIZE(ls1c_platform_devices)); - return err; } arch_initcall(ls1c_platform_init); -- GitLab From db19462bb7acddd0a9881d75d960974982a454b8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 15 Sep 2016 00:31:01 +0900 Subject: [PATCH 0223/1167] MIPS: Squash lines for simple wrapper functions Remove unneeded variables and assignments. Signed-off-by: Masahiro Yamada Cc: Boris Brezillon Cc: Brian Norris Cc: Michal Hocko Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14260/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-generic/floppy.h | 6 +----- arch/mips/include/asm/pgalloc.h | 6 +----- arch/mips/mti-malta/malta-platform.c | 8 +------- arch/mips/pnx833x/common/platform.c | 8 ++------ 4 files changed, 5 insertions(+), 23 deletions(-) diff --git a/arch/mips/include/asm/mach-generic/floppy.h b/arch/mips/include/asm/mach-generic/floppy.h index e2561d99a3fea..9ec2f6a5200b6 100644 --- a/arch/mips/include/asm/mach-generic/floppy.h +++ b/arch/mips/include/asm/mach-generic/floppy.h @@ -115,11 +115,7 @@ static inline unsigned long fd_getfdaddr1(void) static inline unsigned long fd_dma_mem_alloc(unsigned long size) { - unsigned long mem; - - mem = __get_dma_pages(GFP_KERNEL, get_order(size)); - - return mem; + return __get_dma_pages(GFP_KERNEL, get_order(size)); } static inline void fd_dma_mem_free(unsigned long addr, unsigned long size) diff --git a/arch/mips/include/asm/pgalloc.h b/arch/mips/include/asm/pgalloc.h index 93c079a1cfc8e..a03e86969f78a 100644 --- a/arch/mips/include/asm/pgalloc.h +++ b/arch/mips/include/asm/pgalloc.h @@ -67,11 +67,7 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) { - pte_t *pte; - - pte = (pte_t *) __get_free_pages(GFP_KERNEL|__GFP_ZERO, PTE_ORDER); - - return pte; + return (pte_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, PTE_ORDER); } static inline struct page *pte_alloc_one(struct mm_struct *mm, diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c index e1dd1c1d3fdee..20a53e73b28ec 100644 --- a/arch/mips/mti-malta/malta-platform.c +++ b/arch/mips/mti-malta/malta-platform.c @@ -135,13 +135,7 @@ static struct platform_device *malta_devices[] __initdata = { static int __init malta_add_devices(void) { - int err; - - err = platform_add_devices(malta_devices, ARRAY_SIZE(malta_devices)); - if (err) - return err; - - return 0; + return platform_add_devices(malta_devices, ARRAY_SIZE(malta_devices)); } device_initcall(malta_add_devices); diff --git a/arch/mips/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c index 3cd357737a267..7cf4eb50fc721 100644 --- a/arch/mips/pnx833x/common/platform.c +++ b/arch/mips/pnx833x/common/platform.c @@ -232,12 +232,8 @@ static struct platform_device *pnx833x_platform_devices[] __initdata = { static int __init pnx833x_platform_init(void) { - int res; - - res = platform_add_devices(pnx833x_platform_devices, - ARRAY_SIZE(pnx833x_platform_devices)); - - return res; + return platform_add_devices(pnx833x_platform_devices, + ARRAY_SIZE(pnx833x_platform_devices)); } arch_initcall(pnx833x_platform_init); -- GitLab From 561eca4990557b684605090fe6a2f50cecec34e1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 18 Aug 2016 14:57:47 +0200 Subject: [PATCH 0224/1167] MIPS: TXx9: tx39xx: Move GPIO setup from .mem_setup() to .arch_init() txx9_gpio_init() calls gpiochip_add_data(), which fails with -ENOMEM as it is called too early in the boot process. This causes all subsequent GPIO operations to fail silently. Postpone all GPIO setup to .arch_init() time to fix this. Suggested-by: Atsushi Nemoto Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Cc: linux-mips@linux-mips.org Cc: linux-gpio@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13967/ Signed-off-by: Ralf Baechle --- arch/mips/txx9/generic/setup_tx3927.c | 1 - arch/mips/txx9/jmr3927/setup.c | 11 +++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/mips/txx9/generic/setup_tx3927.c b/arch/mips/txx9/generic/setup_tx3927.c index 110e05c3eb8fb..d3b83a92cf26c 100644 --- a/arch/mips/txx9/generic/setup_tx3927.c +++ b/arch/mips/txx9/generic/setup_tx3927.c @@ -92,7 +92,6 @@ void __init tx3927_setup(void) /* PIO */ __raw_writel(0, &tx3927_pioptr->maskcpu); __raw_writel(0, &tx3927_pioptr->maskext); - txx9_gpio_init(TX3927_PIO_REG, 0, 16); conf = read_c0_conf(); if (conf & TX39_CONF_DCE) { diff --git a/arch/mips/txx9/jmr3927/setup.c b/arch/mips/txx9/jmr3927/setup.c index 3206f76f300b7..a455166dc6d44 100644 --- a/arch/mips/txx9/jmr3927/setup.c +++ b/arch/mips/txx9/jmr3927/setup.c @@ -142,8 +142,6 @@ static void __init jmr3927_board_init(void) /* PIO[15:12] connected to LEDs */ __raw_writel(0x0000f000, &tx3927_pioptr->dir); - gpio_request(11, "dipsw1"); - gpio_request(10, "dipsw2"); jmr3927_pci_setup(); @@ -204,6 +202,14 @@ static void __init jmr3927_device_init(void) txx9_iocled_init(iocled_base, -1, 8, 1, "green", NULL); } +static void __init jmr3927_arch_init(void) +{ + txx9_gpio_init(TX3927_PIO_REG, 0, 16); + + gpio_request(11, "dipsw1"); + gpio_request(10, "dipsw2"); +} + struct txx9_board_vec jmr3927_vec __initdata = { .system = "Toshiba JMR_TX3927", .prom_init = jmr3927_prom_init, @@ -211,6 +217,7 @@ struct txx9_board_vec jmr3927_vec __initdata = { .irq_setup = jmr3927_irq_setup, .time_init = jmr3927_time_init, .device_init = jmr3927_device_init, + .arch_init = jmr3927_arch_init, #ifdef CONFIG_PCI .pci_map_irq = jmr3927_pci_map_irq, #endif -- GitLab From 5ac676ade1eac27fb311f0f2fb11eeac5089a66c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 11 Sep 2016 10:48:33 +0200 Subject: [PATCH 0225/1167] MIPS: TXx9: tx49xx: Move GPIO setup from .mem_setup() to .arch_init() txx9_gpio_init() calls gpiochip_add_data(), which fails with -ENOMEM as it is called too early in the boot process. This causes all subsequent GPIO operations to fail silently (before commit 54d77198fdfbc4f0 ("gpio: bail out silently on NULL descriptors") it printed the error message "gpiod_direction_output_raw: invalid GPIO" on RBTX49[23]7). Postpone all GPIO setup to .arch_init() time to fix this. Suggested-by: Atsushi Nemoto Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Cc: linux-mips@linux-mips.org Cc: linux-gpio@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14237/ Signed-off-by: Ralf Baechle --- arch/mips/txx9/generic/setup_tx4927.c | 1 - arch/mips/txx9/generic/setup_tx4938.c | 1 - arch/mips/txx9/rbtx4927/setup.c | 32 ++++++++++++++++++--------- arch/mips/txx9/rbtx4938/setup.c | 1 + 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/arch/mips/txx9/generic/setup_tx4927.c b/arch/mips/txx9/generic/setup_tx4927.c index a4664cb6c1e18..8d8011570b1db 100644 --- a/arch/mips/txx9/generic/setup_tx4927.c +++ b/arch/mips/txx9/generic/setup_tx4927.c @@ -215,7 +215,6 @@ void __init tx4927_setup(void) txx9_tmr_init(TX4927_TMR_REG(i) & 0xfffffffffULL); /* PIO */ - txx9_gpio_init(TX4927_PIO_REG & 0xfffffffffULL, 0, TX4927_NUM_PIO); __raw_writel(0, &tx4927_pioptr->maskcpu); __raw_writel(0, &tx4927_pioptr->maskext); diff --git a/arch/mips/txx9/generic/setup_tx4938.c b/arch/mips/txx9/generic/setup_tx4938.c index 58cdb2aba5e1b..ba265bf1fd067 100644 --- a/arch/mips/txx9/generic/setup_tx4938.c +++ b/arch/mips/txx9/generic/setup_tx4938.c @@ -241,7 +241,6 @@ void __init tx4938_setup(void) txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL); /* PIO */ - txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, TX4938_NUM_PIO); __raw_writel(0, &tx4938_pioptr->maskcpu); __raw_writel(0, &tx4938_pioptr->maskext); diff --git a/arch/mips/txx9/rbtx4927/setup.c b/arch/mips/txx9/rbtx4927/setup.c index 3c516ef625e57..f5b367e20dff1 100644 --- a/arch/mips/txx9/rbtx4927/setup.c +++ b/arch/mips/txx9/rbtx4927/setup.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -151,20 +152,37 @@ static void __init tx4937_pci_setup(void) } tx4938_setup_pcierr_irq(); } +#else +static inline void tx4927_pci_setup(void) {} +static inline void tx4937_pci_setup(void) {} +#endif /* CONFIG_PCI */ + +static void __init rbtx4927_gpio_init(void) +{ + /* TX4927-SIO DTR on (PIO[15]) */ + gpio_request(15, "sio-dtr"); + gpio_direction_output(15, 1); + + tx4927_sio_init(0, 0); +} static void __init rbtx4927_arch_init(void) { + txx9_gpio_init(TX4927_PIO_REG & 0xfffffffffULL, 0, TX4927_NUM_PIO); + + rbtx4927_gpio_init(); + tx4927_pci_setup(); } static void __init rbtx4937_arch_init(void) { + txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, TX4938_NUM_PIO); + + rbtx4927_gpio_init(); + tx4937_pci_setup(); } -#else -#define rbtx4927_arch_init NULL -#define rbtx4937_arch_init NULL -#endif /* CONFIG_PCI */ static void toshiba_rbtx4927_restart(char *command) { @@ -205,12 +223,6 @@ static void __init rbtx4927_mem_setup(void) #else set_io_port_base(KSEG1 + RBTX4927_ISA_IO_OFFSET); #endif - - /* TX4927-SIO DTR on (PIO[15]) */ - gpio_request(15, "sio-dtr"); - gpio_direction_output(15, 1); - - tx4927_sio_init(0, 0); } static void __init rbtx4927_clock_init(void) diff --git a/arch/mips/txx9/rbtx4938/setup.c b/arch/mips/txx9/rbtx4938/setup.c index 54de66837103c..07939ed6b22fd 100644 --- a/arch/mips/txx9/rbtx4938/setup.c +++ b/arch/mips/txx9/rbtx4938/setup.c @@ -336,6 +336,7 @@ static void __init rbtx4938_mtd_init(void) static void __init rbtx4938_arch_init(void) { + txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, TX4938_NUM_PIO); gpiochip_add_data(&rbtx4938_spi_gpio_chip, NULL); rbtx4938_pci_setup(); rbtx4938_spi_init(); -- GitLab From 39a3b6355329397c30441b62c940bb9cecec0448 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 11 Sep 2016 10:59:57 +0200 Subject: [PATCH 0226/1167] WATCHDOG: txx9wdt: Add missing clock (un)prepare calls for CCF While the custom minimal TXx9 clock implementation doesn't need or use clock (un)prepare calls (they are dummies if !CONFIG_HAVE_CLK_PREPARE), they are mandatory when using the Common Clock Framework. Hence add them, to prepare for the advent of CCF. Signed-off-by: Geert Uytterhoeven Reviewed-by: Guenter Roeck Cc: Atsushi Nemoto Cc: Wim Van Sebroeck Cc: linux-clk@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-watchdog@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14238/ Signed-off-by: Ralf Baechle --- drivers/watchdog/txx9wdt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c index c2da880292bc2..6f7a9deb27d05 100644 --- a/drivers/watchdog/txx9wdt.c +++ b/drivers/watchdog/txx9wdt.c @@ -112,7 +112,7 @@ static int __init txx9wdt_probe(struct platform_device *dev) txx9_imclk = NULL; goto exit; } - ret = clk_enable(txx9_imclk); + ret = clk_prepare_enable(txx9_imclk); if (ret) { clk_put(txx9_imclk); txx9_imclk = NULL; @@ -144,7 +144,7 @@ static int __init txx9wdt_probe(struct platform_device *dev) return 0; exit: if (txx9_imclk) { - clk_disable(txx9_imclk); + clk_disable_unprepare(txx9_imclk); clk_put(txx9_imclk); } return ret; @@ -153,7 +153,7 @@ static int __init txx9wdt_probe(struct platform_device *dev) static int __exit txx9wdt_remove(struct platform_device *dev) { watchdog_unregister_device(&txx9wdt); - clk_disable(txx9_imclk); + clk_disable_unprepare(txx9_imclk); clk_put(txx9_imclk); return 0; } -- GitLab From 44ce9a9ae977736fe7f470a7b1e506028375165a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 11 Sep 2016 10:59:58 +0200 Subject: [PATCH 0227/1167] MIPS: TXx9: Convert to Common Clock Framework Replace the custom minimal clock implementation for Toshiba TXx9 by a basic implementation using the Common Clock Framework. The only clocks that are provided are those needed by TXx9-specific drivers ("imbus" and "spi" (TX4938 only)), and their common parent clock "gbus". Other clocks can be added when needed. Signed-off-by: Geert Uytterhoeven Reviewed-by: Stephen Boyd Reviewed-by: Atsushi Nemoto Cc: Wim Van Sebroeck Cc: Guenter Roeck Cc: linux-clk@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-watchdog@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14239/ Signed-off-by: Ralf Baechle --- arch/mips/txx9/Kconfig | 2 +- arch/mips/txx9/generic/setup.c | 70 +++++++++++++++++----------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/arch/mips/txx9/Kconfig b/arch/mips/txx9/Kconfig index 8c337d60f790d..42923478d45ca 100644 --- a/arch/mips/txx9/Kconfig +++ b/arch/mips/txx9/Kconfig @@ -20,7 +20,7 @@ config MACH_TXX9 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN - select HAVE_CLK + select COMMON_CLK config TOSHIBA_JMR3927 bool "Toshiba JMR-TX3927 board" diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index ada92db92f87d..a1d98b5c8fd67 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -15,7 +15,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -83,40 +84,6 @@ int txx9_ccfg_toeon __initdata; int txx9_ccfg_toeon __initdata = 1; #endif -/* Minimum CLK support */ - -struct clk *clk_get(struct device *dev, const char *id) -{ - if (!strcmp(id, "spi-baseclk")) - return (struct clk *)((unsigned long)txx9_gbus_clock / 2 / 2); - if (!strcmp(id, "imbus_clk")) - return (struct clk *)((unsigned long)txx9_gbus_clock / 2); - return ERR_PTR(-ENOENT); -} -EXPORT_SYMBOL(clk_get); - -int clk_enable(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_disable); - -unsigned long clk_get_rate(struct clk *clk) -{ - return (unsigned long)clk; -} -EXPORT_SYMBOL(clk_get_rate); - -void clk_put(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_put); - #define BOARD_VEC(board) extern struct txx9_board_vec board; #include #undef BOARD_VEC @@ -560,8 +527,41 @@ void __init plat_time_init(void) txx9_board_vec->time_init(); } +static void txx9_clk_init(void) +{ + struct clk_hw *hw; + int error; + + hw = clk_hw_register_fixed_rate(NULL, "gbus", NULL, 0, txx9_gbus_clock); + if (IS_ERR(hw)) { + error = PTR_ERR(hw); + goto fail; + } + + hw = clk_hw_register_fixed_factor(NULL, "imbus", "gbus", 0, 1, 2); + error = clk_hw_register_clkdev(hw, "imbus_clk", NULL); + if (error) + goto fail; + +#ifdef CONFIG_CPU_TX49XX + if (TX4938_REV_PCODE() == 0x4938) { + hw = clk_hw_register_fixed_factor(NULL, "spi", "gbus", 0, 1, 4); + error = clk_hw_register_clkdev(hw, "spi-baseclk", NULL); + if (error) + goto fail; + } +#endif + + return; + +fail: + pr_err("Failed to register clocks: %d\n", error); +} + static int __init _txx9_arch_init(void) { + txx9_clk_init(); + if (txx9_board_vec->arch_init) txx9_board_vec->arch_init(); return 0; -- GitLab From 5f92635462d64f09f4643e7c15c48ea7a1f7d2b7 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 13 Sep 2016 09:21:47 -0600 Subject: [PATCH 0228/1167] MIPS: PCI: Reduce stack frame usage This patch removes creating a fake pci device in MIPS early config access and instead just uses the pci bus to get the same functionality. The struct pci_dev is too large to allocate on the stack, and was relying on compiler optimizations to remove its usage. Signed-off-by: Keith Busch Reviewed-by: Atsushi Nemoto Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14253/ Signed-off-by: Ralf Baechle --- arch/mips/txx9/generic/pci.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c index 1f6bc9a3036c0..285d84e5c7b92 100644 --- a/arch/mips/txx9/generic/pci.c +++ b/arch/mips/txx9/generic/pci.c @@ -29,12 +29,8 @@ static int __init early_read_config_word(struct pci_controller *hose, int top_bus, int bus, int devfn, int offset, u16 *value) { - struct pci_dev fake_dev; struct pci_bus fake_bus; - fake_dev.bus = &fake_bus; - fake_dev.sysdata = hose; - fake_dev.devfn = devfn; fake_bus.number = bus; fake_bus.sysdata = hose; fake_bus.ops = hose->pci_ops; @@ -45,7 +41,7 @@ early_read_config_word(struct pci_controller *hose, else fake_bus.parent = NULL; - return pci_read_config_word(&fake_dev, offset, value); + return pci_bus_read_config_word(&fake_bus, devfn, offset, value); } int __init txx9_pci66_check(struct pci_controller *hose, int top_bus, -- GitLab From 00ca0250125934c8e47f58f973ea2f8905cee017 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 19 Sep 2016 03:04:35 +0900 Subject: [PATCH 0229/1167] MIPS: BCM63xx: Let clk_disable() return immediately if clk is NULL In many of clk_disable() implementations, it is a no-op for a NULL pointer input, but this is one of the exceptions. Making it treewide consistent will allow clock consumers to call clk_disable() without NULL pointer check. Signed-off-by: Masahiro Yamada Acked-by: Florian Fainelli Cc: Stephen Boyd Cc: Michael Turquette Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: bcm-kernel-feedback-list@broadcom.com Cc: linux-arm-kernel@lists.infradead.org Patchwork: https://patchwork.linux-mips.org/patch/14264/ Signed-off-by: Ralf Baechle --- arch/mips/bcm63xx/clk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c index 637565284732d..b49fc9cb9cad2 100644 --- a/arch/mips/bcm63xx/clk.c +++ b/arch/mips/bcm63xx/clk.c @@ -326,6 +326,9 @@ EXPORT_SYMBOL(clk_enable); void clk_disable(struct clk *clk) { + if (!clk) + return; + mutex_lock(&clocks_mutex); clk_disable_unlocked(clk); mutex_unlock(&clocks_mutex); -- GitLab From 23d1f8f589df4a537751f4d6accc5841ed6cb24e Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 2 Sep 2016 23:44:16 +0300 Subject: [PATCH 0230/1167] MIPS: Octeon: Delete legacy hack for broken bootloaders Delete legacy hack for broken bootloaders. The warning has been in kernel for several years, and if there are still users using such bootloaders, they can fix the boot by supplying a proper DTB. Signed-off-by: Aaro Koskinen Cc: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14201/ Signed-off-by: Ralf Baechle --- .../executive/cvmx-helper-board.c | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c index ff49fc04500c7..3751c580ff85f 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c @@ -675,48 +675,6 @@ int __cvmx_helper_board_hardware_enable(int interface) cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc); } - } else if (cvmx_sysinfo_get()->board_type == - CVMX_BOARD_TYPE_CN3010_EVB_HS5) { - /* - * Broadcom PHYs require differnet ASX - * clocks. Unfortunately many boards don't define a - * new board Id and simply mangle the - * CN3010_EVB_HS5 - */ - if (interface == 0) { - /* - * Some boards use a hacked up bootloader that - * identifies them as CN3010_EVB_HS5 - * evaluation boards. This leads to all kinds - * of configuration problems. Detect one - * case, and print warning, while trying to do - * the right thing. - */ - int phy_addr = cvmx_helper_board_get_mii_address(0); - if (phy_addr != -1) { - int phy_identifier = - cvmx_mdio_read(phy_addr >> 8, - phy_addr & 0xff, 0x2); - /* Is it a Broadcom PHY? */ - if (phy_identifier == 0x0143) { - cvmx_dprintf("\n"); - cvmx_dprintf("ERROR:\n"); - cvmx_dprintf - ("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n"); - cvmx_dprintf - ("ERROR: The board type is mis-configured, and software malfunctions are likely.\n"); - cvmx_dprintf - ("ERROR: All boards require a unique board type to identify them.\n"); - cvmx_dprintf("ERROR:\n"); - cvmx_dprintf("\n"); - cvmx_wait(1000000000); - cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX - (0, interface), 5); - cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX - (0, interface), 5); - } - } - } } else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_UBNT_E100) { cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0); -- GitLab From b93ebc1d5bd127a0c6161cf4bbb098374b1d8956 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 2 Sep 2016 23:44:17 +0300 Subject: [PATCH 0231/1167] MIPS: Octeon: Don't try to maintain link state in early init. Leave that to actual ethernet/phy drivers. Signed-off-by: Aaro Koskinen Cc: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14202/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c | 3 +-- arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c | 2 -- arch/mips/cavium-octeon/executive/cvmx-helper.c | 10 ---------- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c b/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c index f59c88ee9b31c..809cd8b73f36c 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c @@ -243,8 +243,7 @@ int __cvmx_helper_rgmii_enable(int interface) /* enable the ports now */ for (port = 0; port < num_ports; port++) { union cvmx_gmxx_prtx_cfg gmx_cfg; - cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port - (interface, port)); + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface)); gmx_cfg.s.en = 1; diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c index a56ee590de1f3..d347fe13b6664 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c @@ -234,8 +234,6 @@ int __cvmx_helper_xaui_enable(int interface) cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64); cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64); - cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, 0)); - /* (8) Enable packet reception */ xauiMiscCtl.s.gmxeno = 0; cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index ff26d0217b878..6456af6424719 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c @@ -841,7 +841,6 @@ int __cvmx_helper_errata_fix_ipd_ptr_alignment(void) int retry_cnt; int retry_loop_cnt; int i; - cvmx_helper_link_info_t link_info; /* Save values for restore at end */ uint64_t prtx_cfg = @@ -1002,15 +1001,6 @@ int __cvmx_helper_errata_fix_ipd_ptr_alignment(void) (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), frame_max); cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 0); - /* Set link to down so autonegotiation will set it up again */ - link_info.u64 = 0; - cvmx_helper_link_set(FIX_IPD_OUTPORT, link_info); - - /* - * Bring the link back up as autonegotiation is not done in - * user applications. - */ - cvmx_helper_link_autoconf(FIX_IPD_OUTPORT); CVMX_SYNC; if (num_segs) -- GitLab From 80c73b3509f29b363a7bb07203c310ee0ad8b625 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 2 Sep 2016 23:44:18 +0300 Subject: [PATCH 0232/1167] MIPS: Octeon: Delete unused cvmx_override_board_link_get. Signed-off-by: Aaro Koskinen Cc: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14203/ Signed-off-by: Ralf Baechle --- .../cavium-octeon/executive/cvmx-helper-board.c | 15 --------------- arch/mips/include/asm/octeon/cvmx-helper-board.h | 10 ---------- 2 files changed, 25 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c index 3751c580ff85f..0deeb827a4430 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c @@ -45,17 +45,6 @@ #include #include -/** - * cvmx_override_board_link_get(int ipd_port) is a function - * pointer. It is meant to allow customization of the process of - * talking to a PHY to determine link speed. It is called every - * time a PHY must be polled for link status. Users should set - * this pointer to a function before calling any cvmx-helper - * operations. - */ -cvmx_helper_link_info_t(*cvmx_override_board_link_get) (int ipd_port) = - NULL; - /** * Return the MII PHY address associated with the given IPD * port. A result of -1 means there isn't a MII capable PHY @@ -225,10 +214,6 @@ cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) int phy_addr; int is_broadcom_phy = 0; - /* Give the user a chance to override the processing of this function */ - if (cvmx_override_board_link_get) - return cvmx_override_board_link_get(ipd_port); - /* Unless we fix it later, all links are defaulted to down */ result.u64 = 0; diff --git a/arch/mips/include/asm/octeon/cvmx-helper-board.h b/arch/mips/include/asm/octeon/cvmx-helper-board.h index cda93aee712c6..271be7a54d316 100644 --- a/arch/mips/include/asm/octeon/cvmx-helper-board.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-board.h @@ -57,16 +57,6 @@ typedef enum { */ #define CVMX_HELPER_BOARD_MGMT_IPD_PORT -10 -/** - * cvmx_override_board_link_get(int ipd_port) is a function - * pointer. It is meant to allow customization of the process of - * talking to a PHY to determine link speed. It is called every - * time a PHY must be polled for link status. Users should set - * this pointer to a function before calling any cvmx-helper - * operations. - */ -extern cvmx_helper_link_info_t(*cvmx_override_board_link_get) (int ipd_port); - /** * Return the MII PHY address associated with the given IPD * port. A result of -1 means there isn't a MII capable PHY -- GitLab From 0a1e192d660db17c532a6ab36eb2f77332d9cb1c Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 2 Sep 2016 23:44:19 +0300 Subject: [PATCH 0233/1167] MIPS: Octeon: Delete unused cvmx_helper_board_link_set_phy. Signed-off-by: Aaro Koskinen Cc: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14204/ Signed-off-by: Ralf Baechle --- .../executive/cvmx-helper-board.c | 170 ------------------ .../include/asm/octeon/cvmx-helper-board.h | 20 --- 2 files changed, 190 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c index 0deeb827a4430..5572e398180b0 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c @@ -417,176 +417,6 @@ cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) return result; } -/** - * This function as a board specific method of changing the PHY - * speed, duplex, and auto-negotiation. This programs the PHY and - * not Octeon. This can be used to force Octeon's links to - * specific settings. - * - * @phy_addr: The address of the PHY to program - * @enable_autoneg: - * Non zero if you want to enable auto-negotiation. - * @link_info: Link speed to program. If the speed is zero and auto-negotiation - * is enabled, all possible negotiation speeds are advertised. - * - * Returns Zero on success, negative on failure - */ -int cvmx_helper_board_link_set_phy(int phy_addr, - cvmx_helper_board_set_phy_link_flags_types_t - link_flags, - cvmx_helper_link_info_t link_info) -{ - - /* Set the flow control settings based on link_flags */ - if ((link_flags & set_phy_link_flags_flow_control_mask) != - set_phy_link_flags_flow_control_dont_touch) { - cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; - reg_autoneg_adver.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER); - reg_autoneg_adver.s.asymmetric_pause = - (link_flags & set_phy_link_flags_flow_control_mask) == - set_phy_link_flags_flow_control_enable; - reg_autoneg_adver.s.pause = - (link_flags & set_phy_link_flags_flow_control_mask) == - set_phy_link_flags_flow_control_enable; - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER, - reg_autoneg_adver.u16); - } - - /* If speed isn't set and autoneg is on advertise all supported modes */ - if ((link_flags & set_phy_link_flags_autoneg) - && (link_info.s.speed == 0)) { - cvmx_mdio_phy_reg_control_t reg_control; - cvmx_mdio_phy_reg_status_t reg_status; - cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; - cvmx_mdio_phy_reg_extended_status_t reg_extended_status; - cvmx_mdio_phy_reg_control_1000_t reg_control_1000; - - reg_status.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_STATUS); - reg_autoneg_adver.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER); - reg_autoneg_adver.s.advert_100base_t4 = - reg_status.s.capable_100base_t4; - reg_autoneg_adver.s.advert_10base_tx_full = - reg_status.s.capable_10_full; - reg_autoneg_adver.s.advert_10base_tx_half = - reg_status.s.capable_10_half; - reg_autoneg_adver.s.advert_100base_tx_full = - reg_status.s.capable_100base_x_full; - reg_autoneg_adver.s.advert_100base_tx_half = - reg_status.s.capable_100base_x_half; - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER, - reg_autoneg_adver.u16); - if (reg_status.s.capable_extended_status) { - reg_extended_status.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_EXTENDED_STATUS); - reg_control_1000.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL_1000); - reg_control_1000.s.advert_1000base_t_full = - reg_extended_status.s.capable_1000base_t_full; - reg_control_1000.s.advert_1000base_t_half = - reg_extended_status.s.capable_1000base_t_half; - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL_1000, - reg_control_1000.u16); - } - reg_control.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL); - reg_control.s.autoneg_enable = 1; - reg_control.s.restart_autoneg = 1; - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); - } else if ((link_flags & set_phy_link_flags_autoneg)) { - cvmx_mdio_phy_reg_control_t reg_control; - cvmx_mdio_phy_reg_status_t reg_status; - cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; - cvmx_mdio_phy_reg_control_1000_t reg_control_1000; - - reg_status.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_STATUS); - reg_autoneg_adver.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER); - reg_autoneg_adver.s.advert_100base_t4 = 0; - reg_autoneg_adver.s.advert_10base_tx_full = 0; - reg_autoneg_adver.s.advert_10base_tx_half = 0; - reg_autoneg_adver.s.advert_100base_tx_full = 0; - reg_autoneg_adver.s.advert_100base_tx_half = 0; - if (reg_status.s.capable_extended_status) { - reg_control_1000.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL_1000); - reg_control_1000.s.advert_1000base_t_full = 0; - reg_control_1000.s.advert_1000base_t_half = 0; - } - switch (link_info.s.speed) { - case 10: - reg_autoneg_adver.s.advert_10base_tx_full = - link_info.s.full_duplex; - reg_autoneg_adver.s.advert_10base_tx_half = - !link_info.s.full_duplex; - break; - case 100: - reg_autoneg_adver.s.advert_100base_tx_full = - link_info.s.full_duplex; - reg_autoneg_adver.s.advert_100base_tx_half = - !link_info.s.full_duplex; - break; - case 1000: - reg_control_1000.s.advert_1000base_t_full = - link_info.s.full_duplex; - reg_control_1000.s.advert_1000base_t_half = - !link_info.s.full_duplex; - break; - } - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER, - reg_autoneg_adver.u16); - if (reg_status.s.capable_extended_status) - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL_1000, - reg_control_1000.u16); - reg_control.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL); - reg_control.s.autoneg_enable = 1; - reg_control.s.restart_autoneg = 1; - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); - } else { - cvmx_mdio_phy_reg_control_t reg_control; - reg_control.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL); - reg_control.s.autoneg_enable = 0; - reg_control.s.restart_autoneg = 1; - reg_control.s.duplex = link_info.s.full_duplex; - if (link_info.s.speed == 1000) { - reg_control.s.speed_msb = 1; - reg_control.s.speed_lsb = 0; - } else if (link_info.s.speed == 100) { - reg_control.s.speed_msb = 0; - reg_control.s.speed_lsb = 1; - } else if (link_info.s.speed == 10) { - reg_control.s.speed_msb = 0; - reg_control.s.speed_lsb = 0; - } - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); - } - return 0; -} - /** * This function is called by cvmx_helper_interface_probe() after it * determines the number of ports Octeon can support on a specific diff --git a/arch/mips/include/asm/octeon/cvmx-helper-board.h b/arch/mips/include/asm/octeon/cvmx-helper-board.h index 271be7a54d316..b4d19c21b62cf 100644 --- a/arch/mips/include/asm/octeon/cvmx-helper-board.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-board.h @@ -75,26 +75,6 @@ typedef enum { */ extern int cvmx_helper_board_get_mii_address(int ipd_port); -/** - * This function as a board specific method of changing the PHY - * speed, duplex, and autonegotiation. This programs the PHY and - * not Octeon. This can be used to force Octeon's links to - * specific settings. - * - * @phy_addr: The address of the PHY to program - * @link_flags: - * Flags to control autonegotiation. Bit 0 is autonegotiation - * enable/disable to maintain backward compatibility. - * @link_info: Link speed to program. If the speed is zero and autonegotiation - * is enabled, all possible negotiation speeds are advertised. - * - * Returns Zero on success, negative on failure - */ -int cvmx_helper_board_link_set_phy(int phy_addr, - cvmx_helper_board_set_phy_link_flags_types_t - link_flags, - cvmx_helper_link_info_t link_info); - /** * This function is the board specific method of determining an * ethernet ports link speed. Most Octeon boards have Marvell PHYs -- GitLab From 0d19672e7807d7d365ca3b317f4b2d0db6847ca6 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 2 Sep 2016 23:44:20 +0300 Subject: [PATCH 0234/1167] MIPS: Octeon: Delete legacy code for PHY access PHY access through the board helper is impossible with the current drivers, so delete this code. Signed-off-by: Aaro Koskinen Cc: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14205/ Signed-off-by: Ralf Baechle --- .../executive/cvmx-helper-board.c | 108 +----------------- 1 file changed, 2 insertions(+), 106 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c index 5572e398180b0..bc37266da6fd3 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c @@ -211,8 +211,6 @@ int cvmx_helper_board_get_mii_address(int ipd_port) cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) { cvmx_helper_link_info_t result; - int phy_addr; - int is_broadcom_phy = 0; /* Unless we fix it later, all links are defaulted to down */ result.u64 = 0; @@ -248,8 +246,7 @@ cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) result.s.full_duplex = 1; result.s.speed = 1000; return result; - } else /* The other port uses a broadcom PHY */ - is_broadcom_phy = 1; + } break; case CVMX_BOARD_TYPE_BBGW_REF: /* Port 1 on these boards is always Gigabit */ @@ -267,108 +264,7 @@ cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) break; } - phy_addr = cvmx_helper_board_get_mii_address(ipd_port); - if (phy_addr != -1) { - if (is_broadcom_phy) { - /* - * Below we are going to read SMI/MDIO - * register 0x19 which works on Broadcom - * parts - */ - int phy_status = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - 0x19); - switch ((phy_status >> 8) & 0x7) { - case 0: - result.u64 = 0; - break; - case 1: - result.s.link_up = 1; - result.s.full_duplex = 0; - result.s.speed = 10; - break; - case 2: - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 10; - break; - case 3: - result.s.link_up = 1; - result.s.full_duplex = 0; - result.s.speed = 100; - break; - case 4: - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 100; - break; - case 5: - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 100; - break; - case 6: - result.s.link_up = 1; - result.s.full_duplex = 0; - result.s.speed = 1000; - break; - case 7: - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 1000; - break; - } - } else { - /* - * This code assumes we are using a Marvell - * Gigabit PHY. All the speed information can - * be read from register 17 in one - * go. Somebody using a different PHY will - * need to handle it above in the board - * specific area. - */ - int phy_status = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); - - /* - * If the resolve bit 11 isn't set, see if - * autoneg is turned off (bit 12, reg 0). The - * resolve bit doesn't get set properly when - * autoneg is off, so force it. - */ - if ((phy_status & (1 << 11)) == 0) { - int auto_status = - cvmx_mdio_read(phy_addr >> 8, - phy_addr & 0xff, 0); - if ((auto_status & (1 << 12)) == 0) - phy_status |= 1 << 11; - } - - /* - * Only return a link if the PHY has finished - * auto negotiation and set the resolved bit - * (bit 11) - */ - if (phy_status & (1 << 11)) { - result.s.link_up = 1; - result.s.full_duplex = ((phy_status >> 13) & 1); - switch ((phy_status >> 14) & 3) { - case 0: /* 10 Mbps */ - result.s.speed = 10; - break; - case 1: /* 100 Mbps */ - result.s.speed = 100; - break; - case 2: /* 1 Gbps */ - result.s.speed = 1000; - break; - case 3: /* Illegal */ - result.u64 = 0; - break; - } - } - } - } else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) + if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) { /* -- GitLab From 6376d7baffb903bebebe32cc8c3610cfeade0849 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 2 Sep 2016 23:44:21 +0300 Subject: [PATCH 0235/1167] MIPS: Octeon: Delete unused cvmx-mdio.h Signed-off-by: Aaro Koskinen Cc: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14206/ Signed-off-by: Ralf Baechle --- .../executive/cvmx-helper-board.c | 2 - .../executive/cvmx-helper-rgmii.c | 2 - .../executive/cvmx-helper-sgmii.c | 1 - arch/mips/include/asm/octeon/cvmx-mdio.h | 506 ------------------ 4 files changed, 511 deletions(-) delete mode 100644 arch/mips/include/asm/octeon/cvmx-mdio.h diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c index bc37266da6fd3..ab8362e04461e 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c @@ -36,8 +36,6 @@ #include -#include - #include #include #include diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c b/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c index 809cd8b73f36c..671ab1db27276 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c @@ -33,8 +33,6 @@ #include - -#include #include #include #include diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c index 6f9609e63a65a..54375340afe8b 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c @@ -34,7 +34,6 @@ #include -#include #include #include diff --git a/arch/mips/include/asm/octeon/cvmx-mdio.h b/arch/mips/include/asm/octeon/cvmx-mdio.h deleted file mode 100644 index 9f6a4f32a83c5..0000000000000 --- a/arch/mips/include/asm/octeon/cvmx-mdio.h +++ /dev/null @@ -1,506 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * - * Interface to the SMI/MDIO hardware, including support for both IEEE 802.3 - * clause 22 and clause 45 operations. - * - */ - -#ifndef __CVMX_MIO_H__ -#define __CVMX_MIO_H__ - -#include - -/** - * PHY register 0 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_CONTROL 0 -typedef union { - uint16_t u16; - struct { - uint16_t reset:1; - uint16_t loopback:1; - uint16_t speed_lsb:1; - uint16_t autoneg_enable:1; - uint16_t power_down:1; - uint16_t isolate:1; - uint16_t restart_autoneg:1; - uint16_t duplex:1; - uint16_t collision_test:1; - uint16_t speed_msb:1; - uint16_t unidirectional_enable:1; - uint16_t reserved_0_4:5; - } s; -} cvmx_mdio_phy_reg_control_t; - -/** - * PHY register 1 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_STATUS 1 -typedef union { - uint16_t u16; - struct { - uint16_t capable_100base_t4:1; - uint16_t capable_100base_x_full:1; - uint16_t capable_100base_x_half:1; - uint16_t capable_10_full:1; - uint16_t capable_10_half:1; - uint16_t capable_100base_t2_full:1; - uint16_t capable_100base_t2_half:1; - uint16_t capable_extended_status:1; - uint16_t capable_unidirectional:1; - uint16_t capable_mf_preamble_suppression:1; - uint16_t autoneg_complete:1; - uint16_t remote_fault:1; - uint16_t capable_autoneg:1; - uint16_t link_status:1; - uint16_t jabber_detect:1; - uint16_t capable_extended_registers:1; - - } s; -} cvmx_mdio_phy_reg_status_t; - -/** - * PHY register 2 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_ID1 2 -typedef union { - uint16_t u16; - struct { - uint16_t oui_bits_3_18; - } s; -} cvmx_mdio_phy_reg_id1_t; - -/** - * PHY register 3 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_ID2 3 -typedef union { - uint16_t u16; - struct { - uint16_t oui_bits_19_24:6; - uint16_t model:6; - uint16_t revision:4; - } s; -} cvmx_mdio_phy_reg_id2_t; - -/** - * PHY register 4 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_AUTONEG_ADVER 4 -typedef union { - uint16_t u16; - struct { - uint16_t next_page:1; - uint16_t reserved_14:1; - uint16_t remote_fault:1; - uint16_t reserved_12:1; - uint16_t asymmetric_pause:1; - uint16_t pause:1; - uint16_t advert_100base_t4:1; - uint16_t advert_100base_tx_full:1; - uint16_t advert_100base_tx_half:1; - uint16_t advert_10base_tx_full:1; - uint16_t advert_10base_tx_half:1; - uint16_t selector:5; - } s; -} cvmx_mdio_phy_reg_autoneg_adver_t; - -/** - * PHY register 5 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_LINK_PARTNER_ABILITY 5 -typedef union { - uint16_t u16; - struct { - uint16_t next_page:1; - uint16_t ack:1; - uint16_t remote_fault:1; - uint16_t reserved_12:1; - uint16_t asymmetric_pause:1; - uint16_t pause:1; - uint16_t advert_100base_t4:1; - uint16_t advert_100base_tx_full:1; - uint16_t advert_100base_tx_half:1; - uint16_t advert_10base_tx_full:1; - uint16_t advert_10base_tx_half:1; - uint16_t selector:5; - } s; -} cvmx_mdio_phy_reg_link_partner_ability_t; - -/** - * PHY register 6 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_AUTONEG_EXPANSION 6 -typedef union { - uint16_t u16; - struct { - uint16_t reserved_5_15:11; - uint16_t parallel_detection_fault:1; - uint16_t link_partner_next_page_capable:1; - uint16_t local_next_page_capable:1; - uint16_t page_received:1; - uint16_t link_partner_autoneg_capable:1; - - } s; -} cvmx_mdio_phy_reg_autoneg_expansion_t; - -/** - * PHY register 9 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_CONTROL_1000 9 -typedef union { - uint16_t u16; - struct { - uint16_t test_mode:3; - uint16_t manual_master_slave:1; - uint16_t master:1; - uint16_t port_type:1; - uint16_t advert_1000base_t_full:1; - uint16_t advert_1000base_t_half:1; - uint16_t reserved_0_7:8; - } s; -} cvmx_mdio_phy_reg_control_1000_t; - -/** - * PHY register 10 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_STATUS_1000 10 -typedef union { - uint16_t u16; - struct { - uint16_t master_slave_fault:1; - uint16_t is_master:1; - uint16_t local_receiver_ok:1; - uint16_t remote_receiver_ok:1; - uint16_t remote_capable_1000base_t_full:1; - uint16_t remote_capable_1000base_t_half:1; - uint16_t reserved_8_9:2; - uint16_t idle_error_count:8; - } s; -} cvmx_mdio_phy_reg_status_1000_t; - -/** - * PHY register 15 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_EXTENDED_STATUS 15 -typedef union { - uint16_t u16; - struct { - uint16_t capable_1000base_x_full:1; - uint16_t capable_1000base_x_half:1; - uint16_t capable_1000base_t_full:1; - uint16_t capable_1000base_t_half:1; - uint16_t reserved_0_11:12; - } s; -} cvmx_mdio_phy_reg_extended_status_t; - -/** - * PHY register 13 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_MMD_CONTROL 13 -typedef union { - uint16_t u16; - struct { - uint16_t function:2; - uint16_t reserved_5_13:9; - uint16_t devad:5; - } s; -} cvmx_mdio_phy_reg_mmd_control_t; - -/** - * PHY register 14 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA 14 -typedef union { - uint16_t u16; - struct { - uint16_t address_data:16; - } s; -} cvmx_mdio_phy_reg_mmd_address_data_t; - -/* Operating request encodings. */ -#define MDIO_CLAUSE_22_WRITE 0 -#define MDIO_CLAUSE_22_READ 1 - -#define MDIO_CLAUSE_45_ADDRESS 0 -#define MDIO_CLAUSE_45_WRITE 1 -#define MDIO_CLAUSE_45_READ_INC 2 -#define MDIO_CLAUSE_45_READ 3 - -/* MMD identifiers, mostly for accessing devices within XENPAK modules. */ -#define CVMX_MMD_DEVICE_PMA_PMD 1 -#define CVMX_MMD_DEVICE_WIS 2 -#define CVMX_MMD_DEVICE_PCS 3 -#define CVMX_MMD_DEVICE_PHY_XS 4 -#define CVMX_MMD_DEVICE_DTS_XS 5 -#define CVMX_MMD_DEVICE_TC 6 -#define CVMX_MMD_DEVICE_CL22_EXT 29 -#define CVMX_MMD_DEVICE_VENDOR_1 30 -#define CVMX_MMD_DEVICE_VENDOR_2 31 - -/* Helper function to put MDIO interface into clause 45 mode */ -static inline void __cvmx_mdio_set_clause45_mode(int bus_id) -{ - union cvmx_smix_clk smi_clk; - /* Put bus into clause 45 mode */ - smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id)); - smi_clk.s.mode = 1; - smi_clk.s.preamble = 1; - cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64); -} - -/* Helper function to put MDIO interface into clause 22 mode */ -static inline void __cvmx_mdio_set_clause22_mode(int bus_id) -{ - union cvmx_smix_clk smi_clk; - /* Put bus into clause 22 mode */ - smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id)); - smi_clk.s.mode = 0; - cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64); -} - -/** - * Perform an MII read. This function is used to read PHY - * registers controlling auto negotiation. - * - * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) - * support multiple busses. - * @phy_id: The MII phy id - * @location: Register location to read - * - * Returns Result from the read or -1 on failure - */ -static inline int cvmx_mdio_read(int bus_id, int phy_id, int location) -{ - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_rd_dat smi_rd; - int timeout = 1000; - - if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) - __cvmx_mdio_set_clause22_mode(bus_id); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_22_READ; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = location; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id)); - } while (smi_rd.s.pending && timeout--); - - if (smi_rd.s.val) - return smi_rd.s.dat; - else - return -1; -} - -/** - * Perform an MII write. This function is used to write PHY - * registers controlling auto negotiation. - * - * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) - * support multiple busses. - * @phy_id: The MII phy id - * @location: Register location to write - * @val: Value to write - * - * Returns -1 on error - * 0 on success - */ -static inline int cvmx_mdio_write(int bus_id, int phy_id, int location, int val) -{ - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_wr_dat smi_wr; - int timeout = 1000; - - if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) - __cvmx_mdio_set_clause22_mode(bus_id); - - smi_wr.u64 = 0; - smi_wr.s.dat = val; - cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_22_WRITE; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = location; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); - } while (smi_wr.s.pending && --timeout); - if (timeout <= 0) - return -1; - - return 0; -} - -/** - * Perform an IEEE 802.3 clause 45 MII read. This function is used to - * read PHY registers controlling auto negotiation. - * - * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) - * support multiple busses. - * @phy_id: The MII phy id - * @device: MDIO Managable Device (MMD) id - * @location: Register location to read - * - * Returns Result from the read or -1 on failure - */ - -static inline int cvmx_mdio_45_read(int bus_id, int phy_id, int device, - int location) -{ - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_rd_dat smi_rd; - union cvmx_smix_wr_dat smi_wr; - int timeout = 1000; - - if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) - return -1; - - __cvmx_mdio_set_clause45_mode(bus_id); - - smi_wr.u64 = 0; - smi_wr.s.dat = location; - cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = device; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); - } while (smi_wr.s.pending && --timeout); - if (timeout <= 0) { - cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d " - "device %2d register %2d TIME OUT(address)\n", - bus_id, phy_id, device, location); - return -1; - } - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_45_READ; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = device; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id)); - } while (smi_rd.s.pending && --timeout); - - if (timeout <= 0) { - cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d " - "device %2d register %2d TIME OUT(data)\n", - bus_id, phy_id, device, location); - return -1; - } - - if (smi_rd.s.val) - return smi_rd.s.dat; - else { - cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d " - "device %2d register %2d INVALID READ\n", - bus_id, phy_id, device, location); - return -1; - } -} - -/** - * Perform an IEEE 802.3 clause 45 MII write. This function is used to - * write PHY registers controlling auto negotiation. - * - * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) - * support multiple busses. - * @phy_id: The MII phy id - * @device: MDIO Managable Device (MMD) id - * @location: Register location to write - * @val: Value to write - * - * Returns -1 on error - * 0 on success - */ -static inline int cvmx_mdio_45_write(int bus_id, int phy_id, int device, - int location, int val) -{ - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_wr_dat smi_wr; - int timeout = 1000; - - if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) - return -1; - - __cvmx_mdio_set_clause45_mode(bus_id); - - smi_wr.u64 = 0; - smi_wr.s.dat = location; - cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = device; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); - } while (smi_wr.s.pending && --timeout); - if (timeout <= 0) - return -1; - - smi_wr.u64 = 0; - smi_wr.s.dat = val; - cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_45_WRITE; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = device; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); - } while (smi_wr.s.pending && --timeout); - if (timeout <= 0) - return -1; - - return 0; -} - -#endif -- GitLab From 1491eaf970eeb5b1285d88592706217a1c60ed85 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 12 Sep 2016 23:39:08 +0300 Subject: [PATCH 0236/1167] MIPS: Octeon: Split dlink_dsr-1000n.dts to allow reuse with D-Link DSR-500N. Signed-off-by: Aaro Koskinen Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14248/ Signed-off-by: Ralf Baechle --- .../dts/cavium-octeon/dlink_dsr-1000n.dts | 45 +------------- .../cavium-octeon/dlink_dsr-500n-1000n.dtsi | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 44 deletions(-) create mode 100644 arch/mips/boot/dts/cavium-octeon/dlink_dsr-500n-1000n.dtsi diff --git a/arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts b/arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts index b134798a0fd72..cfa29156eb69d 100644 --- a/arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts +++ b/arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts @@ -8,55 +8,16 @@ * published by the Free Software Foundation. */ -/include/ "octeon_3xxx.dtsi" +/include/ "dlink_dsr-500n-1000n.dtsi" #include / { model = "dlink,dsr-1000n"; soc@0 { - smi0: mdio@1180000001800 { - phy8: ethernet-phy@8 { - reg = <8>; - compatible = "ethernet-phy-ieee802.3-c22"; - }; - }; - - pip: pip@11800a0000000 { - interface@0 { - ethernet@0 { - fixed-link { - speed = <1000>; - full-duplex; - }; - }; - ethernet@1 { - fixed-link { - speed = <1000>; - full-duplex; - }; - }; - ethernet@2 { - phy-handle = <&phy8>; - }; - }; - }; - - twsi0: i2c@1180000001000 { - rtc@68 { - compatible = "dallas,ds1337"; - reg = <0x68>; - }; - }; - uart0: serial@1180000000800 { clock-frequency = <500000000>; }; - - usbn: usbn@1180068000000 { - refclk-frequency = <12000000>; - refclk-type = "crystal"; - }; }; leds { @@ -87,8 +48,4 @@ gpios = <&gpio 18 GPIO_ACTIVE_LOW>; }; }; - - aliases { - pip = &pip; - }; }; diff --git a/arch/mips/boot/dts/cavium-octeon/dlink_dsr-500n-1000n.dtsi b/arch/mips/boot/dts/cavium-octeon/dlink_dsr-500n-1000n.dtsi new file mode 100644 index 0000000000000..246b598201f84 --- /dev/null +++ b/arch/mips/boot/dts/cavium-octeon/dlink_dsr-500n-1000n.dtsi @@ -0,0 +1,58 @@ +/* + * Device tree source for D-Link DSR-500N/1000N (common parts). + * + * Written by: Aaro Koskinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/include/ "octeon_3xxx.dtsi" + +/ { + soc@0 { + smi0: mdio@1180000001800 { + phy8: ethernet-phy@8 { + reg = <8>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + }; + + pip: pip@11800a0000000 { + interface@0 { + ethernet@0 { + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + ethernet@1 { + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + ethernet@2 { + phy-handle = <&phy8>; + }; + }; + }; + + twsi0: i2c@1180000001000 { + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + }; + }; + + usbn: usbn@1180068000000 { + refclk-frequency = <12000000>; + refclk-type = "crystal"; + }; + }; + + aliases { + pip = &pip; + }; +}; -- GitLab From 6fcdc71735a5537931f3155e86540c47df18b9f3 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 12 Sep 2016 23:39:09 +0300 Subject: [PATCH 0237/1167] MIPS: Octeon: Add DTS for D-Link DSR-500N. Signed-off-by: Aaro Koskinen Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14249/ Signed-off-by: Ralf Baechle --- .../boot/dts/cavium-octeon/dlink_dsr-500n.dts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 arch/mips/boot/dts/cavium-octeon/dlink_dsr-500n.dts diff --git a/arch/mips/boot/dts/cavium-octeon/dlink_dsr-500n.dts b/arch/mips/boot/dts/cavium-octeon/dlink_dsr-500n.dts new file mode 100644 index 0000000000000..78886e172c489 --- /dev/null +++ b/arch/mips/boot/dts/cavium-octeon/dlink_dsr-500n.dts @@ -0,0 +1,40 @@ +/* + * Device tree source for D-Link DSR-500N. + * + * Written by: Aaro Koskinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/include/ "dlink_dsr-500n-1000n.dtsi" +#include + +/ { + model = "dlink,dsr-500n"; + compatible = "dlink,dsr-500n", "cavium,octeon-3860"; + + soc@0 { + uart0: serial@1180000000800 { + clock-frequency = <300000000>; + }; + }; + + leds { + compatible = "gpio-leds"; + + usb { + gpios = <&gpio 9 GPIO_ACTIVE_LOW>; + }; + + wps { + gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + }; + + wireless { + label = "2.4g"; + gpios = <&gpio 18 GPIO_ACTIVE_LOW>; + }; + }; +}; -- GitLab From e6e5b7b6d0de7e2c25b45fc7a0c914ed6aa1d5e8 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 12 Sep 2016 23:39:10 +0300 Subject: [PATCH 0238/1167] MIPS: Octeon: Fix PCI interrupt routing on D-Link DSR-500N. Signed-off-by: Aaro Koskinen Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14250/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-octeon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c index c258cd406fbbe..308d051fc45cd 100644 --- a/arch/mips/pci/pci-octeon.c +++ b/arch/mips/pci/pci-octeon.c @@ -204,6 +204,8 @@ const char *octeon_get_pci_interrupts(void) * Interrupt Number (INTA# = 0, INTB# = 1, INTC# = 2, and * INTD# = 3) */ + if (of_machine_is_compatible("dlink,dsr-500n")) + return "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"; switch (octeon_bootinfo->board_type) { case CVMX_BOARD_TYPE_NAO38: /* This is really the NAC38 */ -- GitLab From 6b89d22e742aa3fbb1878c2e6684b0bfd591f7c8 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:09 +0100 Subject: [PATCH 0239/1167] MIPS: CPC: Convert bare 'unsigned' to 'unsigned int' Checkpatch complains about use of bare unsigned type. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14217/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cpc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index 566b8d2c092c3..0e337f55ac600 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -52,7 +52,7 @@ static phys_addr_t mips_cpc_phys_base(void) int mips_cpc_probe(void) { phys_addr_t addr; - unsigned cpu; + unsigned int cpu; for_each_possible_cpu(cpu) spin_lock_init(&per_cpu(cpc_core_lock, cpu)); @@ -70,7 +70,7 @@ int mips_cpc_probe(void) void mips_cpc_lock_other(unsigned int core) { - unsigned curr_core; + unsigned int curr_core; preempt_disable(); curr_core = current_cpu_data.core; spin_lock_irqsave(&per_cpu(cpc_core_lock, curr_core), @@ -86,7 +86,7 @@ void mips_cpc_lock_other(unsigned int core) void mips_cpc_unlock_other(void) { - unsigned curr_core = current_cpu_data.core; + unsigned int curr_core = current_cpu_data.core; spin_unlock_irqrestore(&per_cpu(cpc_core_lock, curr_core), per_cpu(cpc_core_lock_flags, curr_core)); preempt_enable(); -- GitLab From d6219420480b75258b93583caa3885fb80d83313 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:10 +0100 Subject: [PATCH 0240/1167] MIPS: CPC: Avoid lock when MIPS CM >= 3 is present MIPS CM version 3 removed the CPC_CL_OTHER register and instead the CM_CL_OTHER register is used to redirect the CPC_OTHER region. As such, we should not write the unimplmented register and can avoid the spinlock as well. These lock functions should aleady be called within the context of a mips_cm_{lock,unlock}_other pair ensuring the correct CPC_OTHER region will be accessed. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14219/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cpc.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index 0e337f55ac600..2a45867d3b4f5 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -71,6 +71,11 @@ int mips_cpc_probe(void) void mips_cpc_lock_other(unsigned int core) { unsigned int curr_core; + + if (mips_cm_revision() >= CM_REV_CM3) + /* Systems with CM >= 3 lock the CPC via mips_cm_lock_other */ + return; + preempt_disable(); curr_core = current_cpu_data.core; spin_lock_irqsave(&per_cpu(cpc_core_lock, curr_core), @@ -86,7 +91,13 @@ void mips_cpc_lock_other(unsigned int core) void mips_cpc_unlock_other(void) { - unsigned int curr_core = current_cpu_data.core; + unsigned int curr_core; + + if (mips_cm_revision() >= CM_REV_CM3) + /* Systems with CM >= 3 lock the CPC via mips_cm_lock_other */ + return; + + curr_core = current_cpu_data.core; spin_unlock_irqrestore(&per_cpu(cpc_core_lock, curr_core), per_cpu(cpc_core_lock_flags, curr_core)); preempt_enable(); -- GitLab From b97d0b9099afcd5c569acaf9b0eb3f6e3b1b1f35 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:11 +0100 Subject: [PATCH 0241/1167] MIPS: pm-cps: Change FSB workaround to CPU blacklist The check for whether a CPU required the FSB flush workaround previously required every CPU not requiring it to be whitelisted. That approach does not scale well as new CPUs are introduced so change the default from a WARN and returning an error to just returning 0. Any CPUs requiring the workaround can then be added to the blacklist. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Adam Buchbinder Cc: Masahiro Yamada Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14218/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/pm-cps.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 5b31a9405ebc6..2faa227a032e7 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -272,14 +272,9 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, /* On older ones it's unavailable */ return -1; - /* CPUs which do not require the workaround */ - case CPU_P5600: - case CPU_I6400: - return 0; - default: - WARN_ONCE(1, "pm-cps: FSB flush unsupported for this CPU\n"); - return -1; + /* Assume that the CPU does not need this workaround */ + return 0; } /* -- GitLab From f6b43d935482abe28e9206ad10e1d2aa3fc78996 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:12 +0100 Subject: [PATCH 0242/1167] MIPS: pm-cps: Update comments on barrier instructions This code makes large use of barriers, which had quite vague descriptions. Update the comments to make the choice of barrier and reason for it more clear. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Adam Buchbinder Cc: Masahiro Yamada Cc: Kees Cook Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14220/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/pm-cps.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 2faa227a032e7..7e8d4aa22233a 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -315,7 +315,7 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, i * line_size * line_stride, t0); } - /* Completion barrier */ + /* Barrier ensuring previous cache invalidates are complete */ uasm_i_sync(pp, stype_memory); uasm_i_ehb(pp); @@ -414,7 +414,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_il_beqz(&p, &r, t2, lbl_incready); uasm_i_addiu(&p, t1, t1, 1); - /* Ordering barrier */ + /* Barrier ensuring all CPUs see the updated r_nc_count value */ uasm_i_sync(&p, stype_ordering); /* @@ -467,7 +467,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) cps_gen_cache_routine(&p, &l, &r, &cpu_data[cpu].dcache, Index_Writeback_Inv_D, lbl_flushdcache); - /* Completion barrier */ + /* Barrier ensuring previous cache invalidates are complete */ uasm_i_sync(&p, stype_memory); uasm_i_ehb(&p); @@ -480,7 +480,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_i_sw(&p, t0, 0, r_pcohctl); uasm_i_lw(&p, t0, 0, r_pcohctl); - /* Sync to ensure previous interventions are complete */ + /* Barrier to ensure write to coherence control is complete */ uasm_i_sync(&p, stype_intervention); uasm_i_ehb(&p); @@ -526,7 +526,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) goto gen_done; } - /* Completion barrier */ + /* Barrier to ensure write to CPC command is complete */ uasm_i_sync(&p, stype_memory); uasm_i_ehb(&p); } @@ -561,7 +561,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_i_sw(&p, t0, 0, r_pcohctl); uasm_i_lw(&p, t0, 0, r_pcohctl); - /* Completion barrier */ + /* Barrier to ensure write to coherence control is complete */ uasm_i_sync(&p, stype_memory); uasm_i_ehb(&p); @@ -575,7 +575,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_il_beqz(&p, &r, t2, lbl_decready); uasm_i_andi(&p, v0, t1, (1 << fls(smp_num_siblings)) - 1); - /* Ordering barrier */ + /* Barrier ensuring all CPUs see the updated r_nc_count value */ uasm_i_sync(&p, stype_ordering); } @@ -597,7 +597,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) */ uasm_build_label(&l, p, lbl_secondary_cont); - /* Ordering barrier */ + /* Barrier ensuring all CPUs see the updated r_nc_count value */ uasm_i_sync(&p, stype_ordering); } -- GitLab From 6622ada354ba2c865c6ee1854e130c3abb430808 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:13 +0100 Subject: [PATCH 0243/1167] MIPS: Barrier: Add definitions of SYNC stype values Add the definitions of sync stype 0 (global completion barrier) and sync stype 0x10 (local ordering barrier) to barrier.h for use with the sync instruction. These types are defined by the MIPS Instruction Set since R2 of the architecture and are documented in document MD00087 table 6.5. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Arnd Bergmann Cc: Michael S. Tsirkin Cc: Peter Zijlstra Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14222/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/barrier.h | 96 +++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/arch/mips/include/asm/barrier.h b/arch/mips/include/asm/barrier.h index d296633d890e5..a5eb1bb199a7f 100644 --- a/arch/mips/include/asm/barrier.h +++ b/arch/mips/include/asm/barrier.h @@ -10,6 +10,102 @@ #include +/* + * Sync types defined by the MIPS architecture (document MD00087 table 6.5) + * These values are used with the sync instruction to perform memory barriers. + * Types of ordering guarantees available through the SYNC instruction: + * - Completion Barriers + * - Ordering Barriers + * As compared to the completion barrier, the ordering barrier is a + * lighter-weight operation as it does not require the specified instructions + * before the SYNC to be already completed. Instead it only requires that those + * specified instructions which are subsequent to the SYNC in the instruction + * stream are never re-ordered for processing ahead of the specified + * instructions which are before the SYNC in the instruction stream. + * This potentially reduces how many cycles the barrier instruction must stall + * before it completes. + * Implementations that do not use any of the non-zero values of stype to define + * different barriers, such as ordering barriers, must make those stype values + * act the same as stype zero. + */ + +/* + * Completion barriers: + * - Every synchronizable specified memory instruction (loads or stores or both) + * that occurs in the instruction stream before the SYNC instruction must be + * already globally performed before any synchronizable specified memory + * instructions that occur after the SYNC are allowed to be performed, with + * respect to any other processor or coherent I/O module. + * + * - The barrier does not guarantee the order in which instruction fetches are + * performed. + * + * - A stype value of zero will always be defined such that it performs the most + * complete set of synchronization operations that are defined.This means + * stype zero always does a completion barrier that affects both loads and + * stores preceding the SYNC instruction and both loads and stores that are + * subsequent to the SYNC instruction. Non-zero values of stype may be defined + * by the architecture or specific implementations to perform synchronization + * behaviors that are less complete than that of stype zero. If an + * implementation does not use one of these non-zero values to define a + * different synchronization behavior, then that non-zero value of stype must + * act the same as stype zero completion barrier. This allows software written + * for an implementation with a lighter-weight barrier to work on another + * implementation which only implements the stype zero completion barrier. + * + * - A completion barrier is required, potentially in conjunction with SSNOP (in + * Release 1 of the Architecture) or EHB (in Release 2 of the Architecture), + * to guarantee that memory reference results are visible across operating + * mode changes. For example, a completion barrier is required on some + * implementations on entry to and exit from Debug Mode to guarantee that + * memory effects are handled correctly. + */ + +/* + * stype 0 - A completion barrier that affects preceding loads and stores and + * subsequent loads and stores. + * Older instructions which must reach the load/store ordering point before the + * SYNC instruction completes: Loads, Stores + * Younger instructions which must reach the load/store ordering point only + * after the SYNC instruction completes: Loads, Stores + * Older instructions which must be globally performed when the SYNC instruction + * completes: Loads, Stores + */ +#define STYPE_SYNC 0x0 + +/* + * Ordering barriers: + * - Every synchronizable specified memory instruction (loads or stores or both) + * that occurs in the instruction stream before the SYNC instruction must + * reach a stage in the load/store datapath after which no instruction + * re-ordering is possible before any synchronizable specified memory + * instruction which occurs after the SYNC instruction in the instruction + * stream reaches the same stage in the load/store datapath. + * + * - If any memory instruction before the SYNC instruction in program order, + * generates a memory request to the external memory and any memory + * instruction after the SYNC instruction in program order also generates a + * memory request to external memory, the memory request belonging to the + * older instruction must be globally performed before the time the memory + * request belonging to the younger instruction is globally performed. + * + * - The barrier does not guarantee the order in which instruction fetches are + * performed. + */ + +/* + * stype 0x10 - An ordering barrier that affects preceding loads and stores and + * subsequent loads and stores. + * Older instructions which must reach the load/store ordering point before the + * SYNC instruction completes: Loads, Stores + * Younger instructions which must reach the load/store ordering point only + * after the SYNC instruction completes: Loads, Stores + * Older instructions which must be globally performed when the SYNC instruction + * completes: N/A + */ +#define STYPE_SYNC_MB 0x10 + + #ifdef CONFIG_CPU_HAS_SYNC #define __sync() \ __asm__ __volatile__( \ -- GitLab From 85e540be7549c8eda90f056d30534be8f58777a7 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:14 +0100 Subject: [PATCH 0244/1167] MIPS: pm-cps: Use MIPS standard lightweight ordering barrier Since R2 of the MIPS architecture, SYNC(0x10) has been an optional but architecturally defined ordering barrier. If a CPU does not implement it, the arch specifies that it must fall back to SYNC(0). In places where we require that the instruction stream not be reordered, but do not require that loads / stores are gloablly completed, use the defined standard sync stype. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Adam Buchbinder Cc: Masahiro Yamada Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14221/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/pm-cps.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 7e8d4aa22233a..d7037fe00d1c3 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -76,7 +76,6 @@ static struct uasm_reloc relocs[32] __initdata; /* CPU dependant sync types */ static unsigned stype_intervention; static unsigned stype_memory; -static unsigned stype_ordering; enum mips_reg { zero, at, v0, v1, a0, a1, a2, a3, @@ -406,7 +405,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) if (coupled_coherence) { /* Increment ready_count */ - uasm_i_sync(&p, stype_ordering); + uasm_i_sync(&p, STYPE_SYNC_MB); uasm_build_label(&l, p, lbl_incready); uasm_i_ll(&p, t1, 0, r_nc_count); uasm_i_addiu(&p, t2, t1, 1); @@ -415,7 +414,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_i_addiu(&p, t1, t1, 1); /* Barrier ensuring all CPUs see the updated r_nc_count value */ - uasm_i_sync(&p, stype_ordering); + uasm_i_sync(&p, STYPE_SYNC_MB); /* * If this is the last VPE to become ready for non-coherence @@ -568,7 +567,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) if (coupled_coherence && (state == CPS_PM_NC_WAIT)) { /* Decrement ready_count */ uasm_build_label(&l, p, lbl_decready); - uasm_i_sync(&p, stype_ordering); + uasm_i_sync(&p, STYPE_SYNC_MB); uasm_i_ll(&p, t1, 0, r_nc_count); uasm_i_addiu(&p, t2, t1, -1); uasm_i_sc(&p, t2, 0, r_nc_count); @@ -576,7 +575,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_i_andi(&p, v0, t1, (1 << fls(smp_num_siblings)) - 1); /* Barrier ensuring all CPUs see the updated r_nc_count value */ - uasm_i_sync(&p, stype_ordering); + uasm_i_sync(&p, STYPE_SYNC_MB); } if (coupled_coherence && (state == CPS_PM_CLOCK_GATED)) { @@ -598,7 +597,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_build_label(&l, p, lbl_secondary_cont); /* Barrier ensuring all CPUs see the updated r_nc_count value */ - uasm_i_sync(&p, stype_ordering); + uasm_i_sync(&p, STYPE_SYNC_MB); } /* The core is coherent, time to return to C code */ @@ -677,7 +676,6 @@ static int __init cps_pm_init(void) case CPU_I6400: stype_intervention = 0x2; stype_memory = 0x3; - stype_ordering = 0x10; break; default: -- GitLab From 90b084b1bc7ebde5379017c29ae617fcc4ccd557 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:15 +0100 Subject: [PATCH 0245/1167] MIPS: pm-cps: Use MIPS standard completion barrier SYNC type 0 is defined in the MIPS architecture as a completion barrier where all loads/stores in the pipeline before the sync instruction must complete before any loads/stores subsequent to the sync instruction. In places where we require loads / stores be globally completed, use the standard completion sync stype. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Adam Buchbinder Cc: Masahiro Yamada Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14224/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/pm-cps.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index d7037fe00d1c3..953ff0db90612 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -315,7 +315,7 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, } /* Barrier ensuring previous cache invalidates are complete */ - uasm_i_sync(pp, stype_memory); + uasm_i_sync(pp, STYPE_SYNC); uasm_i_ehb(pp); /* Check whether the pipeline stalled due to the FSB being full */ @@ -467,7 +467,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) Index_Writeback_Inv_D, lbl_flushdcache); /* Barrier ensuring previous cache invalidates are complete */ - uasm_i_sync(&p, stype_memory); + uasm_i_sync(&p, STYPE_SYNC); uasm_i_ehb(&p); /* @@ -480,7 +480,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_i_lw(&p, t0, 0, r_pcohctl); /* Barrier to ensure write to coherence control is complete */ - uasm_i_sync(&p, stype_intervention); + uasm_i_sync(&p, STYPE_SYNC); uasm_i_ehb(&p); /* Disable coherence */ @@ -526,7 +526,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) } /* Barrier to ensure write to CPC command is complete */ - uasm_i_sync(&p, stype_memory); + uasm_i_sync(&p, STYPE_SYNC); uasm_i_ehb(&p); } @@ -561,7 +561,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_i_lw(&p, t0, 0, r_pcohctl); /* Barrier to ensure write to coherence control is complete */ - uasm_i_sync(&p, stype_memory); + uasm_i_sync(&p, STYPE_SYNC); uasm_i_ehb(&p); if (coupled_coherence && (state == CPS_PM_NC_WAIT)) { -- GitLab From 15ea26cf510ce07c9397579ce869f7f3713eaae4 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:16 +0100 Subject: [PATCH 0246/1167] MIPS: pm-cps: Remove selection of sync types Instead of selecting an implementation or vendor specific sync type for the required sync operations, always use the architecturally mandated sync types which previous patches have put in place. The selection of special sync types is now redundant an can be removed. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Adam Buchbinder Cc: Masahiro Yamada Cc: Kees Cook Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14223/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/pm-cps.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 953ff0db90612..b3a7d36ada5ae 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -73,10 +73,6 @@ DEFINE_PER_CPU_ALIGNED(struct mips_static_suspend_state, cps_cpu_state); static struct uasm_label labels[32] __initdata; static struct uasm_reloc relocs[32] __initdata; -/* CPU dependant sync types */ -static unsigned stype_intervention; -static unsigned stype_memory; - enum mips_reg { zero, at, v0, v1, a0, a1, a2, a3, t0, t1, t2, t3, t4, t5, t6, t7, @@ -667,21 +663,6 @@ static int __init cps_pm_init(void) unsigned cpu; int err; - /* Detect appropriate sync types for the system */ - switch (current_cpu_data.cputype) { - case CPU_INTERAPTIV: - case CPU_PROAPTIV: - case CPU_M5150: - case CPU_P5600: - case CPU_I6400: - stype_intervention = 0x2; - stype_memory = 0x3; - break; - - default: - pr_warn("Power management is using heavyweight sync 0\n"); - } - /* A CM is required for all non-coherent states */ if (!mips_cm_present()) { pr_warn("pm-cps: no CM, non-coherent states unavailable\n"); -- GitLab From 929d4f51e6b87900c9179eb62d6b43db6ce4930d Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:17 +0100 Subject: [PATCH 0247/1167] MIPS: pm-cps: Add MIPSr6 CPU support This patch adds support for CPUs implementing the MIPSr6 ISA to the CPS power management code. Three changes are necessary: 1. In MIPSr6, coupled coherence is necessary when CPUS implement multiple Virtual Processors (VPs). 2. MIPSr6 virtual processors are more like real cores and cannot yield to other VPs on the same core, so drop the MT ASE yield instruction. 3. To halt a MIPSr6 VP, the CPC VP_STOP register is used rather than the MT ASE TCHalt CP0 register. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Adam Buchbinder Cc: Masahiro Yamada Cc: Kees Cook Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14225/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pm-cps.h | 6 ++++-- arch/mips/kernel/pm-cps.c | 22 ++++++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/asm/pm-cps.h b/arch/mips/include/asm/pm-cps.h index 625eda53d5716..89d58d80b77bb 100644 --- a/arch/mips/include/asm/pm-cps.h +++ b/arch/mips/include/asm/pm-cps.h @@ -13,10 +13,12 @@ /* * The CM & CPC can only handle coherence & power control on a per-core basis, - * thus in an MT system the VPEs within each core are coupled and can only + * thus in an MT system the VP(E)s within each core are coupled and can only * enter or exit states requiring CM or CPC assistance in unison. */ -#ifdef CONFIG_MIPS_MT +#if defined(CONFIG_CPU_MIPSR6) +# define coupled_coherence cpu_has_vp +#elif defined(CONFIG_MIPS_MT) # define coupled_coherence cpu_has_mipsmt #else # define coupled_coherence 0 diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index b3a7d36ada5ae..440e792595664 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -129,7 +129,7 @@ int cps_pm_enter_state(enum cps_pm_state state) return -EINVAL; /* Calculate which coupled CPUs (VPEs) are online */ -#ifdef CONFIG_MIPS_MT +#if defined(CONFIG_MIPS_MT) || defined(CONFIG_CPU_MIPSR6) if (cpu_online(cpu)) { cpumask_and(coupled_mask, cpu_online_mask, &cpu_sibling_map[cpu]); @@ -431,7 +431,8 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_i_lw(&p, t0, 0, r_nc_count); uasm_il_bltz(&p, &r, t0, lbl_secondary_cont); uasm_i_ehb(&p); - uasm_i_yield(&p, zero, t1); + if (cpu_has_mipsmt) + uasm_i_yield(&p, zero, t1); uasm_il_b(&p, &r, lbl_poll_cont); uasm_i_nop(&p); } else { @@ -439,8 +440,21 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) * The core will lose power & this VPE will not continue * so it can simply halt here. */ - uasm_i_addiu(&p, t0, zero, TCHALT_H); - uasm_i_mtc0(&p, t0, 2, 4); + if (cpu_has_mipsmt) { + /* Halt the VPE via C0 tchalt register */ + uasm_i_addiu(&p, t0, zero, TCHALT_H); + uasm_i_mtc0(&p, t0, 2, 4); + } else if (cpu_has_vp) { + /* Halt the VP via the CPC VP_STOP register */ + unsigned int vpe_id; + + vpe_id = cpu_vpe_id(&cpu_data[cpu]); + uasm_i_addiu(&p, t0, zero, 1 << vpe_id); + UASM_i_LA(&p, t1, (long)addr_cpc_cl_vp_stop()); + uasm_i_sw(&p, t0, 0, t1); + } else { + BUG(); + } uasm_build_label(&l, p, lbl_secondary_hang); uasm_il_b(&p, &r, lbl_secondary_hang); uasm_i_nop(&p); -- GitLab From 77451997237fa7e8ba4f5e2f0fcd99898f78ff9b Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:18 +0100 Subject: [PATCH 0248/1167] MIPS: pm-cps: Support CM3 changes to Coherence Enable Register MIPS CM3 changed the management of coherence. Instead of a coherence control register with a bitmask of coherent domains, CM3 simply has a coherence enable register with a single bit to enable coherence of the local core. Support this by clearing and setting this single bit to disable / enable coherence. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Adam Buchbinder Cc: Tony Wu Cc: Masahiro Yamada Cc: Nikolay Martynov Cc: Kees Cook Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14226/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cm.h | 1 + arch/mips/kernel/pm-cps.c | 31 ++++++++++++++++++------------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 4fafeefe65c2a..2e4180797b218 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -359,6 +359,7 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) /* GCR_Cx_COHERENCE register fields */ #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF 0 #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK (_ULCAST_(0xff) << 0) +#define CM3_GCR_Cx_COHERENCE_COHEN_MSK (_ULCAST_(0x1) << 0) /* GCR_Cx_CONFIG register fields */ #define CM_GCR_Cx_CONFIG_IOCUTYPE_SHF 10 diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 440e792595664..05bcdedcf9bdb 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -480,18 +480,20 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) uasm_i_sync(&p, STYPE_SYNC); uasm_i_ehb(&p); - /* - * Disable all but self interventions. The load from COHCTL is defined - * by the interAptiv & proAptiv SUMs as ensuring that the operation - * resulting from the preceding store is complete. - */ - uasm_i_addiu(&p, t0, zero, 1 << cpu_data[cpu].core); - uasm_i_sw(&p, t0, 0, r_pcohctl); - uasm_i_lw(&p, t0, 0, r_pcohctl); - - /* Barrier to ensure write to coherence control is complete */ - uasm_i_sync(&p, STYPE_SYNC); - uasm_i_ehb(&p); + if (mips_cm_revision() < CM_REV_CM3) { + /* + * Disable all but self interventions. The load from COHCTL is + * defined by the interAptiv & proAptiv SUMs as ensuring that the + * operation resulting from the preceding store is complete. + */ + uasm_i_addiu(&p, t0, zero, 1 << cpu_data[cpu].core); + uasm_i_sw(&p, t0, 0, r_pcohctl); + uasm_i_lw(&p, t0, 0, r_pcohctl); + + /* Barrier to ensure write to coherence control is complete */ + uasm_i_sync(&p, STYPE_SYNC); + uasm_i_ehb(&p); + } /* Disable coherence */ uasm_i_sw(&p, zero, 0, r_pcohctl); @@ -566,7 +568,10 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) * will run this. The first will actually re-enable coherence & the * rest will just be performing a rather unusual nop. */ - uasm_i_addiu(&p, t0, zero, CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK); + uasm_i_addiu(&p, t0, zero, mips_cm_revision() < CM_REV_CM3 + ? CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK + : CM3_GCR_Cx_COHERENCE_COHEN_MSK); + uasm_i_sw(&p, t0, 0, r_pcohctl); uasm_i_lw(&p, t0, 0, r_pcohctl); -- GitLab From 4b6401365a6ccc53de820209cb328507a2103d30 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:19 +0100 Subject: [PATCH 0249/1167] MIPS: SMP: Wrap call to mips_cpc_lock_other in mips_cm_lock_other All calls to mips_cpc_lock_other should be wrapped in mips_cm_lock_other. This only matters if the system has CM3 and is using cpu idle, since otherwise a) the CPC lock is sufficent for CM < 3 and b) any systems with CM > 3 have not been able to use cpu idle until now. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: Thomas Gleixner Cc: James Hogan Cc: Qais Yousef Patchwork: https://patchwork.linux-mips.org/patch/14227/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index b0baf48951faa..cb02df215365d 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -192,9 +192,11 @@ void mips_smp_send_ipi_mask(const struct cpumask *mask, unsigned int action) continue; while (!cpumask_test_cpu(cpu, &cpu_coherent_mask)) { + mips_cm_lock_other(core, 0); mips_cpc_lock_other(core); write_cpc_co_cmd(CPC_Cx_CMD_PWRUP); mips_cpc_unlock_other(); + mips_cm_unlock_other(); } } } -- GitLab From 72bc8c75eaf72aa0e45652d09f1b80dd5346797e Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:20 +0100 Subject: [PATCH 0250/1167] cpuidle: cpuidle-cps: Enable use with MIPSr6 CPUs. This patch enables the MIPS CPS driver for MIPSr6 CPUs. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Reviewed-by: Daniel Lezcano Cc: Rafael J. Wysocki Cc: linux-mips@linux-mips.org Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14228/ Signed-off-by: Ralf Baechle --- drivers/cpuidle/Kconfig.mips | 2 +- drivers/cpuidle/cpuidle-cps.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpuidle/Kconfig.mips b/drivers/cpuidle/Kconfig.mips index 4102be01d06a0..512ee37b374b1 100644 --- a/drivers/cpuidle/Kconfig.mips +++ b/drivers/cpuidle/Kconfig.mips @@ -5,7 +5,7 @@ config MIPS_CPS_CPUIDLE bool "CPU Idle driver for MIPS CPS platforms" depends on CPU_IDLE && MIPS_CPS depends on SYS_SUPPORTS_MIPS_CPS - select ARCH_NEEDS_CPU_IDLE_COUPLED if MIPS_MT + select ARCH_NEEDS_CPU_IDLE_COUPLED if MIPS_MT || CPU_MIPSR6 select GENERIC_CLOCKEVENTS_BROADCAST if SMP select MIPS_CPS_PM default y diff --git a/drivers/cpuidle/cpuidle-cps.c b/drivers/cpuidle/cpuidle-cps.c index 1adb6980b707c..926ba9871c628 100644 --- a/drivers/cpuidle/cpuidle-cps.c +++ b/drivers/cpuidle/cpuidle-cps.c @@ -163,7 +163,7 @@ static int __init cps_cpuidle_init(void) core = cpu_data[cpu].core; device = &per_cpu(cpuidle_dev, cpu); device->cpu = cpu; -#ifdef CONFIG_MIPS_MT +#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED cpumask_copy(&device->coupled_cpus, &cpu_sibling_map[cpu]); #endif -- GitLab From 18022894eca1315851bfd0614f011fbc01e44d16 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 1 Sep 2016 17:30:07 +0100 Subject: [PATCH 0251/1167] MIPS: traps: 64bit kernels should read CP0_EBase 64bit When reading the CP0_EBase register containing the WG (write gate) bit, the ebase variable should be set to the full value of the register, i.e. on a 64-bit kernel the full 64-bit width of the register via read_cp0_ebase_64(), and on a 32-bit kernel the full 32-bit width including bits 31:30 which may be writeable. Signed-off-by: James Hogan Signed-off-by: Matt Redfearn Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14148/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 6061d47c57c9c..4b60fb53b6043 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2215,8 +2215,17 @@ void __init trap_init(void) } else { ebase = CAC_BASE; - if (cpu_has_mips_r2_r6) - ebase += (read_c0_ebase() & 0x3ffff000); + if (cpu_has_mips_r2_r6) { + if (cpu_has_ebase_wg) { +#ifdef CONFIG_64BIT + ebase = (read_c0_ebase_64() & ~0xfff); +#else + ebase = (read_c0_ebase() & ~0xfff); +#endif + } else { + ebase += (read_c0_ebase() & 0x3ffff000); + } + } } if (cpu_has_mmips) { -- GitLab From c195e079e9dd00ffeb274965737280ca6d10ff70 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 1 Sep 2016 17:30:08 +0100 Subject: [PATCH 0252/1167] MIPS: traps: Convert ebase to KSEG0 When allocating boot memory for the exception vector when vectored interrupts (vint) or vectored external interrupt controllers (veic) are enabled, try to ensure that the virtual address resides in KSeg0 (and WARN should that not be possible). This will be helpful on MIPS64 cores supporting the CP0_EBase Write Gate (WG) bit once we start using the WG bit to write the full ebase into CP0_EBase, as we ideally need to avoid hitting the architecturally poorly defined exception base for Cache Errors when CP0_EBase is in XKPhys. An exception is made for Enhanced Virtual Addressing (EVA) kernels which allow segments to be rearranged and to become uncached during cache error handling, making it valid for ebase to be elsewhere. Signed-off-by: James Hogan Cc: Matt Redfearn Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14149/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 4b60fb53b6043..edc0c3d8e3865 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2210,8 +2210,25 @@ void __init trap_init(void) if (cpu_has_veic || cpu_has_vint) { unsigned long size = 0x200 + VECTORSPACING*64; + phys_addr_t ebase_pa; + ebase = (unsigned long) __alloc_bootmem(size, 1 << fls(size), 0); + + /* + * Try to ensure ebase resides in KSeg0 if possible. + * + * It shouldn't generally be in XKPhys on MIPS64 to avoid + * hitting a poorly defined exception base for Cache Errors. + * The allocation is likely to be in the low 512MB of physical, + * in which case we should be able to convert to KSeg0. + * + * EVA is special though as it allows segments to be rearranged + * and to become uncached during cache error handling. + */ + ebase_pa = __pa(ebase); + if (!IS_ENABLED(CONFIG_EVA) && !WARN_ON(ebase_pa >= 0x20000000)) + ebase = CKSEG0ADDR(ebase_pa); } else { ebase = CAC_BASE; -- GitLab From 4b22c693e325af075d78069e25d6c17cb102c73e Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Thu, 1 Sep 2016 17:30:09 +0100 Subject: [PATCH 0253/1167] MIPS: traps: Ensure full EBase is written On CPUs which support the EBase WG (write gate) flag, the most significant bits of the exception base can be changed. Firmware running on a VP(E) using MIPS rproc may change EBase to point into the user segment where the firmware is located such that it can service interrupts. When control is transferred back to the kernel the EBase must be switched back into the kernel segment, such that the kernel's exception vectors are used. Similarly when vectored interrupts (vint) or vectored external interrupt controllers (veic) are enabled an exception vector is allocated from bootmem, and written to the EBase register. Due to the WG flag being clear, only bits 29:12 will be written. Asside from the rproc case above this is normally fine (as it will usually be a low allocation within the KSeg0 range, however when Enhanced Virtual Addressing (EVA) is enabled the allocation may be outside of the traditional KSeg0/KSeg1 address range, resulting in the wrong EBase being written. Correct both cases (configure_exception_vector() for the boot CPU, and per_cpu_trap_init() for secondary CPUs) to write EBase with the WG flag first if supported. On the Malta EVA configuration, KSeg0 is mapped to physical address 0, and memory is allocated from the KUSeg segment which is mapped to physical address 0x80000000, which physically aliases the RAM at 0. This only worked due to the exception base address aliasing the same underlying RAM that was written to & cache flushed, and due to flush_icache_range() going beyond the call of duty and flushing from the L2 cache too (due to the differing physical addresses). Signed-off-by: Matt Redfearn Signed-off-by: James Hogan Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14150/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index edc0c3d8e3865..0c0270c29cd1f 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2092,6 +2092,14 @@ static void configure_exception_vector(void) { if (cpu_has_veic || cpu_has_vint) { unsigned long sr = set_c0_status(ST0_BEV); + /* If available, use WG to set top bits of EBASE */ + if (cpu_has_ebase_wg) { +#ifdef CONFIG_64BIT + write_c0_ebase_64(ebase | MIPS_EBASE_WG); +#else + write_c0_ebase(ebase | MIPS_EBASE_WG); +#endif + } write_c0_ebase(ebase); write_c0_status(sr); /* Setting vector spacing enables EI/VI mode */ @@ -2128,8 +2136,17 @@ void per_cpu_trap_init(bool is_boot_cpu) * We shouldn't trust a secondary core has a sane EBASE register * so use the one calculated by the boot CPU. */ - if (!is_boot_cpu) + if (!is_boot_cpu) { + /* If available, use WG to set top bits of EBASE */ + if (cpu_has_ebase_wg) { +#ifdef CONFIG_64BIT + write_c0_ebase_64(ebase | MIPS_EBASE_WG); +#else + write_c0_ebase(ebase | MIPS_EBASE_WG); +#endif + } write_c0_ebase(ebase); + } cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP; cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7; -- GitLab From d260d97e64c0d988eab3c420ab1497037d1af26f Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 1 Sep 2016 17:30:10 +0100 Subject: [PATCH 0254/1167] MIPS: c-r4k: Drop bc_wback_inv() from icache flush The EVA conditional bc_wback_inv() at the end of flush_icache_range() to flush the modified code all the way back to RAM was apparently there for debug purposes and to accommodate the Malta EVA configuration which makes use of a physical alias, and didn't use the CP0_EBase.WG (Write Gate) bit to put the exception vector in the same physical alias where the exception vector code is written and is being flushed. Now that CP0_EBase.WG is used, lets drop this flush. Signed-off-by: James Hogan Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14151/ Signed-off-by: Ralf Baechle --- arch/mips/mm/c-r4k.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index fa7d8d3790bfc..bbb7dfea40f9f 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -752,17 +752,6 @@ static inline void __local_r4k_flush_icache_range(unsigned long start, break; } } -#ifdef CONFIG_EVA - /* - * Due to all possible segment mappings, there might cache aliases - * caused by the bootloader being in non-EVA mode, and the CPU switching - * to EVA during early kernel init. It's best to flush the scache - * to avoid having secondary cores fetching stale data and lead to - * kernel crashes. - */ - bc_wback_inv(start, (end - start)); - __sync(); -#endif } static inline void local_r4k_flush_icache_range(unsigned long start, -- GitLab From 01882b4d5eae2800c8e86a29d279020f87e5d4f3 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 1 Sep 2016 17:30:11 +0100 Subject: [PATCH 0255/1167] MIPS: c-r4k: Split user/kernel flush_icache_range() flush_icache_range() is used for both user addresses (i.e. cacheflush(2)), and kernel addresses (as the API documentation describes). This isn't really suitable however for Enhanced Virtual Addressing (EVA) where cache operations on usermode addresses must use a different instruction, and the protected cache ops assume user addresses, making flush_icache_range() ineffective on kernel addresses. Split out a new __flush_icache_user_range() and __local_flush_icache_user_range() for users which actually want to flush usermode addresses (note that flush_icache_user_range() already exists on various architectures but with different arguments). The implementation of flush_icache_range() will be changed in an upcoming commit to use unprotected normal cache ops so as to always work on the kernel mode address space. Signed-off-by: James Hogan Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14152/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cacheflush.h | 5 +++++ arch/mips/mm/c-octeon.c | 2 ++ arch/mips/mm/c-r3k.c | 2 ++ arch/mips/mm/c-r4k.c | 2 ++ arch/mips/mm/c-tx39.c | 3 +++ arch/mips/mm/cache.c | 4 ++++ 6 files changed, 18 insertions(+) diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h index 34ed22ec6c33e..4812d1fed0c2c 100644 --- a/arch/mips/include/asm/cacheflush.h +++ b/arch/mips/include/asm/cacheflush.h @@ -28,6 +28,7 @@ * - flush_cache_sigtramp() flush signal trampoline * - flush_icache_all() flush the entire instruction cache * - flush_data_cache_page() flushes a page from the data cache + * - __flush_icache_user_range(start, end) flushes range of user instructions */ /* @@ -80,6 +81,10 @@ static inline void flush_icache_page(struct vm_area_struct *vma, extern void (*flush_icache_range)(unsigned long start, unsigned long end); extern void (*local_flush_icache_range)(unsigned long start, unsigned long end); +extern void (*__flush_icache_user_range)(unsigned long start, + unsigned long end); +extern void (*__local_flush_icache_user_range)(unsigned long start, + unsigned long end); extern void (*__flush_cache_vmap)(void); diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c index 05b1d7cf9514c..0e45b061e5141 100644 --- a/arch/mips/mm/c-octeon.c +++ b/arch/mips/mm/c-octeon.c @@ -294,6 +294,8 @@ void octeon_cache_init(void) flush_data_cache_page = octeon_flush_data_cache_page; flush_icache_range = octeon_flush_icache_range; local_flush_icache_range = local_octeon_flush_icache_range; + __flush_icache_user_range = octeon_flush_icache_range; + __local_flush_icache_user_range = local_octeon_flush_icache_range; __flush_kernel_vmap_range = octeon_flush_kernel_vmap_range; diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index 135ec313c1f65..21e4e662c1fa6 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c @@ -325,6 +325,8 @@ void r3k_cache_init(void) flush_cache_page = r3k_flush_cache_page; flush_icache_range = r3k_flush_icache_range; local_flush_icache_range = r3k_flush_icache_range; + __flush_icache_user_range = r3k_flush_icache_range; + __local_flush_icache_user_range = r3k_flush_icache_range; __flush_kernel_vmap_range = r3k_flush_kernel_vmap_range; diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index bbb7dfea40f9f..5e0a44a0c5572 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1904,6 +1904,8 @@ void r4k_cache_init(void) flush_data_cache_page = r4k_flush_data_cache_page; flush_icache_range = r4k_flush_icache_range; local_flush_icache_range = local_r4k_flush_icache_range; + __flush_icache_user_range = r4k_flush_icache_range; + __local_flush_icache_user_range = local_r4k_flush_icache_range; #if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT) if (coherentio) { diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c index 596e18458e041..5c282583edf16 100644 --- a/arch/mips/mm/c-tx39.c +++ b/arch/mips/mm/c-tx39.c @@ -411,6 +411,9 @@ void tx39_cache_init(void) break; } + __flush_icache_user_range = flush_icache_range; + __local_flush_icache_user_range = local_flush_icache_range; + current_cpu_data.icache.waysize = icache_size / current_cpu_data.icache.ways; current_cpu_data.dcache.waysize = dcache_size / current_cpu_data.dcache.ways; diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index bf04c6c479a4e..5a644c3fe1551 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -33,6 +33,10 @@ void (*flush_icache_range)(unsigned long start, unsigned long end); EXPORT_SYMBOL_GPL(flush_icache_range); void (*local_flush_icache_range)(unsigned long start, unsigned long end); EXPORT_SYMBOL_GPL(local_flush_icache_range); +void (*__flush_icache_user_range)(unsigned long start, unsigned long end); +EXPORT_SYMBOL_GPL(__flush_icache_user_range); +void (*__local_flush_icache_user_range)(unsigned long start, unsigned long end); +EXPORT_SYMBOL_GPL(__local_flush_icache_user_range); void (*__flush_cache_vmap)(void); void (*__flush_cache_vunmap)(void); -- GitLab From 8e3a9f4c3ab6dd0da5e8a89bd252518ff2ee5e3a Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 1 Sep 2016 17:30:12 +0100 Subject: [PATCH 0256/1167] MIPS: cacheflush: Use __flush_icache_user_range() The cacheflush(2) system call uses flush_icache_range() to flush a range of usermode addresses from the icache, so change it to utilise the new __flush_icache_user_range() API to allow the more generic flush_icache_range() to be changed to work on kernel addresses only. Signed-off-by: James Hogan Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14153/ Signed-off-by: Ralf Baechle --- arch/mips/mm/cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 5a644c3fe1551..7ec0847c725a3 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -78,7 +78,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, if (!access_ok(VERIFY_WRITE, (void __user *) addr, bytes)) return -EFAULT; - flush_icache_range(addr, addr + bytes); + __flush_icache_user_range(addr, addr + bytes); return 0; } -- GitLab From d99a043a9a506290a0aac6746a8e412df3dafbfb Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 1 Sep 2016 17:30:13 +0100 Subject: [PATCH 0257/1167] MIPS: uprobes: Flush icache via kernel address Update arch_uprobe_copy_ixol() to use the kmap_atomic() based kernel address to flush the icache with flush_icache_range(), rather than the user mapping. We have the kernel mapping available anyway and this avoids having to switch to using the new __flush_icache_user_range() for the sake of Enhanced Virtual Addressing (EVA) where flush_icache_range() will become ineffective on user addresses. Signed-off-by: James Hogan Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14154/ Patchwork: https://patchwork.linux-mips.org/patch/14308/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/uprobes.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/arch/mips/kernel/uprobes.c b/arch/mips/kernel/uprobes.c index 4c7c1558944a2..15ad17cb2b6e4 100644 --- a/arch/mips/kernel/uprobes.c +++ b/arch/mips/kernel/uprobes.c @@ -282,19 +282,14 @@ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, void __weak arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, void *src, unsigned long len) { - void *kaddr; + unsigned long kaddr, kstart; /* Initialize the slot */ - kaddr = kmap_atomic(page); - memcpy(kaddr + (vaddr & ~PAGE_MASK), src, len); - kunmap_atomic(kaddr); - - /* - * The MIPS version of flush_icache_range will operate safely on - * user space addresses and more importantly, it doesn't require a - * VMA argument. - */ - flush_icache_range(vaddr, vaddr + len); + kaddr = (unsigned long)kmap_atomic(page); + kstart = kaddr + (vaddr & ~PAGE_MASK); + memcpy((void *)kstart, src, len); + flush_icache_range(kstart, kstart + len); + kunmap_atomic((void *)kaddr); } /** -- GitLab From 4777ac220c430173e297237b896932ed5fd8aaf3 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Tue, 4 Oct 2016 11:33:25 -0700 Subject: [PATCH 0258/1167] Input: ALPS - add touchstick support for SS5 hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add touchstick support for the so-called SS5 hardware, which uses a variant of the SS4 protocol. Reviewed-by: Pali Rohár Tested-by: Michal Hocko Signed-off-by: Ben Gamari Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 65 +++++++++++++++++++++++++++++++------- drivers/input/mouse/alps.h | 2 ++ 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 936f07a4e35f4..8e15783d29324 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1156,15 +1156,28 @@ static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte) { unsigned char pkt_id = SS4_PACKET_ID_IDLE; - if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 && - (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && byte[5] == 0x00) { - pkt_id = SS4_PACKET_ID_IDLE; - } else if (!(byte[3] & 0x10)) { - pkt_id = SS4_PACKET_ID_ONE; - } else if (!(byte[3] & 0x20)) { + switch (byte[3] & 0x30) { + case 0x00: + if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 && + (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && + byte[5] == 0x00) { + pkt_id = SS4_PACKET_ID_IDLE; + } else { + pkt_id = SS4_PACKET_ID_ONE; + } + break; + case 0x10: + /* two-finger finger positions */ pkt_id = SS4_PACKET_ID_TWO; - } else { + break; + case 0x20: + /* stick pointer */ + pkt_id = SS4_PACKET_ID_STICK; + break; + case 0x30: + /* third and fourth finger positions */ pkt_id = SS4_PACKET_ID_MULTI; + break; } return pkt_id; @@ -1246,16 +1259,38 @@ static int alps_decode_ss4_v2(struct alps_fields *f, } break; + case SS4_PACKET_ID_STICK: + if (!(priv->flags & ALPS_DUALPOINT)) { + psmouse_warn(psmouse, + "Rejected trackstick packet from non DualPoint device"); + } else { + int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f)); + int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f)); + + input_report_rel(priv->dev2, REL_X, x); + input_report_rel(priv->dev2, REL_Y, -y); + } + break; + case SS4_PACKET_ID_IDLE: default: memset(f, 0, sizeof(struct alps_fields)); break; } - f->left = !!(SS4_BTN_V2(p) & 0x01); - if (!(priv->flags & ALPS_BUTTONPAD)) { - f->right = !!(SS4_BTN_V2(p) & 0x02); - f->middle = !!(SS4_BTN_V2(p) & 0x04); + /* handle buttons */ + if (pkt_id == SS4_PACKET_ID_STICK) { + f->ts_left = !!(SS4_BTN_V2(p) & 0x01); + if (!(priv->flags & ALPS_BUTTONPAD)) { + f->ts_right = !!(SS4_BTN_V2(p) & 0x02); + f->ts_middle = !!(SS4_BTN_V2(p) & 0x04); + } + } else { + f->left = !!(SS4_BTN_V2(p) & 0x01); + if (!(priv->flags & ALPS_BUTTONPAD)) { + f->right = !!(SS4_BTN_V2(p) & 0x02); + f->middle = !!(SS4_BTN_V2(p) & 0x04); + } } return 0; @@ -1266,6 +1301,7 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) struct alps_data *priv = psmouse->private; unsigned char *packet = psmouse->packet; struct input_dev *dev = psmouse->dev; + struct input_dev *dev2 = priv->dev2; struct alps_fields *f = &priv->f; memset(f, 0, sizeof(struct alps_fields)); @@ -1311,6 +1347,13 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) input_report_abs(dev, ABS_PRESSURE, f->pressure); input_sync(dev); + + if (priv->flags & ALPS_DUALPOINT) { + input_report_key(dev2, BTN_LEFT, f->ts_left); + input_report_key(dev2, BTN_RIGHT, f->ts_right); + input_report_key(dev2, BTN_MIDDLE, f->ts_middle); + input_sync(dev2); + } } static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse) diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index d37f814dc4478..b9417e2d7ad3a 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -37,12 +37,14 @@ * or there's button activities. * SS4_PACKET_ID_TWO: There's two or more fingers on touchpad * SS4_PACKET_ID_MULTI: There's three or more fingers on touchpad + * SS4_PACKET_ID_STICK: A stick pointer packet */ enum SS4_PACKET_ID { SS4_PACKET_ID_IDLE = 0, SS4_PACKET_ID_ONE, SS4_PACKET_ID_TWO, SS4_PACKET_ID_MULTI, + SS4_PACKET_ID_STICK, }; #define SS4_COUNT_PER_ELECTRODE 256 -- GitLab From a831776323e7c532ef9c88d0d62512ae15d78415 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Tue, 4 Oct 2016 11:40:44 -0700 Subject: [PATCH 0259/1167] Input: ALPS - handle 0-pressure 1F events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While a button is held SS5 hardware will give us single-finger packets with x, y, and pressure equal to zero. This causes annoying jumps in pointer position if a touch is released while the button is held. Handle this by claiming zero contacts to ensure that no position events are provided to the user. Reviewed-by: Pali Rohár Tested-by: Michal Hocko Signed-off-by: Ben Gamari Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 8e15783d29324..a76e5c6fce54f 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1198,7 +1198,13 @@ static int alps_decode_ss4_v2(struct alps_fields *f, f->mt[0].x = SS4_1F_X_V2(p); f->mt[0].y = SS4_1F_Y_V2(p); f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f; - f->fingers = 1; + /* + * When a button is held the device will give us events + * with x, y, and pressure of 0. This causes annoying jumps + * if a touch is released while the button is held. + * Handle this by claiming zero contacts. + */ + f->fingers = f->pressure > 0 ? 1 : 0; f->first_mp = 0; f->is_mp = 0; break; -- GitLab From 7ad8a1067dfc3bf74ad2daef013ea4f3df1841a7 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Tue, 4 Oct 2016 11:41:58 -0700 Subject: [PATCH 0260/1167] Input: ALPS - allow touchsticks to report pressure The SS5 hardware can report this. Tested-by: Michal Hocko Signed-off-by: Ben Gamari Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index a76e5c6fce54f..bb0b7230cf3b1 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -103,6 +103,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = { 6-byte ALPS packet */ #define ALPS_STICK_BITS 0x100 /* separate stick button bits */ #define ALPS_BUTTONPAD 0x200 /* device is a clickpad */ +#define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */ static const struct alps_model_info alps_model_data[] = { { { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ @@ -1272,9 +1273,11 @@ static int alps_decode_ss4_v2(struct alps_fields *f, } else { int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f)); int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f)); + int pressure = (s8)(p[4] & 0x7f); input_report_rel(priv->dev2, REL_X, x); input_report_rel(priv->dev2, REL_Y, -y); + input_report_abs(priv->dev2, ABS_PRESSURE, pressure); } break; @@ -2998,6 +3001,10 @@ int alps_init(struct psmouse *psmouse) input_set_capability(dev2, EV_REL, REL_X); input_set_capability(dev2, EV_REL, REL_Y); + if (priv->flags & ALPS_DUALPOINT_WITH_PRESSURE) { + input_set_capability(dev2, EV_ABS, ABS_PRESSURE); + input_set_abs_params(dev2, ABS_PRESSURE, 0, 127, 0, 0); + } input_set_capability(dev2, EV_KEY, BTN_LEFT); input_set_capability(dev2, EV_KEY, BTN_RIGHT); input_set_capability(dev2, EV_KEY, BTN_MIDDLE); -- GitLab From aeaa881f9b17823028b464893b89c42db797b717 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Tue, 4 Oct 2016 11:43:30 -0700 Subject: [PATCH 0261/1167] Input: ALPS - set DualPoint flag for 74 03 28 devices Here we introduce logic in alps_identify to set the ALPS_DUALPOINT flag for touchpad hardware responding to E7 report with 73 03 28, as is found in the Dell Latitude E7470. Tested-by: Michal Hocko Signed-off-by: Ben Gamari Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index bb0b7230cf3b1..6d7de9bfed9a7 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -2747,6 +2747,10 @@ static int alps_set_protocol(struct psmouse *psmouse, if (alps_set_defaults_ss4_v2(psmouse, priv)) return -EIO; + if (priv->fw_ver[1] == 0x1) + priv->flags |= ALPS_DUALPOINT | + ALPS_DUALPOINT_WITH_PRESSURE; + break; } @@ -2819,6 +2823,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x14 && ec[1] == 0x02) { protocol = &alps_v8_protocol_data; + } else if (e7[0] == 0x73 && e7[1] == 0x03 && + e7[2] == 0x28 && ec[1] == 0x01) { + protocol = &alps_v8_protocol_data; } else { psmouse_dbg(psmouse, "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); -- GitLab From 574a62c93a663501fd545be9a72e6901089955e4 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Tue, 4 Oct 2016 11:45:17 -0700 Subject: [PATCH 0262/1167] Input: ALPS - add V8 protocol documentation Tested-by: Michal Hocko Signed-off-by: Ben Gamari Signed-off-by: Dmitry Torokhov --- Documentation/input/alps.txt | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt index 1fec1135791d9..8d1341ccde649 100644 --- a/Documentation/input/alps.txt +++ b/Documentation/input/alps.txt @@ -319,3 +319,60 @@ For touchpad packet, the format is: otherwise byte 0 bit 4 must be set and byte 0/4/5 are in NEW fmt F: Number of fingers - 3, 0 means 3 fingers, 1 means 4 ... + + +ALPS Absolute Mode - Protocol Version 8 +--------------------------------------- + +Spoken by SS4 (73 03 14) and SS5 (73 03 28) hardware. + +The packet type is given by the APD field, bits 4-5 of byte 3. + +Touchpad packet (APD = 0x2): + + b7 b6 b5 b4 b3 b2 b1 b0 + byte 0: SWM SWR SWL 1 1 0 0 X7 + byte 1: 0 X6 X5 X4 X3 X2 X1 X0 + byte 2: 0 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + byte 3: 0 T&P 1 0 1 0 0 Y7 + byte 4: 0 Z6 Z5 Z4 Z3 Z2 Z1 Z0 + byte 5: 0 0 0 0 0 0 0 0 + +SWM, SWR, SWL: Middle, Right, and Left button states + +Touchpad 1 Finger packet (APD = 0x0): + + b7 b6 b5 b4 b3 b2 b1 b0 + byte 0: SWM SWR SWL 1 1 X2 X1 X0 + byte 1: X9 X8 X7 1 X6 X5 X4 X3 + byte 2: 0 X11 X10 LFB Y3 Y2 Y1 Y0 + byte 3: Y5 Y4 0 0 1 TAPF2 TAPF1 TAPF0 + byte 4: Zv7 Y11 Y10 1 Y9 Y8 Y7 Y6 + byte 5: Zv6 Zv5 Zv4 0 Zv3 Zv2 Zv1 Zv0 + +TAPF: ??? +LFB: ??? + +Touchpad 2 Finger packet (APD = 0x1): + + b7 b6 b5 b4 b3 b2 b1 b0 + byte 0: SWM SWR SWL 1 1 AX6 AX5 AX4 + byte 1: AX11 AX10 AX9 AX8 AX7 AZ1 AY4 AZ0 + byte 2: AY11 AY10 AY9 CONT AY8 AY7 AY6 AY5 + byte 3: 0 0 0 1 1 BX6 BX5 BX4 + byte 4: BX11 BX10 BX9 BX8 BX7 BZ1 BY4 BZ0 + byte 5: BY11 BY10 BY9 0 BY8 BY7 BY5 BY5 + +CONT: A 3-or-4 Finger packet is to follow + +Touchpad 3-or-4 Finger packet (APD = 0x3): + + b7 b6 b5 b4 b3 b2 b1 b0 + byte 0: SWM SWR SWL 1 1 AX6 AX5 AX4 + byte 1: AX11 AX10 AX9 AX8 AX7 AZ1 AY4 AZ0 + byte 2: AY11 AY10 AY9 OVF AY8 AY7 AY6 AY5 + byte 3: 0 0 1 1 1 BX6 BX5 BX4 + byte 4: BX11 BX10 BX9 BX8 BX7 BZ1 BY4 BZ0 + byte 5: BY11 BY10 BY9 0 BY8 BY7 BY5 BY5 + +OVF: 5th finger detected -- GitLab From bbc2ceeb3220e54c7574f0b5e3a252fd9a62cf8a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 4 Oct 2016 11:48:55 -0700 Subject: [PATCH 0263/1167] Input: synaptics-rmi4 - fix error handling in SPI transport driver Instantiating the rmi4 SPI transport driver without an interrupt assigned caused the driver to fail to load, but it does not clean up its transport device registration. Result may be a crash at a later time, for example when rebooting the system. Fixes: 8d99758dee31 ("Input: synaptics-rmi4 - add SPI transport driver") Signed-off-by: Guenter Roeck Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_spi.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c index 55bd1b34970c9..4ebef607e2141 100644 --- a/drivers/input/rmi4/rmi_spi.c +++ b/drivers/input/rmi4/rmi_spi.c @@ -396,6 +396,13 @@ static inline int rmi_spi_of_probe(struct spi_device *spi, } #endif +static void rmi_spi_unregister_transport(void *data) +{ + struct rmi_spi_xport *rmi_spi = data; + + rmi_unregister_transport_device(&rmi_spi->xport); +} + static int rmi_spi_probe(struct spi_device *spi) { struct rmi_spi_xport *rmi_spi; @@ -464,6 +471,11 @@ static int rmi_spi_probe(struct spi_device *spi) dev_err(&spi->dev, "failed to register transport.\n"); return retval; } + retval = devm_add_action_or_reset(&spi->dev, + rmi_spi_unregister_transport, + rmi_spi); + if (retval) + return retval; retval = rmi_spi_init_irq(spi); if (retval < 0) @@ -473,15 +485,6 @@ static int rmi_spi_probe(struct spi_device *spi) return 0; } -static int rmi_spi_remove(struct spi_device *spi) -{ - struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); - - rmi_unregister_transport_device(&rmi_spi->xport); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int rmi_spi_suspend(struct device *dev) { @@ -577,7 +580,6 @@ static struct spi_driver rmi_spi_driver = { }, .id_table = rmi_id, .probe = rmi_spi_probe, - .remove = rmi_spi_remove, }; module_spi_driver(rmi_spi_driver); -- GitLab From 261d7794c49b9a3bb5115c5ffc452e00f969bf43 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 4 Oct 2016 11:50:54 -0700 Subject: [PATCH 0264/1167] Input: synaptics-rmi4 - fix error handling in I2C transport driver Instantiating the rmi4 I2C transport driver without interrupts assigned (for example using manual i2c instantiation from the command line) caused the driver to fail to load, but it does not clean up its regulator or transport device registrations. Result is a crash at a later time, for example when rebooting the system. Fixes: 946c8432aab0 ("Input: synaptics-rmi4 - support regulator supplies") Cc: Bjorn Andersson Signed-off-by: Guenter Roeck Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_i2c.c | 38 ++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index 6f2e0e4f02969..1ebc2c1debae3 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c @@ -221,6 +221,21 @@ static const struct of_device_id rmi_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, rmi_i2c_of_match); #endif +static void rmi_i2c_regulator_bulk_disable(void *data) +{ + struct rmi_i2c_xport *rmi_i2c = data; + + regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies), + rmi_i2c->supplies); +} + +static void rmi_i2c_unregister_transport(void *data) +{ + struct rmi_i2c_xport *rmi_i2c = data; + + rmi_unregister_transport_device(&rmi_i2c->xport); +} + static int rmi_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -264,6 +279,12 @@ static int rmi_i2c_probe(struct i2c_client *client, if (retval < 0) return retval; + retval = devm_add_action_or_reset(&client->dev, + rmi_i2c_regulator_bulk_disable, + rmi_i2c); + if (retval) + return retval; + of_property_read_u32(client->dev.of_node, "syna,startup-delay-ms", &rmi_i2c->startup_delay); @@ -294,6 +315,11 @@ static int rmi_i2c_probe(struct i2c_client *client, client->addr); return retval; } + retval = devm_add_action_or_reset(&client->dev, + rmi_i2c_unregister_transport, + rmi_i2c); + if (retval) + return retval; retval = rmi_i2c_init_irq(client); if (retval < 0) @@ -304,17 +330,6 @@ static int rmi_i2c_probe(struct i2c_client *client, return 0; } -static int rmi_i2c_remove(struct i2c_client *client) -{ - struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); - - rmi_unregister_transport_device(&rmi_i2c->xport); - regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies), - rmi_i2c->supplies); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int rmi_i2c_suspend(struct device *dev) { @@ -431,7 +446,6 @@ static struct i2c_driver rmi_i2c_driver = { }, .id_table = rmi_id, .probe = rmi_i2c_probe, - .remove = rmi_i2c_remove, }; module_i2c_driver(rmi_i2c_driver); -- GitLab From ea908ba8f73446dfbf87ff71f7cadb1994d2c5bb Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 4 Oct 2016 22:19:57 +0100 Subject: [PATCH 0265/1167] drm/armada: fix clock counts The DPMS handling wrt clock enables/disables was incorrect: we could end up decrementing the clock count multiple times if we transition via several low-power DPMS states, resulting in a kernel warning. Fix this by only testing to see whether we are entering or exiting the DPMS off state. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 2f58e9e2a59cb..a51f8cbcfe26d 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -332,17 +332,19 @@ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - if (dcrtc->dpms != dpms) { - dcrtc->dpms = dpms; - if (!IS_ERR(dcrtc->clk) && !dpms_blanked(dpms)) - WARN_ON(clk_prepare_enable(dcrtc->clk)); - armada_drm_crtc_update(dcrtc); - if (!IS_ERR(dcrtc->clk) && dpms_blanked(dpms)) - clk_disable_unprepare(dcrtc->clk); + if (dpms_blanked(dcrtc->dpms) != dpms_blanked(dpms)) { if (dpms_blanked(dpms)) armada_drm_vblank_off(dcrtc); - else + else if (!IS_ERR(dcrtc->clk)) + WARN_ON(clk_prepare_enable(dcrtc->clk)); + dcrtc->dpms = dpms; + armada_drm_crtc_update(dcrtc); + if (!dpms_blanked(dpms)) drm_crtc_vblank_on(&dcrtc->crtc); + else if (!IS_ERR(dcrtc->clk)) + clk_disable_unprepare(dcrtc->clk); + } else if (dcrtc->dpms != dpms) { + dcrtc->dpms = dpms; } } -- GitLab From 24d1a6e63e8f4045551f4dce3d75724f765c5069 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 1 Sep 2016 17:30:14 +0100 Subject: [PATCH 0266/1167] MIPS: KVM: Use __local_flush_icache_user_range() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert KVM dynamic translation of guest instructions to flush icache for guest mapped addresses using the new __local_flush_icache_user_range() API to allow the more generic flush_icache_range() to be changed to work on kernel addresses only. Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Paolo Bonzini Cc: "Radim Krčmář" Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14155/ Signed-off-by: Ralf Baechle --- arch/mips/kvm/dyntrans.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/kvm/dyntrans.c b/arch/mips/kvm/dyntrans.c index d280894915ed0..5317ed2d8909d 100644 --- a/arch/mips/kvm/dyntrans.c +++ b/arch/mips/kvm/dyntrans.c @@ -45,8 +45,8 @@ static int kvm_mips_trans_replace(struct kvm_vcpu *vcpu, u32 *opc, } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) { local_irq_save(flags); memcpy((void *)opc, (void *)&replace, sizeof(u32)); - local_flush_icache_range((unsigned long)opc, - (unsigned long)opc + 32); + __local_flush_icache_user_range((unsigned long)opc, + (unsigned long)opc + 32); local_irq_restore(flags); } else { kvm_err("%s: Invalid address: %p\n", __func__, opc); -- GitLab From b2ff71718e6025fed33a693a1772e2ed39f25d6c Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 1 Sep 2016 17:30:15 +0100 Subject: [PATCH 0267/1167] MIPS: c-r4k: Fix flush_icache_range() for EVA flush_icache_range() flushes icache lines in a protected fashion for kernel addresses, however this isn't correct with EVA where protected cache ops only operate on user addresses, making flush_icache_range() ineffective. Split the implementations of __flush_icache_user_range() from flush_icache_range(), changing the normal flush_icache_range() to use unprotected normal cache ops. Signed-off-by: James Hogan Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14156/ Signed-off-by: Ralf Baechle --- arch/mips/mm/c-r4k.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 5e0a44a0c5572..c643b1eaead78 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -722,11 +722,13 @@ struct flush_icache_range_args { unsigned long start; unsigned long end; unsigned int type; + bool user; }; static inline void __local_r4k_flush_icache_range(unsigned long start, unsigned long end, - unsigned int type) + unsigned int type, + bool user) { if (!cpu_has_ic_fills_f_dc) { if (type == R4K_INDEX || @@ -734,7 +736,10 @@ static inline void __local_r4k_flush_icache_range(unsigned long start, r4k_blast_dcache(); } else { R4600_HIT_CACHEOP_WAR_IMPL; - protected_blast_dcache_range(start, end); + if (user) + protected_blast_dcache_range(start, end); + else + blast_dcache_range(start, end); } } @@ -748,7 +753,10 @@ static inline void __local_r4k_flush_icache_range(unsigned long start, break; default: - protected_blast_icache_range(start, end); + if (user) + protected_blast_icache_range(start, end); + else + blast_icache_range(start, end); break; } } @@ -757,7 +765,13 @@ static inline void __local_r4k_flush_icache_range(unsigned long start, static inline void local_r4k_flush_icache_range(unsigned long start, unsigned long end) { - __local_r4k_flush_icache_range(start, end, R4K_HIT | R4K_INDEX); + __local_r4k_flush_icache_range(start, end, R4K_HIT | R4K_INDEX, false); +} + +static inline void local_r4k_flush_icache_user_range(unsigned long start, + unsigned long end) +{ + __local_r4k_flush_icache_range(start, end, R4K_HIT | R4K_INDEX, true); } static inline void local_r4k_flush_icache_range_ipi(void *args) @@ -766,11 +780,13 @@ static inline void local_r4k_flush_icache_range_ipi(void *args) unsigned long start = fir_args->start; unsigned long end = fir_args->end; unsigned int type = fir_args->type; + bool user = fir_args->user; - __local_r4k_flush_icache_range(start, end, type); + __local_r4k_flush_icache_range(start, end, type, user); } -static void r4k_flush_icache_range(unsigned long start, unsigned long end) +static void __r4k_flush_icache_range(unsigned long start, unsigned long end, + bool user) { struct flush_icache_range_args args; unsigned long size, cache_size; @@ -778,6 +794,7 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end) args.start = start; args.end = end; args.type = R4K_HIT | R4K_INDEX; + args.user = user; /* * Indexed cache ops require an SMP call. @@ -803,6 +820,16 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end) instruction_hazard(); } +static void r4k_flush_icache_range(unsigned long start, unsigned long end) +{ + return __r4k_flush_icache_range(start, end, false); +} + +static void r4k_flush_icache_user_range(unsigned long start, unsigned long end) +{ + return __r4k_flush_icache_range(start, end, true); +} + #if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT) static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) @@ -1904,8 +1931,8 @@ void r4k_cache_init(void) flush_data_cache_page = r4k_flush_data_cache_page; flush_icache_range = r4k_flush_icache_range; local_flush_icache_range = local_r4k_flush_icache_range; - __flush_icache_user_range = r4k_flush_icache_range; - __local_flush_icache_user_range = local_r4k_flush_icache_range; + __flush_icache_user_range = r4k_flush_icache_user_range; + __local_flush_icache_user_range = local_r4k_flush_icache_user_range; #if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT) if (coherentio) { -- GitLab From e710d6668309d227cc7a46e9c222d97d4a502b9e Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Tue, 20 Sep 2016 09:47:25 +0100 Subject: [PATCH 0268/1167] MIPS: tlb-r4k: If there are wired entries, don't use TLBINVF When adding a wired entry to the TLB via add_wired_entry, the tlb is flushed with local_flush_tlb_all, which on CPUs with TLBINV results in the new wired entry being flushed again. Behavior of the TLBINV instruction applies to all applicable TLB entries and is unaffected by the setting of the Wired register. Therefore if the TLB has any wired entries, fall back to iterating over the entries rather than blasting them all using TLBINVF. Signed-off-by: Matt Redfearn Cc: Bjorn Andersson Cc: Ohad Ben-Cohen Cc: Thomas Gleixner Cc: lisa.parratt@imgtec.com Cc: Hugh Dickins Cc: Huacai Chen Cc: David S. Miller Cc: James Hogan Cc: Paul Burton Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: linux-remoteproc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14283/ Signed-off-by: Ralf Baechle --- arch/mips/mm/tlb-r4k.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index e8b335c162958..4953c1a8cdfdb 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -67,8 +67,11 @@ void local_flush_tlb_all(void) entry = read_c0_wired(); - /* Blast 'em all away. */ - if (cpu_has_tlbinv) { + /* + * Blast 'em all away. + * If there are any wired entries, fall back to iterating + */ + if (cpu_has_tlbinv && !entry) { if (current_cpu_data.tlbsizevtlb) { write_c0_index(0); mtc0_tlbw_hazard(); -- GitLab From 7688c5391038e60377275f078e6d7043dc115efc Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Tue, 20 Sep 2016 09:47:26 +0100 Subject: [PATCH 0269/1167] MIPS: smp.c: Introduce mechanism for freeing and allocating IPIs For the MIPS remote processor implementation, we need additional IPIs to talk to the remote processor. Since MIPS GIC reserves exactly the right number of IPI IRQs required by Linux for the number of VPs in the system, this is not possible without releasing some recources. This commit introduces mips_smp_ipi_allocate() which allocates IPIs to a given cpumask. It is called as normal with the cpu_possible_mask at bootup to initialise IPIs to all CPUs. mips_smp_ipi_free() may then be used to free IPIs to a subset of those CPUs so that their hardware resources can be reused. Signed-off-by: Matt Redfearn Cc: Bjorn Andersson Cc: Ohad Ben-Cohen Cc: Thomas Gleixner Cc: Lisa Parratt Cc: James Hogan Cc: Qais Yousef Cc: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-remoteproc@vger.kernel.org Cc: lisa.parratt@imgtec.com Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14285/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/smp.h | 14 +++++++++ arch/mips/kernel/smp.c | 61 ++++++++++++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index 8bc6c70a40302..060f23ff18171 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -85,6 +85,20 @@ static inline void __cpu_die(unsigned int cpu) extern void play_dead(void); #endif +/* + * This function will set up the necessary IPIs for Linux to communicate + * with the CPUs in mask. + * Return 0 on success. + */ +int mips_smp_ipi_allocate(const struct cpumask *mask); + +/* + * This function will free up IPIs allocated with mips_smp_ipi_allocate to the + * CPUs in mask, which must be a subset of the IPIs that have been configured. + * Return 0 on success. + */ +int mips_smp_ipi_free(const struct cpumask *mask); + static inline void arch_send_call_function_single_ipi(int cpu) { extern struct plat_smp_ops *mp_ops; /* private */ diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index cb02df215365d..0e131c9c39f6a 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -231,7 +231,7 @@ static struct irqaction irq_call = { .name = "IPI call" }; -static __init void smp_ipi_init_one(unsigned int virq, +static void smp_ipi_init_one(unsigned int virq, struct irqaction *action) { int ret; @@ -241,9 +241,11 @@ static __init void smp_ipi_init_one(unsigned int virq, BUG_ON(ret); } -static int __init mips_smp_ipi_init(void) +static unsigned int call_virq, sched_virq; + +int mips_smp_ipi_allocate(const struct cpumask *mask) { - unsigned int call_virq, sched_virq; + int virq; struct irq_domain *ipidomain; struct device_node *node; @@ -270,16 +272,20 @@ static int __init mips_smp_ipi_init(void) if (!ipidomain) return 0; - call_virq = irq_reserve_ipi(ipidomain, cpu_possible_mask); - BUG_ON(!call_virq); + virq = irq_reserve_ipi(ipidomain, mask); + BUG_ON(!virq); + if (!call_virq) + call_virq = virq; - sched_virq = irq_reserve_ipi(ipidomain, cpu_possible_mask); - BUG_ON(!sched_virq); + virq = irq_reserve_ipi(ipidomain, mask); + BUG_ON(!virq); + if (!sched_virq) + sched_virq = virq; if (irq_domain_is_ipi_per_cpu(ipidomain)) { int cpu; - for_each_cpu(cpu, cpu_possible_mask) { + for_each_cpu(cpu, mask) { smp_ipi_init_one(call_virq + cpu, &irq_call); smp_ipi_init_one(sched_virq + cpu, &irq_resched); } @@ -288,6 +294,45 @@ static int __init mips_smp_ipi_init(void) smp_ipi_init_one(sched_virq, &irq_resched); } + return 0; +} + +int mips_smp_ipi_free(const struct cpumask *mask) +{ + struct irq_domain *ipidomain; + struct device_node *node; + + node = of_irq_find_parent(of_root); + ipidomain = irq_find_matching_host(node, DOMAIN_BUS_IPI); + + /* + * Some platforms have half DT setup. So if we found irq node but + * didn't find an ipidomain, try to search for one that is not in the + * DT. + */ + if (node && !ipidomain) + ipidomain = irq_find_matching_host(NULL, DOMAIN_BUS_IPI); + + BUG_ON(!ipidomain); + + if (irq_domain_is_ipi_per_cpu(ipidomain)) { + int cpu; + + for_each_cpu(cpu, mask) { + remove_irq(call_virq + cpu, &irq_call); + remove_irq(sched_virq + cpu, &irq_resched); + } + } + irq_destroy_ipi(call_virq, mask); + irq_destroy_ipi(sched_virq, mask); + return 0; +} + + +static int __init mips_smp_ipi_init(void) +{ + mips_smp_ipi_allocate(cpu_possible_mask); + call_desc = irq_to_desc(call_virq); sched_desc = irq_to_desc(sched_virq); -- GitLab From 74abd4e9b100d68a9114c845c6c5b70aa8e4e52e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 26 Sep 2016 11:34:24 +0200 Subject: [PATCH 0270/1167] mailmap: Canonicalize to Qais' current email address. Signed-off-by: Ralf Baechle --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 1dab0a156489e..d410bcdd94aab 100644 --- a/.mailmap +++ b/.mailmap @@ -125,6 +125,7 @@ Peter Oruba Peter Oruba Pratyush Anand Praveen BP +Qais Yousef Rajesh Shah Ralf Baechle Ralf Wildenhues -- GitLab From d9d5417755eda87db8e370e4dd2175fbd8814acc Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 21 Aug 2016 15:58:13 -0400 Subject: [PATCH 0271/1167] MIPS: kernel: Audit and remove any unnecessary uses of module.h Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. The advantage in doing so is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h was the source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each obj-y/bool instance for the presence of either and replace as needed. In the case of the n32/o32 files, we have to get rid of a couple no-op MODULE_ tags to facilitate the module.h removal. They piggy back off the fs/ elf binary support, which is also a bool Kconfig. Signed-off-by: Paul Gortmaker Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14032/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/binfmt_elfn32.c | 8 +------- arch/mips/kernel/binfmt_elfo32.c | 8 +------- arch/mips/kernel/branch.c | 2 +- arch/mips/kernel/linux32.c | 1 - arch/mips/kernel/mips-r2-to-r6-emul.c | 1 - arch/mips/kernel/smp.c | 2 +- 6 files changed, 4 insertions(+), 18 deletions(-) diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c index 58ad63d7eb424..9c7f3e136d50d 100644 --- a/arch/mips/kernel/binfmt_elfn32.c +++ b/arch/mips/kernel/binfmt_elfn32.c @@ -1,5 +1,6 @@ /* * Support for n32 Linux/MIPS ELF binaries. + * Author: Ralf Baechle (ralf@linux-mips.org) * * Copyright (C) 1999, 2001 Ralf Baechle * Copyright (C) 1999, 2001 Silicon Graphics, Inc. @@ -37,7 +38,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2) #include -#include #include #include #include @@ -96,12 +96,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) #define ELF_CORE_EFLAGS EF_MIPS_ABI2 -MODULE_DESCRIPTION("Binary format loader for compatibility with n32 Linux/MIPS binaries"); -MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)"); - -#undef MODULE_DESCRIPTION -#undef MODULE_AUTHOR - #undef TASK_SIZE #define TASK_SIZE TASK_SIZE32 diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index 49fb881481f7b..1ab34322dd977 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -1,5 +1,6 @@ /* * Support for o32 Linux/MIPS ELF binaries. + * Author: Ralf Baechle (ralf@linux-mips.org) * * Copyright (C) 1999, 2001 Ralf Baechle * Copyright (C) 1999, 2001 Silicon Graphics, Inc. @@ -42,7 +43,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #include -#include #include #include #include @@ -99,12 +99,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) value->tv_usec = rem / NSEC_PER_USEC; } -MODULE_DESCRIPTION("Binary format loader for compatibility with o32 Linux/MIPS binaries"); -MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)"); - -#undef MODULE_DESCRIPTION -#undef MODULE_AUTHOR - #undef TASK_SIZE #define TASK_SIZE TASK_SIZE32 diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 46c227fc98f5a..f5c68483c98ea 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 0b29646bcee77..50fb62544df71 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index 0a7e10b5f9e39..22dedd62818ad 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 0e131c9c39f6a..7ebb1918e2ac8 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include -- GitLab From d9ba57780637bfde6ac1efb65a8685231ffbc715 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 21 Aug 2016 15:58:14 -0400 Subject: [PATCH 0272/1167] MIPS: mm: Audit and remove any unnecessary uses of module.h Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. The advantage in doing so is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h was the source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each obj-y/bool instance for the presence of either and replace as needed. Signed-off-by: Paul Gortmaker Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14033/ Signed-off-by: Ralf Baechle --- arch/mips/mm/c-r4k.c | 2 +- arch/mips/mm/cache.c | 2 +- arch/mips/mm/dma-default.c | 2 +- arch/mips/mm/fault.c | 1 - arch/mips/mm/highmem.c | 3 ++- arch/mips/mm/init.c | 2 +- arch/mips/mm/ioremap.c | 2 +- arch/mips/mm/mmap.c | 2 +- arch/mips/mm/page.c | 1 - arch/mips/mm/tlb-r4k.c | 2 +- 10 files changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index c643b1eaead78..1fc11184e999e 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 7ec0847c725a3..6db3413472023 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index b2eadd6fa9a1e..755259c54976b 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 9560ad7311209..d56a855828c2b 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index d7258a103439d..f13f51003bd83 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -1,5 +1,6 @@ #include -#include +#include +#include #include #include #include diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 72f7478ee0684..3a6edecc3f385 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -10,7 +10,7 @@ */ #include #include -#include +#include #include #include #include diff --git a/arch/mips/mm/ioremap.c b/arch/mips/mm/ioremap.c index 8d5008cbdc0f0..1f189627440f2 100644 --- a/arch/mips/mm/ioremap.c +++ b/arch/mips/mm/ioremap.c @@ -6,7 +6,7 @@ * (C) Copyright 1995 1996 Linus Torvalds * (C) Copyright 2001, 2002 Ralf Baechle */ -#include +#include #include #include #include diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c index 353037699512c..d08ea3ff0f533 100644 --- a/arch/mips/mm/mmap.c +++ b/arch/mips/mm/mmap.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c index c41953ca6605c..6f804f5960abe 100644 --- a/arch/mips/mm/page.c +++ b/arch/mips/mm/page.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 4953c1a8cdfdb..bba9c1484b41e 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include -- GitLab From 527581b9cf6ec560502eea91a82f511a2db77cde Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 21 Aug 2016 15:58:15 -0400 Subject: [PATCH 0273/1167] MIPS: lib: Audit and remove any unnecessary uses of module.h Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. The advantage in doing so is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h was the source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each obj-y/bool instance for the presence of either and replace as needed. The compiler.h additions are for an implict presence of the "notrace" which module.h brought in but export.h does not. Signed-off-by: Paul Gortmaker Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14034/ Signed-off-by: Ralf Baechle --- arch/mips/lib/ashldi3.c | 2 +- arch/mips/lib/ashrdi3.c | 2 +- arch/mips/lib/bswapdi.c | 3 ++- arch/mips/lib/bswapsi.c | 3 ++- arch/mips/lib/cmpdi2.c | 2 +- arch/mips/lib/delay.c | 2 +- arch/mips/lib/iomap-pci.c | 2 +- arch/mips/lib/iomap.c | 2 +- arch/mips/lib/lshrdi3.c | 2 +- arch/mips/lib/ucmpdi2.c | 2 +- 10 files changed, 12 insertions(+), 10 deletions(-) diff --git a/arch/mips/lib/ashldi3.c b/arch/mips/lib/ashldi3.c index 927dc94a030f3..c3e22053d13eb 100644 --- a/arch/mips/lib/ashldi3.c +++ b/arch/mips/lib/ashldi3.c @@ -1,4 +1,4 @@ -#include +#include #include "libgcc.h" diff --git a/arch/mips/lib/ashrdi3.c b/arch/mips/lib/ashrdi3.c index 9fdf1a598428a..17456024873d2 100644 --- a/arch/mips/lib/ashrdi3.c +++ b/arch/mips/lib/ashrdi3.c @@ -1,4 +1,4 @@ -#include +#include #include "libgcc.h" diff --git a/arch/mips/lib/bswapdi.c b/arch/mips/lib/bswapdi.c index e3e77aa52c957..a8114148f82a4 100644 --- a/arch/mips/lib/bswapdi.c +++ b/arch/mips/lib/bswapdi.c @@ -1,4 +1,5 @@ -#include +#include +#include unsigned long long notrace __bswapdi2(unsigned long long u) { diff --git a/arch/mips/lib/bswapsi.c b/arch/mips/lib/bswapsi.c index 530a8afe6fda2..106fd978317d3 100644 --- a/arch/mips/lib/bswapsi.c +++ b/arch/mips/lib/bswapsi.c @@ -1,4 +1,5 @@ -#include +#include +#include unsigned int notrace __bswapsi2(unsigned int u) { diff --git a/arch/mips/lib/cmpdi2.c b/arch/mips/lib/cmpdi2.c index 06857da96993c..9d849d8743c95 100644 --- a/arch/mips/lib/cmpdi2.c +++ b/arch/mips/lib/cmpdi2.c @@ -1,4 +1,4 @@ -#include +#include #include "libgcc.h" diff --git a/arch/mips/lib/delay.c b/arch/mips/lib/delay.c index 21d27c6819a2f..2307a3cb2714f 100644 --- a/arch/mips/lib/delay.c +++ b/arch/mips/lib/delay.c @@ -8,7 +8,7 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. * Copyright (C) 2007, 2014 Maciej W. Rozycki */ -#include +#include #include #include #include diff --git a/arch/mips/lib/iomap-pci.c b/arch/mips/lib/iomap-pci.c index fd35daa45314a..a629077fd7b9a 100644 --- a/arch/mips/lib/iomap-pci.c +++ b/arch/mips/lib/iomap-pci.c @@ -7,7 +7,7 @@ * written by Ralf Baechle */ #include -#include +#include #include void __iomem *__pci_ioport_map(struct pci_dev *dev, diff --git a/arch/mips/lib/iomap.c b/arch/mips/lib/iomap.c index 8e7e378ce51c3..9daa92428e23b 100644 --- a/arch/mips/lib/iomap.c +++ b/arch/mips/lib/iomap.c @@ -6,7 +6,7 @@ * (C) Copyright 2007 MIPS Technologies, Inc. * written by Ralf Baechle */ -#include +#include #include /* diff --git a/arch/mips/lib/lshrdi3.c b/arch/mips/lib/lshrdi3.c index 364547449c653..221167c1be551 100644 --- a/arch/mips/lib/lshrdi3.c +++ b/arch/mips/lib/lshrdi3.c @@ -1,4 +1,4 @@ -#include +#include #include "libgcc.h" diff --git a/arch/mips/lib/ucmpdi2.c b/arch/mips/lib/ucmpdi2.c index bd599f58234c9..08067fa538f2d 100644 --- a/arch/mips/lib/ucmpdi2.c +++ b/arch/mips/lib/ucmpdi2.c @@ -1,4 +1,4 @@ -#include +#include #include "libgcc.h" -- GitLab From 2722090af4f8988ecce1b22c667fa03ee0f473ca Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 21 Aug 2016 15:58:16 -0400 Subject: [PATCH 0274/1167] MIPS: pci: Audit and remove any unnecessary uses of module.h Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. The advantage in doing so is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h was the source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each obj-y/bool instance for the presence of either and replace as needed. We also needed to remove the no-op MODULE_DEVICE_TABLE usage in several instances to permit removal of the module.h include. The files in these instances were all controlled by bool Kconfig. In one instance, module_param was being used so we transition the module.h include onto a moduleparam.h include. Signed-off-by: Paul Gortmaker Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14035/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-ar71xx.c | 2 +- arch/mips/pci/pci-ar724x.c | 2 +- arch/mips/pci/pci-lantiq.c | 2 -- arch/mips/pci/pci-mt7620.c | 2 -- arch/mips/pci/pci-rt2880.c | 2 -- arch/mips/pci/pci-rt3883.c | 2 -- arch/mips/pci/pcie-octeon.c | 2 +- 7 files changed, 3 insertions(+), 11 deletions(-) diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index 7db963deec737..bdf87b43633fe 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 2013dad700dfa..1e23c8d587bde 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index b9deab17ccf24..f18f887f481d8 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -234,7 +233,6 @@ static const struct of_device_id ltq_pci_match[] = { { .compatible = "lantiq,pci-xway" }, {}, }; -MODULE_DEVICE_TABLE(of, ltq_pci_match); static struct platform_driver ltq_pci_driver = { .probe = ltq_pci_probe, diff --git a/arch/mips/pci/pci-mt7620.c b/arch/mips/pci/pci-mt7620.c index eb39826a62c3b..628c5132b3d8b 100644 --- a/arch/mips/pci/pci-mt7620.c +++ b/arch/mips/pci/pci-mt7620.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -407,7 +406,6 @@ static const struct of_device_id mt7620_pci_ids[] = { { .compatible = "mediatek,mt7620-pci" }, {}, }; -MODULE_DEVICE_TABLE(of, mt7620_pci_ids); static struct platform_driver mt7620_pci_driver = { .probe = mt7620_pci_probe, diff --git a/arch/mips/pci/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c index f2a1050168d95..d6360fe73d058 100644 --- a/arch/mips/pci/pci-rt2880.c +++ b/arch/mips/pci/pci-rt2880.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -260,7 +259,6 @@ static const struct of_device_id rt288x_pci_match[] = { { .compatible = "ralink,rt288x-pci" }, {}, }; -MODULE_DEVICE_TABLE(of, rt288x_pci_match); static struct platform_driver rt288x_pci_driver = { .probe = rt288x_pci_probe, diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index 53a42b07008b9..3520e9b414e7b 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -580,7 +579,6 @@ static const struct of_device_id rt3883_pci_ids[] = { { .compatible = "ralink,rt3883-pci" }, {}, }; -MODULE_DEVICE_TABLE(of, rt3883_pci_ids); static struct platform_driver rt3883_pci_driver = { .probe = rt3883_pci_probe, diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c index 99f3db4f0a9b1..9f672ceb089b9 100644 --- a/arch/mips/pci/pcie-octeon.c +++ b/arch/mips/pci/pcie-octeon.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include -- GitLab From cd14c92bbd095fdc2d0b78f7dac920769ff06a9f Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 21 Aug 2016 15:58:17 -0400 Subject: [PATCH 0275/1167] MIPS: kvm: Audit and remove any unnecessary uses of module.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. In the case of kvm where it is modular, we can extend that to also include files that are building basic support functionality but not related to loading or registering the final module; such files also have no need whatsoever for module.h The advantage in removing such instances is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h was the source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each instance for the presence of either and replace as needed. In this case, we did not need to add either to any files. Signed-off-by: Paul Gortmaker Acked-by: James Hogan Acked-by: Paolo Bonzini Cc: "Radim Krčmář" Cc: kvm@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14036/ Signed-off-by: Ralf Baechle --- arch/mips/kvm/commpage.c | 1 - arch/mips/kvm/dyntrans.c | 1 - arch/mips/kvm/emulate.c | 1 - arch/mips/kvm/interrupt.c | 1 - arch/mips/kvm/trap_emul.c | 1 - 5 files changed, 5 deletions(-) diff --git a/arch/mips/kvm/commpage.c b/arch/mips/kvm/commpage.c index a36b77e1705c5..f43629979a0e5 100644 --- a/arch/mips/kvm/commpage.c +++ b/arch/mips/kvm/commpage.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/kvm/dyntrans.c b/arch/mips/kvm/dyntrans.c index 5317ed2d8909d..010cef2406880 100644 --- a/arch/mips/kvm/dyntrans.c +++ b/arch/mips/kvm/dyntrans.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index e788515f766b4..68fd666f8cb9d 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/kvm/interrupt.c b/arch/mips/kvm/interrupt.c index ad28dac6b7e95..e88403b3dcdd5 100644 --- a/arch/mips/kvm/interrupt.c +++ b/arch/mips/kvm/interrupt.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c index 091553942bcbc..21d80274ccff8 100644 --- a/arch/mips/kvm/trap_emul.c +++ b/arch/mips/kvm/trap_emul.c @@ -11,7 +11,6 @@ #include #include -#include #include #include -- GitLab From ba7505022c8b7c7366b905262631b293ac60c863 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 14 Sep 2016 11:00:27 +0100 Subject: [PATCH 0276/1167] MIPS: pm-cps: Generate idle state entry code when CPUs are onlined The MIPS Coherent Processing System (CPS) power management code has previously generated code used to enter low power idle states once during boot for all CPUs. This has the drawback that if a CPU is present in the system but not being used (for example due to the maxcpus kernel parameter) then we encounter problems due to not having probed that CPU for information about its type & properties. The result of this is that we generate entry code which is both unused, potentially entirely invalid & likely to be unsuitable for the CPU in question anyway. Avoid this by generating idle state entry code only when a CPU is brought online. This way we only ever generate code for CPUs that we know we've probed the properties of, and that will actually be used. [ralf@linux-mips.org: Resolve merge conflict.] Signed-off-by: Paul Burton Cc: Adam Buchbinder Cc: Masahiro Yamada Cc: Markos Chandras Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14259/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/pm-cps.c | 45 +++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 05bcdedcf9bdb..7cf653e214237 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -8,6 +8,7 @@ * option) any later version. */ +#include #include #include #include @@ -70,8 +71,8 @@ static DEFINE_PER_CPU_ALIGNED(atomic_t, pm_barrier); DEFINE_PER_CPU_ALIGNED(struct mips_static_suspend_state, cps_cpu_state); /* A somewhat arbitrary number of labels & relocs for uasm */ -static struct uasm_label labels[32] __initdata; -static struct uasm_reloc relocs[32] __initdata; +static struct uasm_label labels[32]; +static struct uasm_reloc relocs[32]; enum mips_reg { zero, at, v0, v1, a0, a1, a2, a3, @@ -193,10 +194,10 @@ int cps_pm_enter_state(enum cps_pm_state state) return 0; } -static void __init cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, - struct uasm_reloc **pr, - const struct cache_desc *cache, - unsigned op, int lbl) +static void cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, + struct uasm_reloc **pr, + const struct cache_desc *cache, + unsigned op, int lbl) { unsigned cache_size = cache->ways << cache->waybit; unsigned i; @@ -237,10 +238,10 @@ static void __init cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, uasm_i_nop(pp); } -static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, - struct uasm_reloc **pr, - const struct cpuinfo_mips *cpu_info, - int lbl) +static int cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, + struct uasm_reloc **pr, + const struct cpuinfo_mips *cpu_info, + int lbl) { unsigned i, fsb_size = 8; unsigned num_loads = (fsb_size * 3) / 2; @@ -330,9 +331,9 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, return 0; } -static void __init cps_gen_set_top_bit(u32 **pp, struct uasm_label **pl, - struct uasm_reloc **pr, - unsigned r_addr, int lbl) +static void cps_gen_set_top_bit(u32 **pp, struct uasm_label **pl, + struct uasm_reloc **pr, + unsigned r_addr, int lbl) { uasm_i_lui(pp, t0, uasm_rel_hi(0x80000000)); uasm_build_label(pl, *pp, lbl); @@ -343,7 +344,7 @@ static void __init cps_gen_set_top_bit(u32 **pp, struct uasm_label **pl, uasm_i_nop(pp); } -static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) +static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) { struct uasm_label *l = labels; struct uasm_reloc *r = relocs; @@ -637,7 +638,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) return NULL; } -static int __init cps_gen_core_entries(unsigned cpu) +static int cps_pm_online_cpu(unsigned int cpu) { enum cps_pm_state state; unsigned core = cpu_data[cpu].core; @@ -679,13 +680,10 @@ static int __init cps_gen_core_entries(unsigned cpu) static int __init cps_pm_init(void) { - unsigned cpu; - int err; - /* A CM is required for all non-coherent states */ if (!mips_cm_present()) { pr_warn("pm-cps: no CM, non-coherent states unavailable\n"); - goto out; + return 0; } /* @@ -715,12 +713,7 @@ static int __init cps_pm_init(void) pr_warn("pm-cps: no CPC, clock & power gating unavailable\n"); } - for_each_present_cpu(cpu) { - err = cps_gen_core_entries(cpu); - if (err) - return err; - } -out: - return 0; + return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "AP_PM_CPS_CPU_ONLINE", + cps_pm_online_cpu, NULL); } arch_initcall(cps_pm_init); -- GitLab From 0a15273666aa18a45985e6419afa05ec24ecfeb4 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:33 +0100 Subject: [PATCH 0277/1167] MIPS: SEAD3: Split obj-y entries across lines Split the obj-y entries for SEAD3 onto a line each, so that they're more independent & can be modified more clearly by later commits. Signed-off-by: Paul Burton Cc: Jacek Anaszewski Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14046/ Signed-off-by: Ralf Baechle --- arch/mips/mti-sead3/Makefile | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile index 7a584e0bf9333..8b03cfb127599 100644 --- a/arch/mips/mti-sead3/Makefile +++ b/arch/mips/mti-sead3/Makefile @@ -8,8 +8,13 @@ # Copyright (C) 2012 MIPS Technoligies, Inc. All rights reserved. # Steven J. Hill # -obj-y := sead3-lcd.o sead3-display.o sead3-init.o \ - sead3-int.o sead3-platform.o sead3-reset.o \ - sead3-setup.o sead3-time.o +obj-y := sead3-lcd.o +obj-y += sead3-display.o +obj-y += sead3-init.o +obj-y += sead3-int.o +obj-y += sead3-platform.o +obj-y += sead3-reset.o +obj-y += sead3-setup.o +obj-y += sead3-time.o obj-$(CONFIG_EARLY_PRINTK) += sead3-console.o -- GitLab From b6d5e47e67292542a41c3fe367bacb364eb4e601 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:34 +0100 Subject: [PATCH 0278/1167] MIPS: SEAD3: Probe interrupt controllers using DT Probe the CPU interrupt controller & optional Global Interrupt Controller (GIC) using devicetree rather than platform code. Because the bootloader on SEAD3 does not provide a device tree to the kernel & the device tree is always built in, we patch out the GIC node during boot if we detect that a GIC is not present in the system. The appropriate IRQ domain is discovered by platform code setting up device IRQ numbers temporarily. It will be removed by further patches which move the devices towards being probed via device tree. No behavioural change is intended by this patch. Signed-off-by: Paul Burton Cc: Matt Redfearn Cc: Kefeng Wang Cc: Jacek Anaszewski Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14047/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 31 +++++++ .../include/asm/mach-sead3/sead3-dtshim.h | 29 ++++++ arch/mips/include/asm/mips-boards/sead3int.h | 5 - arch/mips/mti-sead3/Makefile | 1 + arch/mips/mti-sead3/sead3-dtshim.c | 92 +++++++++++++++++++ arch/mips/mti-sead3/sead3-int.c | 27 +----- arch/mips/mti-sead3/sead3-platform.c | 43 +++++++-- arch/mips/mti-sead3/sead3-setup.c | 13 +-- 8 files changed, 197 insertions(+), 44 deletions(-) create mode 100644 arch/mips/include/asm/mach-sead3/sead3-dtshim.h create mode 100644 arch/mips/mti-sead3/sead3-dtshim.c diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index e4b317d414f11..051b3a9e5a9e5 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -4,10 +4,13 @@ /memreserve/ 0x00001000 0x000ef000; // ROM data /memreserve/ 0x000f0000 0x004cc000; // reserved +#include + / { #address-cells = <1>; #size-cells = <1>; compatible = "mti,sead-3"; + interrupt-parent = <&gic>; cpus { cpu@0 { @@ -19,4 +22,32 @@ device_type = "memory"; reg = <0x0 0x08000000>; }; + + cpu_intc: interrupt-controller { + compatible = "mti,cpu-interrupt-controller"; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + gic: interrupt-controller@1b1c0000 { + compatible = "mti,gic"; + reg = <0x1b1c0000 0x20000>; + + interrupt-controller; + #interrupt-cells = <3>; + + /* + * Declare the interrupt-parent even though the mti,gic + * binding doesn't require it, such that the kernel can + * figure out that cpu_intc is the root interrupt + * controller & should be probed first. + */ + interrupt-parent = <&cpu_intc>; + + timer { + compatible = "mti,gic-timer"; + interrupts = ; + }; + }; }; diff --git a/arch/mips/include/asm/mach-sead3/sead3-dtshim.h b/arch/mips/include/asm/mach-sead3/sead3-dtshim.h new file mode 100644 index 0000000000000..f5d7d9c9dd177 --- /dev/null +++ b/arch/mips/include/asm/mach-sead3/sead3-dtshim.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __MIPS_SEAD3_DTSHIM_H__ +#define __MIPS_SEAD3_DTSHIM_H__ + +#include + +#ifdef CONFIG_MIPS_SEAD3 + +extern void __init *sead3_dt_shim(void *fdt); + +#else /* !CONFIG_MIPS_SEAD3 */ + +static inline void *sead3_dt_shim(void *fdt) +{ + return fdt; +} + +#endif /* !CONFIG_MIPS_SEAD3 */ + +#endif /* __MIPS_SEAD3_DTSHIM_H__ */ diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h index 8932c7de04198..bd85da3d6770a 100644 --- a/arch/mips/include/asm/mips-boards/sead3int.h +++ b/arch/mips/include/asm/mips-boards/sead3int.h @@ -12,12 +12,7 @@ #include -/* SEAD-3 GIC address space definitions. */ -#define GIC_BASE_ADDR 0x1b1c0000 -#define GIC_ADDRSPACE_SZ (128 * 1024) - /* CPU interrupt offsets */ -#define CPU_INT_GIC 2 #define CPU_INT_EHCI 2 #define CPU_INT_UART0 4 #define CPU_INT_UART1 4 diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile index 8b03cfb127599..aad67aac3dbae 100644 --- a/arch/mips/mti-sead3/Makefile +++ b/arch/mips/mti-sead3/Makefile @@ -10,6 +10,7 @@ # obj-y := sead3-lcd.o obj-y += sead3-display.o +obj-y += sead3-dtshim.o obj-y += sead3-init.o obj-y += sead3-int.o obj-y += sead3-platform.o diff --git a/arch/mips/mti-sead3/sead3-dtshim.c b/arch/mips/mti-sead3/sead3-dtshim.c new file mode 100644 index 0000000000000..3283a7e19a889 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-dtshim.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#define pr_fmt(fmt) "sead3-dtshim: " fmt + +#include +#include +#include + +#include + +#define SEAD_CONFIG CKSEG1ADDR(0x1b100110) +#define SEAD_CONFIG_GIC_PRESENT BIT(1) + +static unsigned char fdt_buf[16 << 10] __initdata; + +static int remove_gic(void *fdt) +{ + int gic_off, cpu_off, err; + uint32_t cfg, cpu_phandle; + + /* leave the GIC node intact if a GIC is present */ + cfg = __raw_readl((uint32_t *)SEAD_CONFIG); + if (cfg & SEAD_CONFIG_GIC_PRESENT) + return 0; + + gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic"); + if (gic_off < 0) { + pr_err("unable to find DT GIC node: %d\n", gic_off); + return gic_off; + } + + err = fdt_nop_node(fdt, gic_off); + if (err) { + pr_err("unable to nop GIC node\n"); + return err; + } + + cpu_off = fdt_node_offset_by_compatible(fdt, -1, + "mti,cpu-interrupt-controller"); + if (cpu_off < 0) { + pr_err("unable to find CPU intc node: %d\n", cpu_off); + return cpu_off; + } + + cpu_phandle = fdt_get_phandle(fdt, cpu_off); + if (!cpu_phandle) { + pr_err("unable to get CPU intc phandle\n"); + return -EINVAL; + } + + err = fdt_setprop_u32(fdt, 0, "interrupt-parent", cpu_phandle); + if (err) { + pr_err("unable to set root interrupt-parent: %d\n", err); + return err; + } + + return 0; +} + +void __init *sead3_dt_shim(void *fdt) +{ + int err; + + if (fdt_check_header(fdt)) + panic("Corrupt DT"); + + /* if this isn't SEAD3, leave the DT alone */ + if (fdt_node_check_compatible(fdt, 0, "mti,sead-3")) + return fdt; + + err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf)); + if (err) + panic("Unable to open FDT: %d", err); + + err = remove_gic(fdt_buf); + if (err) + panic("Unable to patch FDT: %d", err); + + err = fdt_pack(fdt_buf); + if (err) + panic("Unable to pack FDT: %d\n", err); + + return fdt_buf; +} diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c index e31e17f81eefd..2e6b73244ecda 100644 --- a/arch/mips/mti-sead3/sead3-int.c +++ b/arch/mips/mti-sead3/sead3-int.c @@ -6,37 +6,18 @@ * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. */ #include -#include +#include #include -#include -#include -#include - -#include - -#define SEAD_CONFIG_GIC_PRESENT_SHF 1 -#define SEAD_CONFIG_GIC_PRESENT_MSK (1 << SEAD_CONFIG_GIC_PRESENT_SHF) -#define SEAD_CONFIG_BASE 0x1b100110 -#define SEAD_CONFIG_SIZE 4 - -static void __iomem *sead3_config_reg; +#include +#include void __init arch_init_irq(void) { - if (!cpu_has_veic) - mips_cpu_irq_init(); + irqchip_init(); - sead3_config_reg = ioremap_nocache(SEAD_CONFIG_BASE, SEAD_CONFIG_SIZE); - gic_present = (__raw_readl(sead3_config_reg) & - SEAD_CONFIG_GIC_PRESENT_MSK) >> - SEAD_CONFIG_GIC_PRESENT_SHF; pr_info("GIC: %spresent\n", (gic_present) ? "" : "not "); pr_info("EIC: %s\n", (current_cpu_data.options & MIPS_CPU_VEIC) ? "on" : "off"); - - if (gic_present) - gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, CPU_INT_GIC, - MIPS_GIC_IRQ_BASE); } diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c index 73b73efbfb058..d6be0298056a3 100644 --- a/arch/mips/mti-sead3/sead3-platform.c +++ b/arch/mips/mti-sead3/sead3-platform.c @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -204,16 +206,41 @@ static struct platform_device *sead3_platform_devices[] __initdata = { static int __init sead3_platforms_device_init(void) { + const char *intc_compat; + struct device_node *node; + struct irq_domain *irqd; + + if (gic_present) + intc_compat = "mti,gic"; + else + intc_compat = "mti,cpu-interrupt-controller"; + + node = of_find_compatible_node(NULL, NULL, intc_compat); + if (!node) { + pr_err("unable to find interrupt controller DT node\n"); + return -ENODEV; + } + + irqd = irq_find_host(node); + if (!irqd) { + pr_err("unable to find interrupt controller IRQ domain\n"); + return -ENODEV; + } + if (gic_present) { - uart8250_data[0].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART0; - uart8250_data[1].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART1; - ehci_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_EHCI; - sead3_net_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_NET; + uart8250_data[0].irq = irq_create_mapping(irqd, GIC_INT_UART0); + uart8250_data[1].irq = irq_create_mapping(irqd, GIC_INT_UART1); + ehci_resources[1].start = + irq_create_mapping(irqd, GIC_INT_EHCI); + sead3_net_resources[1].start = + irq_create_mapping(irqd, GIC_INT_NET); } else { - uart8250_data[0].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART0; - uart8250_data[1].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART1; - ehci_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_EHCI; - sead3_net_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_NET; + uart8250_data[0].irq = irq_create_mapping(irqd, CPU_INT_UART0); + uart8250_data[1].irq = irq_create_mapping(irqd, CPU_INT_UART1); + ehci_resources[1].start = + irq_create_mapping(irqd, CPU_INT_EHCI); + sead3_net_resources[1].start = + irq_create_mapping(irqd, CPU_INT_NET); } return platform_add_devices(sead3_platform_devices, diff --git a/arch/mips/mti-sead3/sead3-setup.c b/arch/mips/mti-sead3/sead3-setup.c index edfcaf06680d3..c4fc0c6d26543 100644 --- a/arch/mips/mti-sead3/sead3-setup.c +++ b/arch/mips/mti-sead3/sead3-setup.c @@ -13,6 +13,7 @@ #include #include +#include #include const char *get_system_type(void) @@ -89,20 +90,16 @@ void __init *plat_get_fdt(void) void __init plat_mem_setup(void) { + void *fdt = plat_get_fdt(); + /* allow command line/bootloader env to override memory size in DT */ parse_memsize_param(); - /* - * Load the builtin devicetree. This causes the chosen node to be - * parsed resulting in our memory appearing - */ - __dt_setup_arch(__dtb_start); + fdt = sead3_dt_shim(fdt); + __dt_setup_arch(fdt); } void __init device_tree_init(void) { - if (!initial_boot_params) - return; - unflatten_and_copy_device_tree(); } -- GitLab From c11e3b48dbc367e38dfaea6e8a61d3b39f476685 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:35 +0100 Subject: [PATCH 0279/1167] MIPS: SEAD3: Probe UARTs using DT Probe the UARTs on SEAD3 boards using device tree rather than platform code, in order to reduce the amount of the latter. This requires that CONFIG_SERIAL_OF_PLATFORM be enabled, so enable it in sead3_defconfig. The SEAD3 DT shim code is extended to read bootloader environment variables to determine the appropriate UART & mode for kernel console output & set the stdout-path property of the chosen node accordingly. In contrast to the old platform code, which appears to have only ever set "console=ttyS0,38400n8r" with the code in console_config never having an effect, this will honor the "yamontty" environment variable to select between the 2 UARTs on the board and then check the "modetty0" or "modetty1" variable as appropriate to determine the UART configuration. Signed-off-by: Paul Burton Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14048/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 37 +++++++ arch/mips/configs/sead3_defconfig | 2 + arch/mips/include/asm/mips-boards/sead3int.h | 4 - arch/mips/mti-sead3/sead3-dtshim.c | 105 ++++++++++++++++++- arch/mips/mti-sead3/sead3-init.c | 46 -------- arch/mips/mti-sead3/sead3-platform.c | 30 ------ 6 files changed, 143 insertions(+), 81 deletions(-) diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index 051b3a9e5a9e5..3f681c5300824 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -12,6 +12,15 @@ compatible = "mti,sead-3"; interrupt-parent = <&gic>; + chosen { + stdout-path = "uart1:115200"; + }; + + aliases { + uart0 = &uart0; + uart1 = &uart1; + }; + cpus { cpu@0 { compatible = "mti,mips14KEc", "mti,mips14Kc"; @@ -50,4 +59,32 @@ interrupts = ; }; }; + + /* UART connected to FTDI & miniUSB socket */ + uart0: uart@1f000900 { + compatible = "ns16550a"; + reg = <0x1f000900 0x20>; + reg-io-width = <4>; + reg-shift = <2>; + + clock-frequency = <14745600>; + + interrupts = <3>; /* GIC 3 or CPU 4 */ + + no-loopback-test; + }; + + /* UART connected to RS232 socket */ + uart1: uart@1f000800 { + compatible = "ns16550a"; + reg = <0x1f000800 0x20>; + reg-io-width = <4>; + reg-shift = <2>; + + clock-frequency = <14745600>; + + interrupts = <2>; /* GIC 2 or CPU 4 */ + + no-loopback-test; + }; }; diff --git a/arch/mips/configs/sead3_defconfig b/arch/mips/configs/sead3_defconfig index dae9354b62563..deb48fb77d1fd 100644 --- a/arch/mips/configs/sead3_defconfig +++ b/arch/mips/configs/sead3_defconfig @@ -39,6 +39,7 @@ CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_UBI=y CONFIG_MTD_UBI_GLUEBI=y +CONFIG_OF=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_SCSI=y @@ -70,6 +71,7 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set CONFIG_I2C=y # CONFIG_I2C_COMPAT is not set diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h index bd85da3d6770a..3a5e079fda762 100644 --- a/arch/mips/include/asm/mips-boards/sead3int.h +++ b/arch/mips/include/asm/mips-boards/sead3int.h @@ -14,14 +14,10 @@ /* CPU interrupt offsets */ #define CPU_INT_EHCI 2 -#define CPU_INT_UART0 4 -#define CPU_INT_UART1 4 #define CPU_INT_NET 6 /* GIC interrupt offsets */ #define GIC_INT_NET GIC_SHARED_TO_HWIRQ(0) -#define GIC_INT_UART1 GIC_SHARED_TO_HWIRQ(2) -#define GIC_INT_UART0 GIC_SHARED_TO_HWIRQ(3) #define GIC_INT_EHCI GIC_SHARED_TO_HWIRQ(5) #endif /* !(_MIPS_SEAD3INT_H) */ diff --git a/arch/mips/mti-sead3/sead3-dtshim.c b/arch/mips/mti-sead3/sead3-dtshim.c index 3283a7e19a889..b462f65b8ce07 100644 --- a/arch/mips/mti-sead3/sead3-dtshim.c +++ b/arch/mips/mti-sead3/sead3-dtshim.c @@ -14,6 +14,7 @@ #include #include +#include #include #define SEAD_CONFIG CKSEG1ADDR(0x1b100110) @@ -23,7 +24,8 @@ static unsigned char fdt_buf[16 << 10] __initdata; static int remove_gic(void *fdt) { - int gic_off, cpu_off, err; + const unsigned int cpu_uart_int = 4; + int gic_off, cpu_off, uart_off, err; uint32_t cfg, cpu_phandle; /* leave the GIC node intact if a GIC is present */ @@ -62,6 +64,103 @@ static int remove_gic(void *fdt) return err; } + uart_off = fdt_node_offset_by_compatible(fdt, -1, "ns16550a"); + while (uart_off >= 0) { + err = fdt_setprop_u32(fdt, uart_off, "interrupts", + cpu_uart_int); + if (err) { + pr_err("unable to set UART interrupts property: %d\n", + err); + return err; + } + + uart_off = fdt_node_offset_by_compatible(fdt, uart_off, + "ns16550a"); + } + if (uart_off != -FDT_ERR_NOTFOUND) { + pr_err("error searching for UART DT node: %d\n", uart_off); + return uart_off; + } + + return 0; +} + +static int serial_config(void *fdt) +{ + const char *yamontty, *mode_var; + char mode_var_name[9], path[18], parity; + unsigned int uart, baud, stop_bits; + bool hw_flow; + int chosen_off, err; + + yamontty = fw_getenv("yamontty"); + if (!yamontty || !strcmp(yamontty, "tty0")) { + uart = 0; + } else if (!strcmp(yamontty, "tty1")) { + uart = 1; + } else { + pr_warn("yamontty environment variable '%s' invalid\n", + yamontty); + uart = 0; + } + + baud = stop_bits = 0; + parity = 0; + hw_flow = false; + + snprintf(mode_var_name, sizeof(mode_var_name), "modetty%u", uart); + mode_var = fw_getenv(mode_var_name); + if (mode_var) { + while (mode_var[0] >= '0' && mode_var[0] <= '9') { + baud *= 10; + baud += mode_var[0] - '0'; + mode_var++; + } + if (mode_var[0] == ',') + mode_var++; + if (mode_var[0]) + parity = mode_var[0]; + if (mode_var[0] == ',') + mode_var++; + if (mode_var[0]) + stop_bits = mode_var[0] - '0'; + if (mode_var[0] == ',') + mode_var++; + if (!strcmp(mode_var, "hw")) + hw_flow = true; + } + + if (!baud) + baud = 38400; + + if (parity != 'e' && parity != 'n' && parity != 'o') + parity = 'n'; + + if (stop_bits != 7 && stop_bits != 8) + stop_bits = 8; + + WARN_ON(snprintf(path, sizeof(path), "uart%u:%u%c%u%s", + uart, baud, parity, stop_bits, + hw_flow ? "r" : "") >= sizeof(path)); + + /* find or add chosen node */ + chosen_off = fdt_path_offset(fdt, "/chosen"); + if (chosen_off == -FDT_ERR_NOTFOUND) + chosen_off = fdt_path_offset(fdt, "/chosen@0"); + if (chosen_off == -FDT_ERR_NOTFOUND) + chosen_off = fdt_add_subnode(fdt, 0, "chosen"); + if (chosen_off < 0) { + pr_err("Unable to find or add DT chosen node: %d\n", + chosen_off); + return chosen_off; + } + + err = fdt_setprop_string(fdt, chosen_off, "stdout-path", path); + if (err) { + pr_err("Unable to set stdout-path property: %d\n", err); + return err; + } + return 0; } @@ -84,6 +183,10 @@ void __init *sead3_dt_shim(void *fdt) if (err) panic("Unable to patch FDT: %d", err); + err = serial_config(fdt_buf); + if (err) + panic("Unable to patch FDT: %d", err); + err = fdt_pack(fdt_buf); if (err) panic("Unable to pack FDT: %d\n", err); diff --git a/arch/mips/mti-sead3/sead3-init.c b/arch/mips/mti-sead3/sead3-init.c index 3572ea30173ef..e81f5b7657f0c 100644 --- a/arch/mips/mti-sead3/sead3-init.c +++ b/arch/mips/mti-sead3/sead3-init.c @@ -17,47 +17,6 @@ extern char except_vec_nmi; extern char except_vec_ejtag_debug; -#ifdef CONFIG_SERIAL_8250_CONSOLE -static void __init console_config(void) -{ - char console_string[40]; - int baud = 0; - char parity = '\0', bits = '\0', flow = '\0'; - char *s; - - if ((strstr(fw_getcmdline(), "console=")) == NULL) { - s = fw_getenv("modetty0"); - if (s) { - while (*s >= '0' && *s <= '9') - baud = baud*10 + *s++ - '0'; - if (*s == ',') - s++; - if (*s) - parity = *s++; - if (*s == ',') - s++; - if (*s) - bits = *s++; - if (*s == ',') - s++; - if (*s == 'h') - flow = 'r'; - } - if (baud == 0) - baud = 38400; - if (parity != 'n' && parity != 'o' && parity != 'e') - parity = 'n'; - if (bits != '7' && bits != '8') - bits = '8'; - if (flow == '\0') - flow = 'r'; - sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, - parity, bits, flow); - strcat(fw_getcmdline(), console_string); - } -} -#endif - static void __init mips_nmi_setup(void) { void *base; @@ -140,11 +99,6 @@ void __init prom_init(void) else if ((strstr(fw_getcmdline(), "console=ttyS1")) != NULL) fw_init_early_console(1); #endif -#ifdef CONFIG_SERIAL_8250_CONSOLE - if ((strstr(fw_getcmdline(), "console=")) == NULL) - strcat(fw_getcmdline(), " console=ttyS0,38400n8r"); - console_config(); -#endif } void __init prom_free_prom_memory(void) diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c index d6be0298056a3..538a6f8f09175 100644 --- a/arch/mips/mti-sead3/sead3-platform.c +++ b/arch/mips/mti-sead3/sead3-platform.c @@ -14,35 +14,10 @@ #include #include #include -#include #include #include -#define UART(base) \ -{ \ - .mapbase = base, \ - .irq = -1, \ - .uartclk = 14745600, \ - .iotype = UPIO_MEM32, \ - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, \ - .regshift = 2, \ -} - -static struct plat_serial8250_port uart8250_data[] = { - UART(0x1f000900), /* ttyS0 = USB */ - UART(0x1f000800), /* ttyS1 = RS232 */ - { }, -}; - -static struct platform_device uart8250_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM2, - .dev = { - .platform_data = uart8250_data, - }, -}; - static struct smsc911x_platform_config sead3_smsc911x_data = { .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, @@ -195,7 +170,6 @@ static struct platform_device ehci_device = { }; static struct platform_device *sead3_platform_devices[] __initdata = { - &uart8250_device, &sead3_flash, &pled_device, &fled_device, @@ -228,15 +202,11 @@ static int __init sead3_platforms_device_init(void) } if (gic_present) { - uart8250_data[0].irq = irq_create_mapping(irqd, GIC_INT_UART0); - uart8250_data[1].irq = irq_create_mapping(irqd, GIC_INT_UART1); ehci_resources[1].start = irq_create_mapping(irqd, GIC_INT_EHCI); sead3_net_resources[1].start = irq_create_mapping(irqd, GIC_INT_NET); } else { - uart8250_data[0].irq = irq_create_mapping(irqd, CPU_INT_UART0); - uart8250_data[1].irq = irq_create_mapping(irqd, CPU_INT_UART1); ehci_resources[1].start = irq_create_mapping(irqd, CPU_INT_EHCI); sead3_net_resources[1].start = -- GitLab From 53f37d1d306927d21e0256fe6c48fa517d889cf7 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:36 +0100 Subject: [PATCH 0280/1167] MIPS: SEAD3: Use generic ns16550a earlycon support Stop selecting SYS_HAS_EARLY_PRINTK & remove the custom support for early output to the ns16550a UARTs, instead relying upon generic ns16550a earlycon support. This reduces the amount of platform code required for SEAD3 without losing any functionality. Signed-off-by: Paul Burton Cc: Jacek Anaszewski Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14049/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 - arch/mips/configs/sead3_defconfig | 2 ++ arch/mips/mti-sead3/Makefile | 2 -- arch/mips/mti-sead3/sead3-console.c | 46 ----------------------------- arch/mips/mti-sead3/sead3-init.c | 6 ---- 5 files changed, 2 insertions(+), 55 deletions(-) delete mode 100644 arch/mips/mti-sead3/sead3-console.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 6fba0eff858e1..7ec9ed7ab67b7 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -514,7 +514,6 @@ config MIPS_SEAD3 select SYS_HAS_CPU_MIPS32_R2 select SYS_HAS_CPU_MIPS32_R6 select SYS_HAS_CPU_MIPS64_R1 - select SYS_HAS_EARLY_PRINTK select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN diff --git a/arch/mips/configs/sead3_defconfig b/arch/mips/configs/sead3_defconfig index deb48fb77d1fd..23cce819d669c 100644 --- a/arch/mips/configs/sead3_defconfig +++ b/arch/mips/configs/sead3_defconfig @@ -15,6 +15,8 @@ CONFIG_PROFILING=y CONFIG_OPROFILE=y CONFIG_MODULES=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon" # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_NET=y CONFIG_PACKET=y diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile index aad67aac3dbae..a58b6d9648464 100644 --- a/arch/mips/mti-sead3/Makefile +++ b/arch/mips/mti-sead3/Makefile @@ -17,5 +17,3 @@ obj-y += sead3-platform.o obj-y += sead3-reset.o obj-y += sead3-setup.o obj-y += sead3-time.o - -obj-$(CONFIG_EARLY_PRINTK) += sead3-console.o diff --git a/arch/mips/mti-sead3/sead3-console.c b/arch/mips/mti-sead3/sead3-console.c deleted file mode 100644 index 031f47d697700..0000000000000 --- a/arch/mips/mti-sead3/sead3-console.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include -#include -#include -#include - -#define SEAD_UART1_REGS_BASE 0xbf000800 /* ttyS1 = DB9 port */ -#define SEAD_UART0_REGS_BASE 0xbf000900 /* ttyS0 = USB port */ -#define PORT(base_addr, offset) ((unsigned int __iomem *)(base_addr+(offset)*4)) - -static char console_port = 1; - -static inline unsigned int serial_in(int offset, unsigned int base_addr) -{ - return __raw_readl(PORT(base_addr, offset)) & 0xff; -} - -static inline void serial_out(int offset, int value, unsigned int base_addr) -{ - __raw_writel(value, PORT(base_addr, offset)); -} - -void __init fw_init_early_console(char port) -{ - console_port = port; -} - -int prom_putchar(char c) -{ - unsigned int base_addr; - - base_addr = console_port ? SEAD_UART1_REGS_BASE : SEAD_UART0_REGS_BASE; - - while ((serial_in(UART_LSR, base_addr) & UART_LSR_THRE) == 0) - ; - - serial_out(UART_TX, c, base_addr); - - return 1; -} diff --git a/arch/mips/mti-sead3/sead3-init.c b/arch/mips/mti-sead3/sead3-init.c index e81f5b7657f0c..50f3fcb0fd806 100644 --- a/arch/mips/mti-sead3/sead3-init.c +++ b/arch/mips/mti-sead3/sead3-init.c @@ -93,12 +93,6 @@ void __init prom_init(void) board_ejtag_handler_setup = mips_ejtag_setup; fw_init_cmdline(); -#ifdef CONFIG_EARLY_PRINTK - if ((strstr(fw_getcmdline(), "console=ttyS0")) != NULL) - fw_init_early_console(0); - else if ((strstr(fw_getcmdline(), "console=ttyS1")) != NULL) - fw_init_early_console(1); -#endif } void __init prom_free_prom_memory(void) -- GitLab From a34e93882de4e50e349d2d23b20dde5257d42f94 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:37 +0100 Subject: [PATCH 0281/1167] MIPS: SEAD3: Probe ethernet controller using DT Probe the smsc911x ethernet controller using device tree rather than platform code, reducing the amount of the latter. Signed-off-by: Paul Burton Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14050/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 12 +++++++ arch/mips/include/asm/mips-boards/sead3int.h | 2 -- arch/mips/mti-sead3/sead3-dtshim.c | 15 ++++++++- arch/mips/mti-sead3/sead3-platform.c | 33 -------------------- 4 files changed, 26 insertions(+), 36 deletions(-) diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index 3f681c5300824..29ed194fc7622 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -87,4 +87,16 @@ no-loopback-test; }; + + eth@1f010000 { + compatible = "smsc,lan9115"; + reg = <0x1f010000 0x10000>; + reg-io-width = <4>; + + interrupts = <0>; /* GIC 0 or CPU 6 */ + + phy-mode = "mii"; + smsc,irq-push-pull; + smsc,save-mac-address; + }; }; diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h index 3a5e079fda762..7fdb9d4598bff 100644 --- a/arch/mips/include/asm/mips-boards/sead3int.h +++ b/arch/mips/include/asm/mips-boards/sead3int.h @@ -14,10 +14,8 @@ /* CPU interrupt offsets */ #define CPU_INT_EHCI 2 -#define CPU_INT_NET 6 /* GIC interrupt offsets */ -#define GIC_INT_NET GIC_SHARED_TO_HWIRQ(0) #define GIC_INT_EHCI GIC_SHARED_TO_HWIRQ(5) #endif /* !(_MIPS_SEAD3INT_H) */ diff --git a/arch/mips/mti-sead3/sead3-dtshim.c b/arch/mips/mti-sead3/sead3-dtshim.c index b462f65b8ce07..279d8d4646932 100644 --- a/arch/mips/mti-sead3/sead3-dtshim.c +++ b/arch/mips/mti-sead3/sead3-dtshim.c @@ -25,7 +25,8 @@ static unsigned char fdt_buf[16 << 10] __initdata; static int remove_gic(void *fdt) { const unsigned int cpu_uart_int = 4; - int gic_off, cpu_off, uart_off, err; + const unsigned int cpu_eth_int = 6; + int gic_off, cpu_off, uart_off, eth_off, err; uint32_t cfg, cpu_phandle; /* leave the GIC node intact if a GIC is present */ @@ -82,6 +83,18 @@ static int remove_gic(void *fdt) return uart_off; } + eth_off = fdt_node_offset_by_compatible(fdt, -1, "smsc,lan9115"); + if (eth_off < 0) { + pr_err("unable to find ethernet DT node: %d\n", eth_off); + return eth_off; + } + + err = fdt_setprop_u32(fdt, eth_off, "interrupts", cpu_eth_int); + if (err) { + pr_err("unable to set ethernet interrupts property: %d\n", err); + return err; + } + return 0; } diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c index 538a6f8f09175..9f9e91471f178 100644 --- a/arch/mips/mti-sead3/sead3-platform.c +++ b/arch/mips/mti-sead3/sead3-platform.c @@ -14,37 +14,9 @@ #include #include #include -#include #include -static struct smsc911x_platform_config sead3_smsc911x_data = { - .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, - .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, - .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS, - .phy_interface = PHY_INTERFACE_MODE_MII, -}; - -static struct resource sead3_net_resources[] = { - { - .start = 0x1f010000, - .end = 0x1f01ffff, - .flags = IORESOURCE_MEM - }, { - .flags = IORESOURCE_IRQ - } -}; - -static struct platform_device sead3_net_device = { - .name = "smsc911x", - .id = 0, - .dev = { - .platform_data = &sead3_smsc911x_data, - }, - .num_resources = ARRAY_SIZE(sead3_net_resources), - .resource = sead3_net_resources -}; - static struct mtd_partition sead3_mtd_partitions[] = { { .name = "User FS", @@ -175,7 +147,6 @@ static struct platform_device *sead3_platform_devices[] __initdata = { &fled_device, &sead3_led_device, &ehci_device, - &sead3_net_device, }; static int __init sead3_platforms_device_init(void) @@ -204,13 +175,9 @@ static int __init sead3_platforms_device_init(void) if (gic_present) { ehci_resources[1].start = irq_create_mapping(irqd, GIC_INT_EHCI); - sead3_net_resources[1].start = - irq_create_mapping(irqd, GIC_INT_NET); } else { ehci_resources[1].start = irq_create_mapping(irqd, CPU_INT_EHCI); - sead3_net_resources[1].start = - irq_create_mapping(irqd, CPU_INT_NET); } return platform_add_devices(sead3_platform_devices, -- GitLab From 7afd2a5aec2ea27ba87b3a423c5d782fe0f2b96b Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:38 +0100 Subject: [PATCH 0282/1167] MIPS: SEAD3: Probe EHCI controller using DT Probe the SEAD3 EHCI controller using the generic-ehci driver & device tree rather than platform code, in order to reduce the amount of the latter. Now that no devices probed from platform code require interrupts, remove the retrieval of the IRQ domain & sead3int.h. Signed-off-by: Paul Burton Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14051/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 9 +++ arch/mips/include/asm/mips-boards/sead3int.h | 21 ------- arch/mips/mti-sead3/sead3-dtshim.c | 15 ++++- arch/mips/mti-sead3/sead3-platform.c | 59 -------------------- 4 files changed, 23 insertions(+), 81 deletions(-) delete mode 100644 arch/mips/include/asm/mips-boards/sead3int.h diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index 29ed194fc7622..49f57c2818126 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -60,6 +60,15 @@ }; }; + ehci@1b200000 { + compatible = "generic-ehci"; + reg = <0x1b200000 0x1000>; + + interrupts = <0>; /* GIC 0 or CPU 6 */ + + has-transaction-translator; + }; + /* UART connected to FTDI & miniUSB socket */ uart0: uart@1f000900 { compatible = "ns16550a"; diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h deleted file mode 100644 index 7fdb9d4598bff..0000000000000 --- a/arch/mips/include/asm/mips-boards/sead3int.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000,2012 MIPS Technologies, Inc. All rights reserved. - * Douglas Leung - * Steven J. Hill - */ -#ifndef _MIPS_SEAD3INT_H -#define _MIPS_SEAD3INT_H - -#include - -/* CPU interrupt offsets */ -#define CPU_INT_EHCI 2 - -/* GIC interrupt offsets */ -#define GIC_INT_EHCI GIC_SHARED_TO_HWIRQ(5) - -#endif /* !(_MIPS_SEAD3INT_H) */ diff --git a/arch/mips/mti-sead3/sead3-dtshim.c b/arch/mips/mti-sead3/sead3-dtshim.c index 279d8d4646932..6e32ceba533b5 100644 --- a/arch/mips/mti-sead3/sead3-dtshim.c +++ b/arch/mips/mti-sead3/sead3-dtshim.c @@ -24,9 +24,10 @@ static unsigned char fdt_buf[16 << 10] __initdata; static int remove_gic(void *fdt) { + const unsigned int cpu_ehci_int = 2; const unsigned int cpu_uart_int = 4; const unsigned int cpu_eth_int = 6; - int gic_off, cpu_off, uart_off, eth_off, err; + int gic_off, cpu_off, uart_off, eth_off, ehci_off, err; uint32_t cfg, cpu_phandle; /* leave the GIC node intact if a GIC is present */ @@ -95,6 +96,18 @@ static int remove_gic(void *fdt) return err; } + ehci_off = fdt_node_offset_by_compatible(fdt, -1, "mti,sead3-ehci"); + if (ehci_off < 0) { + pr_err("unable to find EHCI DT node: %d\n", ehci_off); + return ehci_off; + } + + err = fdt_setprop_u32(fdt, ehci_off, "interrupts", cpu_ehci_int); + if (err) { + pr_err("unable to set EHCI interrupts property: %d\n", err); + return err; + } + return 0; } diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c index 9f9e91471f178..21047b596af8e 100644 --- a/arch/mips/mti-sead3/sead3-platform.c +++ b/arch/mips/mti-sead3/sead3-platform.c @@ -7,16 +7,10 @@ */ #include #include -#include -#include -#include #include #include -#include #include -#include - static struct mtd_partition sead3_mtd_partitions[] = { { .name = "User FS", @@ -118,68 +112,15 @@ static struct platform_device sead3_led_device = { .id = -1, }; -static struct resource ehci_resources[] = { - { - .start = 0x1b200000, - .end = 0x1b200fff, - .flags = IORESOURCE_MEM - }, { - .flags = IORESOURCE_IRQ - } -}; - -static u64 sead3_usbdev_dma_mask = DMA_BIT_MASK(32); - -static struct platform_device ehci_device = { - .name = "sead3-ehci", - .id = 0, - .dev = { - .dma_mask = &sead3_usbdev_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32) - }, - .num_resources = ARRAY_SIZE(ehci_resources), - .resource = ehci_resources -}; - static struct platform_device *sead3_platform_devices[] __initdata = { &sead3_flash, &pled_device, &fled_device, &sead3_led_device, - &ehci_device, }; static int __init sead3_platforms_device_init(void) { - const char *intc_compat; - struct device_node *node; - struct irq_domain *irqd; - - if (gic_present) - intc_compat = "mti,gic"; - else - intc_compat = "mti,cpu-interrupt-controller"; - - node = of_find_compatible_node(NULL, NULL, intc_compat); - if (!node) { - pr_err("unable to find interrupt controller DT node\n"); - return -ENODEV; - } - - irqd = irq_find_host(node); - if (!irqd) { - pr_err("unable to find interrupt controller IRQ domain\n"); - return -ENODEV; - } - - if (gic_present) { - ehci_resources[1].start = - irq_create_mapping(irqd, GIC_INT_EHCI); - } else { - ehci_resources[1].start = - irq_create_mapping(irqd, CPU_INT_EHCI); - } - return platform_add_devices(sead3_platform_devices, ARRAY_SIZE(sead3_platform_devices)); } -- GitLab From 63c8d90ca967c7e87006dbd363a8724ba31f1b57 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:39 +0100 Subject: [PATCH 0283/1167] USB: host: ehci-sead3: Remove SEAD-3 EHCI code The SEAD-3 board is now probing its EHCI controller using the generic EHCI driver & its generic-ehci device tree binding. Remove the unused SEAD-3 specific EHCI code. Signed-off-by: Paul Burton Acked-by: Alan Stern Cc: Greg Kroah-Hartman Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: linux-usb@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14052/ Signed-off-by: Ralf Baechle --- drivers/usb/host/ehci-hcd.c | 5 - drivers/usb/host/ehci-sead3.c | 185 ---------------------------------- 2 files changed, 190 deletions(-) delete mode 100644 drivers/usb/host/ehci-sead3.c diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 1e5f529d51a21..063064801ceb0 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1308,11 +1308,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_mv_driver #endif -#ifdef CONFIG_MIPS_SEAD3 -#include "ehci-sead3.c" -#define PLATFORM_DRIVER ehci_hcd_sead3_driver -#endif - static int __init ehci_hcd_init(void) { int retval = 0; diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c deleted file mode 100644 index 3d86cc2ffe68a..0000000000000 --- a/drivers/usb/host/ehci-sead3.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * MIPS CI13320A EHCI Host Controller driver - * Based on "ehci-au1xxx.c" by K.Boge - * - * Copyright (C) 2012 MIPS Technologies, 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; either version 2 of the License, or (at your - * option) any later version. - * - * 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. - */ - -#include -#include - -static int ehci_sead3_setup(struct usb_hcd *hcd) -{ - int ret; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - ehci->caps = hcd->regs + 0x100; - -#ifdef __BIG_ENDIAN - ehci->big_endian_mmio = 1; - ehci->big_endian_desc = 1; -#endif - - ret = ehci_setup(hcd); - if (ret) - return ret; - - ehci->need_io_watchdog = 0; - - /* Set burst length to 16 words. */ - ehci_writel(ehci, 0x1010, &ehci->regs->reserved1[1]); - - return ret; -} - -const struct hc_driver ehci_sead3_hc_driver = { - .description = hcd_name, - .product_desc = "SEAD-3 EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, - - /* - * basic lifecycle operations - * - */ - .reset = ehci_sead3_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct resource *res; - int ret; - - if (usb_disabled()) - return -ENODEV; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ"); - return -ENOMEM; - } - hcd = usb_create_hcd(&ehci_sead3_hc_driver, &pdev->dev, "SEAD-3"); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(hcd->regs)) { - ret = PTR_ERR(hcd->regs); - goto err1; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - /* Root hub has integrated TT. */ - hcd->has_tt = 1; - - ret = usb_add_hcd(hcd, pdev->resource[1].start, - IRQF_SHARED); - if (ret == 0) { - platform_set_drvdata(pdev, hcd); - device_wakeup_enable(hcd->self.controller); - return ret; - } - -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - - return 0; -} - -#ifdef CONFIG_PM -static int ehci_hcd_sead3_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - bool do_wakeup = device_may_wakeup(dev); - - return ehci_suspend(hcd, do_wakeup); -} - -static int ehci_hcd_sead3_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - - ehci_resume(hcd, false); - return 0; -} - -static const struct dev_pm_ops sead3_ehci_pmops = { - .suspend = ehci_hcd_sead3_drv_suspend, - .resume = ehci_hcd_sead3_drv_resume, -}; - -#define SEAD3_EHCI_PMOPS (&sead3_ehci_pmops) - -#else -#define SEAD3_EHCI_PMOPS NULL -#endif - -static struct platform_driver ehci_hcd_sead3_driver = { - .probe = ehci_hcd_sead3_drv_probe, - .remove = ehci_hcd_sead3_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "sead3-ehci", - .pm = SEAD3_EHCI_PMOPS, - } -}; - -MODULE_ALIAS("platform:sead3-ehci"); -- GitLab From 3aefc6554ad95f64de5ab384a959f96eb188f273 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:40 +0100 Subject: [PATCH 0284/1167] MIPS: SEAD3: Probe parallel flash via DT Probe the system parallel flash using device tree rather than platform code, in order to reduce the amount of the latter. Signed-off-by: Paul Burton Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14053/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 24 ++++++++++++++++++ arch/mips/mti-sead3/sead3-platform.c | 37 ---------------------------- 2 files changed, 24 insertions(+), 37 deletions(-) diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index 49f57c2818126..8844cc0066769 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -69,6 +69,30 @@ has-transaction-translator; }; + flash@1c000000 { + compatible = "intel,28f128j3", "cfi-flash"; + reg = <0x1c000000 0x2000000>; + #address-cells = <1>; + #size-cells = <1>; + bank-width = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + user-fs@0 { + label = "User FS"; + reg = <0x0 0x1fc0000>; + }; + + board-config@3e0000 { + label = "Board Config"; + reg = <0x1fc0000 0x40000>; + }; + }; + }; + /* UART connected to FTDI & miniUSB socket */ uart0: uart@1f000900 { compatible = "ns16550a"; diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c index 21047b596af8e..5c1f42a23ac5f 100644 --- a/arch/mips/mti-sead3/sead3-platform.c +++ b/arch/mips/mti-sead3/sead3-platform.c @@ -8,44 +8,8 @@ #include #include #include -#include #include -static struct mtd_partition sead3_mtd_partitions[] = { - { - .name = "User FS", - .offset = 0x00000000, - .size = 0x01fc0000, - }, { - .name = "Board Config", - .offset = 0x01fc0000, - .size = 0x00040000, - .mask_flags = MTD_WRITEABLE - }, -}; - -static struct physmap_flash_data sead3_flash_data = { - .width = 4, - .nr_parts = ARRAY_SIZE(sead3_mtd_partitions), - .parts = sead3_mtd_partitions -}; - -static struct resource sead3_flash_resource = { - .start = 0x1c000000, - .end = 0x1dffffff, - .flags = IORESOURCE_MEM -}; - -static struct platform_device sead3_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &sead3_flash_data, - }, - .num_resources = 1, - .resource = &sead3_flash_resource, -}; - #define LEDFLAGS(bits, shift) \ ((bits << 8) | (shift << 8)) @@ -113,7 +77,6 @@ static struct platform_device sead3_led_device = { }; static struct platform_device *sead3_platform_devices[] __initdata = { - &sead3_flash, &pled_device, &fled_device, &sead3_led_device, -- GitLab From c764583f40b8d3cde3a3a0b4a40a7d2fa3987bed Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:41 +0100 Subject: [PATCH 0285/1167] MIPS: SEAD3: Use register-bit-led driver via DT for LEDs Probe a driver for the PLED & FLED LEDs found on the SEAD3 board using the register-bit-led driver via device tree, rather than a custom driver via platform code. Enable support for the register-bit-led driver & its prerequisite syscon in sead3_defconfig. Signed-off-by: Paul Burton Cc: Jacek Anaszewski Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14054/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 103 +++++++++++++++++++++++++++ arch/mips/configs/sead3_defconfig | 2 + arch/mips/mti-sead3/Makefile | 1 - arch/mips/mti-sead3/sead3-platform.c | 91 ----------------------- 4 files changed, 105 insertions(+), 92 deletions(-) delete mode 100644 arch/mips/mti-sead3/sead3-platform.c diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index 8844cc0066769..0159450418edf 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -93,6 +93,109 @@ }; }; + system-controller@1f000200 { + compatible = "mti,sead3-cpld", "syscon", "simple-mfd"; + reg = <0x1f000200 0x300>; + + led@10.0 { + compatible = "register-bit-led"; + offset = <0x10>; + mask = <0x1>; + label = "pled0"; + }; + led@10.1 { + compatible = "register-bit-led"; + offset = <0x10>; + mask = <0x2>; + label = "pled1"; + }; + led@10.2 { + compatible = "register-bit-led"; + offset = <0x10>; + mask = <0x4>; + label = "pled2"; + }; + led@10.3 { + compatible = "register-bit-led"; + offset = <0x10>; + mask = <0x8>; + label = "pled3"; + }; + led@10.4 { + compatible = "register-bit-led"; + offset = <0x10>; + mask = <0x10>; + label = "pled4"; + }; + led@10.5 { + compatible = "register-bit-led"; + offset = <0x10>; + mask = <0x20>; + label = "pled5"; + }; + led@10.6 { + compatible = "register-bit-led"; + offset = <0x10>; + mask = <0x40>; + label = "pled6"; + }; + led@10.7 { + compatible = "register-bit-led"; + offset = <0x10>; + mask = <0x80>; + label = "pled7"; + }; + + led@18.0 { + compatible = "register-bit-led"; + offset = <0x18>; + mask = <0x1>; + label = "fled0"; + }; + led@18.1 { + compatible = "register-bit-led"; + offset = <0x18>; + mask = <0x2>; + label = "fled1"; + }; + led@18.2 { + compatible = "register-bit-led"; + offset = <0x18>; + mask = <0x4>; + label = "fled2"; + }; + led@18.3 { + compatible = "register-bit-led"; + offset = <0x18>; + mask = <0x8>; + label = "fled3"; + }; + led@18.4 { + compatible = "register-bit-led"; + offset = <0x18>; + mask = <0x10>; + label = "fled4"; + }; + led@18.5 { + compatible = "register-bit-led"; + offset = <0x18>; + mask = <0x20>; + label = "fled5"; + }; + led@18.6 { + compatible = "register-bit-led"; + offset = <0x18>; + mask = <0x40>; + label = "fled6"; + }; + led@18.7 { + compatible = "register-bit-led"; + offset = <0x18>; + mask = <0x80>; + label = "fled7"; + }; + }; + /* UART connected to FTDI & miniUSB socket */ uart0: uart@1f000900 { compatible = "ns16550a"; diff --git a/arch/mips/configs/sead3_defconfig b/arch/mips/configs/sead3_defconfig index 23cce819d669c..e1c6582ac7108 100644 --- a/arch/mips/configs/sead3_defconfig +++ b/arch/mips/configs/sead3_defconfig @@ -81,6 +81,7 @@ CONFIG_I2C_CHARDEV=y # CONFIG_I2C_HELPER_AUTO is not set CONFIG_SPI=y CONFIG_SENSORS_ADT7475=y +CONFIG_MFD_SYSCON=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_BACKLIGHT_CLASS_DEVICE=y @@ -95,6 +96,7 @@ CONFIG_MMC_DEBUG=y CONFIG_MMC_SPI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_SYSCON=y CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_RTC_CLASS=y diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile index a58b6d9648464..04ea002f9df26 100644 --- a/arch/mips/mti-sead3/Makefile +++ b/arch/mips/mti-sead3/Makefile @@ -13,7 +13,6 @@ obj-y += sead3-display.o obj-y += sead3-dtshim.o obj-y += sead3-init.o obj-y += sead3-int.o -obj-y += sead3-platform.o obj-y += sead3-reset.o obj-y += sead3-setup.o obj-y += sead3-time.o diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c deleted file mode 100644 index 5c1f42a23ac5f..0000000000000 --- a/arch/mips/mti-sead3/sead3-platform.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include -#include -#include -#include - -#define LEDFLAGS(bits, shift) \ - ((bits << 8) | (shift << 8)) - -#define LEDBITS(id, shift, bits) \ - .name = id #shift, \ - .flags = LEDFLAGS(bits, shift) - -static struct led_info led_data_info[] = { - { LEDBITS("bit", 0, 1) }, - { LEDBITS("bit", 1, 1) }, - { LEDBITS("bit", 2, 1) }, - { LEDBITS("bit", 3, 1) }, - { LEDBITS("bit", 4, 1) }, - { LEDBITS("bit", 5, 1) }, - { LEDBITS("bit", 6, 1) }, - { LEDBITS("bit", 7, 1) }, - { LEDBITS("all", 0, 8) }, -}; - -static struct led_platform_data led_data = { - .num_leds = ARRAY_SIZE(led_data_info), - .leds = led_data_info -}; - -static struct resource pled_resources[] = { - { - .start = 0x1f000210, - .end = 0x1f000217, - .flags = IORESOURCE_MEM - } -}; - -static struct platform_device pled_device = { - .name = "sead3::pled", - .id = 0, - .dev = { - .platform_data = &led_data, - }, - .num_resources = ARRAY_SIZE(pled_resources), - .resource = pled_resources -}; - - -static struct resource fled_resources[] = { - { - .start = 0x1f000218, - .end = 0x1f00021f, - .flags = IORESOURCE_MEM - } -}; - -static struct platform_device fled_device = { - .name = "sead3::fled", - .id = 0, - .dev = { - .platform_data = &led_data, - }, - .num_resources = ARRAY_SIZE(fled_resources), - .resource = fled_resources -}; - -static struct platform_device sead3_led_device = { - .name = "sead3-led", - .id = -1, -}; - -static struct platform_device *sead3_platform_devices[] __initdata = { - &pled_device, - &fled_device, - &sead3_led_device, -}; - -static int __init sead3_platforms_device_init(void) -{ - return platform_add_devices(sead3_platform_devices, - ARRAY_SIZE(sead3_platform_devices)); -} - -device_initcall(sead3_platforms_device_init); -- GitLab From 70bfdcec9ad9bcd3217f85fd422012777d86e168 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:43 +0100 Subject: [PATCH 0286/1167] MIPS: SEAD3: Reset via generic syscon-reboot driver & DT Remove the SEAD3 implementation of _machine_restart & instead make use of the generic syscon-reboot driver probed via device tree. Signed-off-by: Paul Burton Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14056/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 12 ++++++++++++ arch/mips/configs/sead3_defconfig | 3 ++- arch/mips/mti-sead3/sead3-reset.c | 9 --------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index 0159450418edf..047ff7aa5c21e 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -93,6 +93,18 @@ }; }; + fpga_regs: system-controller@1f000000 { + compatible = "mti,sead3-fpga", "syscon", "simple-mfd"; + reg = <0x1f000000 0x200>; + + reboot { + compatible = "syscon-reboot"; + regmap = <&fpga_regs>; + offset = <0x50>; + mask = <0x4d>; + }; + }; + system-controller@1f000200 { compatible = "mti,sead3-cpld", "syscon", "simple-mfd"; reg = <0x1f000200 0x300>; diff --git a/arch/mips/configs/sead3_defconfig b/arch/mips/configs/sead3_defconfig index e1c6582ac7108..055af30726522 100644 --- a/arch/mips/configs/sead3_defconfig +++ b/arch/mips/configs/sead3_defconfig @@ -80,8 +80,9 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y # CONFIG_I2C_HELPER_AUTO is not set CONFIG_SPI=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y CONFIG_SENSORS_ADT7475=y -CONFIG_MFD_SYSCON=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_BACKLIGHT_CLASS_DEVICE=y diff --git a/arch/mips/mti-sead3/sead3-reset.c b/arch/mips/mti-sead3/sead3-reset.c index e6fb24414a70e..8f548f02eb493 100644 --- a/arch/mips/mti-sead3/sead3-reset.c +++ b/arch/mips/mti-sead3/sead3-reset.c @@ -13,14 +13,6 @@ #define SOFTRES_REG 0x1f000050 #define GORESET 0x4d -static void mips_machine_restart(char *command) -{ - unsigned int __iomem *softres_reg = - ioremap(SOFTRES_REG, sizeof(unsigned int)); - - __raw_writel(GORESET, softres_reg); -} - static void mips_machine_halt(void) { unsigned int __iomem *softres_reg = @@ -31,7 +23,6 @@ static void mips_machine_halt(void) static int __init mips_reboot_setup(void) { - _machine_restart = mips_machine_restart; _machine_halt = mips_machine_halt; pm_power_off = mips_machine_halt; -- GitLab From a1ec6003f21547199f57ab529d0eff742917d637 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:44 +0100 Subject: [PATCH 0287/1167] MIPS: SEAD3: Use generic restart-poweroff driver Remove the custom platform code to restart when instructed to power off, instead relying upon the generic restart-poweroff driver probed via DT to do the same thing. Remove also the halt implementation, which is incorrect. The generic MIPS version will hang the system as halt should. Signed-off-by: Paul Burton Cc: Jacek Anaszewski Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14057/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 4 ++++ arch/mips/configs/sead3_defconfig | 1 + arch/mips/mti-sead3/Makefile | 1 - arch/mips/mti-sead3/sead3-reset.c | 31 ------------------------------- 4 files changed, 5 insertions(+), 32 deletions(-) delete mode 100644 arch/mips/mti-sead3/sead3-reset.c diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index 047ff7aa5c21e..32a5ab988b65b 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -103,6 +103,10 @@ offset = <0x50>; mask = <0x4d>; }; + + poweroff { + compatible = "restart-poweroff"; + }; }; system-controller@1f000200 { diff --git a/arch/mips/configs/sead3_defconfig b/arch/mips/configs/sead3_defconfig index 055af30726522..ab4c465d8025e 100644 --- a/arch/mips/configs/sead3_defconfig +++ b/arch/mips/configs/sead3_defconfig @@ -81,6 +81,7 @@ CONFIG_I2C_CHARDEV=y # CONFIG_I2C_HELPER_AUTO is not set CONFIG_SPI=y CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_RESTART=y CONFIG_POWER_RESET_SYSCON=y CONFIG_SENSORS_ADT7475=y CONFIG_BACKLIGHT_LCD_SUPPORT=y diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile index 04ea002f9df26..ad722c857c613 100644 --- a/arch/mips/mti-sead3/Makefile +++ b/arch/mips/mti-sead3/Makefile @@ -13,6 +13,5 @@ obj-y += sead3-display.o obj-y += sead3-dtshim.o obj-y += sead3-init.o obj-y += sead3-int.o -obj-y += sead3-reset.o obj-y += sead3-setup.o obj-y += sead3-time.o diff --git a/arch/mips/mti-sead3/sead3-reset.c b/arch/mips/mti-sead3/sead3-reset.c deleted file mode 100644 index 8f548f02eb493..0000000000000 --- a/arch/mips/mti-sead3/sead3-reset.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include -#include - -#include - -#define SOFTRES_REG 0x1f000050 -#define GORESET 0x4d - -static void mips_machine_halt(void) -{ - unsigned int __iomem *softres_reg = - ioremap(SOFTRES_REG, sizeof(unsigned int)); - - __raw_writel(GORESET, softres_reg); -} - -static int __init mips_reboot_setup(void) -{ - _machine_halt = mips_machine_halt; - pm_power_off = mips_machine_halt; - - return 0; -} -arch_initcall(mips_reboot_setup); -- GitLab From fd4d740427080f67c52e16d4fa639b30ccf1ccde Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:45 +0100 Subject: [PATCH 0288/1167] MIPS: SEAD3: Parse memsize in DT shim Parse the memsize argument provided by the bootloader in the DT shim code, allowing the user to override it on the command line. This places all of the DT manipulation code into sead3-dtshim.c. Signed-off-by: Paul Burton Cc: Matt Redfearn Cc: Rob Herring Cc: Kefeng Wang Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14058/ Signed-off-by: Ralf Baechle --- arch/mips/mti-sead3/sead3-dtshim.c | 71 ++++++++++++++++++++++++++++++ arch/mips/mti-sead3/sead3-setup.c | 66 --------------------------- 2 files changed, 71 insertions(+), 66 deletions(-) diff --git a/arch/mips/mti-sead3/sead3-dtshim.c b/arch/mips/mti-sead3/sead3-dtshim.c index 6e32ceba533b5..d6b0708d7a6f4 100644 --- a/arch/mips/mti-sead3/sead3-dtshim.c +++ b/arch/mips/mti-sead3/sead3-dtshim.c @@ -22,6 +22,73 @@ static unsigned char fdt_buf[16 << 10] __initdata; +static int append_memory(void *fdt) +{ + unsigned long phys_memsize, memsize; + __be32 mem_array[2]; + int err, mem_off; + char *var; + + /* find memory size from the bootloader environment */ + var = fw_getenv("memsize"); + if (var) { + err = kstrtoul(var, 0, &phys_memsize); + if (err) { + pr_err("Failed to read memsize env variable '%s'\n", + var); + return -EINVAL; + } + } else { + pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n"); + phys_memsize = 32 << 20; + } + + /* default to using all available RAM */ + memsize = phys_memsize; + + /* allow the user to override the usable memory */ + var = strstr(arcs_cmdline, "memsize="); + if (var) + memsize = memparse(var + strlen("memsize="), NULL); + + /* if the user says there's more RAM than we thought, believe them */ + phys_memsize = max_t(unsigned long, phys_memsize, memsize); + + /* find or add a memory node */ + mem_off = fdt_path_offset(fdt, "/memory"); + if (mem_off == -FDT_ERR_NOTFOUND) + mem_off = fdt_add_subnode(fdt, 0, "memory"); + if (mem_off < 0) { + pr_err("Unable to find or add memory DT node: %d\n", mem_off); + return mem_off; + } + + err = fdt_setprop_string(fdt, mem_off, "device_type", "memory"); + if (err) { + pr_err("Unable to set memory node device_type: %d\n", err); + return err; + } + + mem_array[0] = 0; + mem_array[1] = cpu_to_be32(phys_memsize); + err = fdt_setprop(fdt, mem_off, "reg", mem_array, sizeof(mem_array)); + if (err) { + pr_err("Unable to set memory regs property: %d\n", err); + return err; + } + + mem_array[0] = 0; + mem_array[1] = cpu_to_be32(memsize); + err = fdt_setprop(fdt, mem_off, "linux,usable-memory", + mem_array, sizeof(mem_array)); + if (err) { + pr_err("Unable to set linux,usable-memory property: %d\n", err); + return err; + } + + return 0; +} + static int remove_gic(void *fdt) { const unsigned int cpu_ehci_int = 2; @@ -205,6 +272,10 @@ void __init *sead3_dt_shim(void *fdt) if (err) panic("Unable to open FDT: %d", err); + err = append_memory(fdt_buf); + if (err) + panic("Unable to patch FDT: %d", err); + err = remove_gic(fdt_buf); if (err) panic("Unable to patch FDT: %d", err); diff --git a/arch/mips/mti-sead3/sead3-setup.c b/arch/mips/mti-sead3/sead3-setup.c index c4fc0c6d26543..c915e54f10ace 100644 --- a/arch/mips/mti-sead3/sead3-setup.c +++ b/arch/mips/mti-sead3/sead3-setup.c @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -21,68 +20,6 @@ const char *get_system_type(void) return "MIPS SEAD3"; } -static uint32_t get_memsize_from_cmdline(void) -{ - int memsize = 0; - char *p = arcs_cmdline; - char *s = "memsize="; - - p = strstr(p, s); - if (p) { - p += strlen(s); - memsize = memparse(p, NULL); - } - - return memsize; -} - -static uint32_t get_memsize_from_env(void) -{ - int memsize = 0; - char *p; - - p = fw_getenv("memsize"); - if (p) - memsize = memparse(p, NULL); - - return memsize; -} - -static uint32_t get_memsize(void) -{ - uint32_t memsize; - - memsize = get_memsize_from_cmdline(); - if (memsize) - return memsize; - - return get_memsize_from_env(); -} - -static void __init parse_memsize_param(void) -{ - int offset; - const uint64_t *prop_value; - int prop_len; - uint32_t memsize = get_memsize(); - - if (!memsize) - return; - - offset = fdt_path_offset(__dtb_start, "/memory"); - if (offset > 0) { - uint64_t new_value; - /* - * reg contains 2 32-bits BE values, offset and size. We just - * want to replace the size value without affecting the offset - */ - prop_value = fdt_getprop(__dtb_start, offset, "reg", &prop_len); - new_value = be64_to_cpu(*prop_value); - new_value = (new_value & ~0xffffffffllu) | memsize; - fdt_setprop_inplace_u64(__dtb_start, offset, "reg", new_value); - } -} - void __init *plat_get_fdt(void) { return (void *)__dtb_start; @@ -92,9 +29,6 @@ void __init plat_mem_setup(void) { void *fdt = plat_get_fdt(); - /* allow command line/bootloader env to override memory size in DT */ - parse_memsize_param(); - fdt = sead3_dt_shim(fdt); __dt_setup_arch(fdt); } -- GitLab From 93c76b6b2faaad7bfbc0cda840763aa4819ef26e Mon Sep 17 00:00:00 2001 From: zijun_hu Date: Wed, 5 Oct 2016 21:19:11 +0800 Subject: [PATCH 0289/1167] mm/percpu.c: correct max_distance calculation for pcpu_embed_first_chunk() pcpu_embed_first_chunk() calculates the range a percpu chunk spans into @max_distance and uses it to ensure that a chunk is not too big compared to the total vmalloc area. However, during calculation, it used incorrect top address by adding a unit size to the highest group's base address. This can make the calculated max_distance slightly smaller than the actual distance although given the scale of values involved the error is very unlikely to have an actual impact. Fix this issue by adding the group's size instead of a unit size. BTW, The type of variable max_distance is changed from size_t to unsigned long too based on below consideration: - type unsigned long usually have same width with IP core registers and can be applied at here very well - make @max_distance type consistent with the operand calculated against it such as @ai->groups[i].base_offset and macro VMALLOC_TOTAL - type unsigned long is more universal then size_t, size_t is type defined to unsigned int or unsigned long among various ARCHs usually Signed-off-by: zijun_hu Signed-off-by: Tejun Heo --- mm/percpu.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mm/percpu.c b/mm/percpu.c index 9903830aaebbf..e2737e56b0173 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1961,7 +1961,8 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, void *base = (void *)ULONG_MAX; void **areas = NULL; struct pcpu_alloc_info *ai; - size_t size_sum, areas_size, max_distance; + size_t size_sum, areas_size; + unsigned long max_distance; int group, i, rc; ai = pcpu_build_alloc_info(reserved_size, dyn_size, atom_size, @@ -2023,17 +2024,18 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, } /* base address is now known, determine group base offsets */ - max_distance = 0; + i = 0; for (group = 0; group < ai->nr_groups; group++) { ai->groups[group].base_offset = areas[group] - base; - max_distance = max_t(size_t, max_distance, - ai->groups[group].base_offset); + if (areas[group] > areas[i]) + i = group; } - max_distance += ai->unit_size; + max_distance = ai->groups[i].base_offset + + ai->unit_size * ai->groups[i].nr_units; /* warn if maximum distance is further than 75% of vmalloc space */ if (max_distance > VMALLOC_TOTAL * 3 / 4) { - pr_warn("max_distance=0x%zx too large for vmalloc space 0x%lx\n", + pr_warn("max_distance=0x%lx too large for vmalloc space 0x%lx\n", max_distance, VMALLOC_TOTAL); #ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK /* and fail if we have fallback */ -- GitLab From 9b7396624a7b503220d85428654634b60762f2b0 Mon Sep 17 00:00:00 2001 From: zijun_hu Date: Wed, 5 Oct 2016 21:30:24 +0800 Subject: [PATCH 0290/1167] mm/percpu.c: fix potential memory leakage for pcpu_embed_first_chunk() in order to ensure the percpu group areas within a chunk aren't distributed too sparsely, pcpu_embed_first_chunk() goes to error handling path when a chunk spans over 3/4 VMALLOC area, however, during the error handling, it forget to free the memory allocated for all percpu groups by going to label @out_free other than @out_free_areas. it will cause memory leakage issue if the rare scene really happens, in order to fix the issue, we check chunk spanned area immediately after completing memory allocation for all percpu groups, we go to label @out_free_areas to free the memory then return if the checking is failed. in order to verify the approach, we dump all memory allocated then enforce the jump then dump all memory freed, the result is okay after checking whether we free all memory we allocate in this function. BTW, The approach is chosen after thinking over the below scenes - we don't go to label @out_free directly to fix this issue since we maybe free several allocated memory blocks twice - the aim of jumping after pcpu_setup_first_chunk() is bypassing free usable memory other than handling error, moreover, the function does not return error code in any case, it either panics due to BUG_ON() or return 0. Signed-off-by: zijun_hu Tested-by: zijun_hu Signed-off-by: Tejun Heo --- mm/percpu.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/mm/percpu.c b/mm/percpu.c index e2737e56b0173..2557143023941 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1963,7 +1963,7 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, struct pcpu_alloc_info *ai; size_t size_sum, areas_size; unsigned long max_distance; - int group, i, rc; + int group, i, highest_group, rc; ai = pcpu_build_alloc_info(reserved_size, dyn_size, atom_size, cpu_distance_fn); @@ -1979,7 +1979,8 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, goto out_free; } - /* allocate, copy and determine base address */ + /* allocate, copy and determine base address & max_distance */ + highest_group = 0; for (group = 0; group < ai->nr_groups; group++) { struct pcpu_group_info *gi = &ai->groups[group]; unsigned int cpu = NR_CPUS; @@ -2000,6 +2001,21 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, areas[group] = ptr; base = min(ptr, base); + if (ptr > areas[highest_group]) + highest_group = group; + } + max_distance = areas[highest_group] - base; + max_distance += ai->unit_size * ai->groups[highest_group].nr_units; + + /* warn if maximum distance is further than 75% of vmalloc space */ + if (max_distance > VMALLOC_TOTAL * 3 / 4) { + pr_warn("max_distance=0x%lx too large for vmalloc space 0x%lx\n", + max_distance, VMALLOC_TOTAL); +#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK + /* and fail if we have fallback */ + rc = -EINVAL; + goto out_free_areas; +#endif } /* @@ -2024,24 +2040,8 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, } /* base address is now known, determine group base offsets */ - i = 0; for (group = 0; group < ai->nr_groups; group++) { ai->groups[group].base_offset = areas[group] - base; - if (areas[group] > areas[i]) - i = group; - } - max_distance = ai->groups[i].base_offset + - ai->unit_size * ai->groups[i].nr_units; - - /* warn if maximum distance is further than 75% of vmalloc space */ - if (max_distance > VMALLOC_TOTAL * 3 / 4) { - pr_warn("max_distance=0x%lx too large for vmalloc space 0x%lx\n", - max_distance, VMALLOC_TOTAL); -#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK - /* and fail if we have fallback */ - rc = -EINVAL; - goto out_free; -#endif } pr_info("Embedded %zu pages/cpu @%p s%zu r%zu d%zu u%zu\n", -- GitLab From f38b7c2547537a8219d273e20eb3b88e6fc6b764 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 28 Sep 2016 14:38:36 +0000 Subject: [PATCH 0291/1167] wlcore: sdio: drop kfree for memory allocated with devm_kzalloc It's not necessary to free memory allocated with devm_kzalloc and using kfree leads to a double free. Fixes: d776fc86b82f ("wlcore: sdio: Populate config firmware data") Signed-off-by: Wei Yongjun Acked-by: Tony Lindgren Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/sdio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index a6e94b1a12cb3..47fe7f96a2427 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -391,7 +391,6 @@ static void wl1271_remove(struct sdio_func *func) pm_runtime_get_noresume(&func->dev); platform_device_unregister(glue->core); - kfree(glue); } #ifdef CONFIG_PM -- GitLab From 2ae342e64d987866cf44cded90891ffde89a93a9 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 6 Oct 2016 20:48:21 +1100 Subject: [PATCH 0292/1167] selftests/powerpc: Add missing binaries to .gitignores Some of the recent new selftests were missing additions to .gitignore, add them now. Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/math/.gitignore | 1 + tools/testing/selftests/powerpc/signal/.gitignore | 2 ++ tools/testing/selftests/powerpc/tm/.gitignore | 4 ++++ 3 files changed, 7 insertions(+) create mode 100644 tools/testing/selftests/powerpc/signal/.gitignore diff --git a/tools/testing/selftests/powerpc/math/.gitignore b/tools/testing/selftests/powerpc/math/.gitignore index 4fe13a439fd7f..50ded63e25b71 100644 --- a/tools/testing/selftests/powerpc/math/.gitignore +++ b/tools/testing/selftests/powerpc/math/.gitignore @@ -4,3 +4,4 @@ fpu_preempt vmx_preempt fpu_signal vmx_signal +vsx_preempt diff --git a/tools/testing/selftests/powerpc/signal/.gitignore b/tools/testing/selftests/powerpc/signal/.gitignore new file mode 100644 index 0000000000000..1b89224a8aab0 --- /dev/null +++ b/tools/testing/selftests/powerpc/signal/.gitignore @@ -0,0 +1,2 @@ +signal +signal_tm diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 82c0a9ce6e748..427621792229e 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore @@ -7,3 +7,7 @@ tm-fork tm-tar tm-tmspr tm-exec +tm-signal-context-chk-fpu +tm-signal-context-chk-gpr +tm-signal-context-chk-vmx +tm-signal-context-chk-vsx -- GitLab From 56a5b8da29fb72816b8b6b0ae97985ac28d09c79 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 13 Sep 2016 14:48:38 -0700 Subject: [PATCH 0293/1167] MAINTAINERS: Remove myself from PA Semi entries The platform is old, very few users and I lack bandwidth to keep after it these days. Mark the base platform as well as the drivers as orphans, patches have been flowing through the fallback maintainers for a while already. Signed-off-by: Olof Johansson Acked-by: Wolfram Sang Signed-off-by: Michael Ellerman --- MAINTAINERS | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index df0e29b88c789..10644088baa59 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7109,9 +7109,8 @@ F: arch/powerpc/platforms/83xx/ F: arch/powerpc/platforms/85xx/ LINUX FOR POWERPC PA SEMI PWRFICIENT -M: Olof Johansson L: linuxppc-dev@lists.ozlabs.org -S: Maintained +S: Orphan F: arch/powerpc/platforms/pasemi/ F: drivers/*/*pasemi* F: drivers/*/*/*pasemi* @@ -8784,15 +8783,13 @@ S: Maintained F: drivers/net/wireless/intersil/p54/ PA SEMI ETHERNET DRIVER -M: Olof Johansson L: netdev@vger.kernel.org -S: Maintained +S: Orphan F: drivers/net/ethernet/pasemi/* PA SEMI SMBUS DRIVER -M: Olof Johansson L: linux-i2c@vger.kernel.org -S: Maintained +S: Orphan F: drivers/i2c/busses/i2c-pasemi.c PADATA PARALLEL EXECUTION MECHANISM -- GitLab From 55099115ca523b5edf5c542bd5c3287d924812f3 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 5 Oct 2016 16:04:00 +1100 Subject: [PATCH 0294/1167] MAINTAINERS: Drop separate pseries entry Paul is no longer acting as a separate maintainer for pseries, it is handled along with the rest of powerpc. The URL no longer links anywhere meaningful, so drop it also. Signed-off-by: Michael Ellerman Acked-by: Paul Mackerras --- MAINTAINERS | 6 ------ 1 file changed, 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 10644088baa59..12835fbfa3ea7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7028,12 +7028,6 @@ F: drivers/lightnvm/ F: include/linux/lightnvm.h F: include/uapi/linux/lightnvm.h -LINUX FOR IBM pSERIES (RS/6000) -M: Paul Mackerras -W: http://www.ibm.com/linux/ltc/projects/ppc -S: Supported -F: arch/powerpc/boot/rs6000.h - LINUX FOR POWERPC (32-BIT AND 64-BIT) M: Benjamin Herrenschmidt M: Paul Mackerras -- GitLab From ad654f25a12d1cbac890d33b7bcc87f625e9eb39 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 5 Oct 2016 16:08:16 +1100 Subject: [PATCH 0295/1167] MAINTAINERS: Update powerpc website & add selftests The selftests under tools/testing/selftests/powerpc are maintained by us, so add a file pattern for them. Also drop the www.penguinppc.org link, it's not dead, but the site is dead (database error). Instead link to the wiki attached to our github, there is some info there which may be useful, which is better than none. Signed-off-by: Michael Ellerman --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 12835fbfa3ea7..23aae83c434e7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7032,7 +7032,7 @@ LINUX FOR POWERPC (32-BIT AND 64-BIT) M: Benjamin Herrenschmidt M: Paul Mackerras M: Michael Ellerman -W: http://www.penguinppc.org/ +W: https://github.com/linuxppc/linux/wiki L: linuxppc-dev@lists.ozlabs.org Q: http://patchwork.ozlabs.org/project/linuxppc-dev/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git @@ -7047,6 +7047,7 @@ F: drivers/net/ethernet/ibm/ibmvnic.* F: drivers/pci/hotplug/pnv_php.c F: drivers/pci/hotplug/rpa* F: drivers/scsi/ibmvscsi/ +F: tools/testing/selftests/powerpc N: opal N: /pmac N: powermac -- GitLab From 8321564a11bbeadffcc7d6335bcf3c07e5c397a3 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 5 Oct 2016 16:15:14 +1100 Subject: [PATCH 0296/1167] selftests/powerpc: Fix build break caused by EXPORT_SYMBOL changes The changes to make EXPORT_SYMBOL work in asm, specifically commit 9445aa1a3062 ("ppc: move exports to definitions"), in the kbuild tree, breaks some of our selftests. That is because we symlink the kernel code into the selftest, and shim the required headers, and we are now missing asm/export.h So create a minimal export.h to keep the tests building once powerpc and the kbuild trees are merged. Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/copyloops/asm/export.h | 1 + tools/testing/selftests/powerpc/stringloops/asm/export.h | 1 + 2 files changed, 2 insertions(+) create mode 100644 tools/testing/selftests/powerpc/copyloops/asm/export.h create mode 100644 tools/testing/selftests/powerpc/stringloops/asm/export.h diff --git a/tools/testing/selftests/powerpc/copyloops/asm/export.h b/tools/testing/selftests/powerpc/copyloops/asm/export.h new file mode 100644 index 0000000000000..2d14a9b4248c7 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/asm/export.h @@ -0,0 +1 @@ +#define EXPORT_SYMBOL(x) diff --git a/tools/testing/selftests/powerpc/stringloops/asm/export.h b/tools/testing/selftests/powerpc/stringloops/asm/export.h new file mode 100644 index 0000000000000..2d14a9b4248c7 --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/asm/export.h @@ -0,0 +1 @@ +#define EXPORT_SYMBOL(x) -- GitLab From ec5218a23c470aad28be13362d11fd7886445866 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:46 +0100 Subject: [PATCH 0297/1167] MIPS: SEAD3: Drop use of cobalt fbdev driver The 2 line * 16 character LCD display on the SEAD3 board has no real use as a framebuffer device. It's far too small to produce any meaningful output if used as the kernel console, SEAD3 is a development board that will essentially always have a far more useful UART connection & the code in sead3-display.c will overwrite whatever's on the display every second anyway. Remove this unused code. Signed-off-by: Paul Burton Cc: Jacek Anaszewski Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14059/ Signed-off-by: Ralf Baechle --- arch/mips/mti-sead3/Makefile | 3 +-- arch/mips/mti-sead3/sead3-lcd.c | 43 --------------------------------- 2 files changed, 1 insertion(+), 45 deletions(-) delete mode 100644 arch/mips/mti-sead3/sead3-lcd.c diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile index ad722c857c613..cb6d620a685cf 100644 --- a/arch/mips/mti-sead3/Makefile +++ b/arch/mips/mti-sead3/Makefile @@ -8,8 +8,7 @@ # Copyright (C) 2012 MIPS Technoligies, Inc. All rights reserved. # Steven J. Hill # -obj-y := sead3-lcd.o -obj-y += sead3-display.o +obj-y := sead3-display.o obj-y += sead3-dtshim.o obj-y += sead3-init.o obj-y += sead3-int.o diff --git a/arch/mips/mti-sead3/sead3-lcd.c b/arch/mips/mti-sead3/sead3-lcd.c deleted file mode 100644 index 10b10ed21f775..0000000000000 --- a/arch/mips/mti-sead3/sead3-lcd.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include -#include - -static struct resource __initdata sead3_lcd_resource = { - .start = 0x1f000400, - .end = 0x1f00041f, - .flags = IORESOURCE_MEM, -}; - -static __init int sead3_lcd_add(void) -{ - struct platform_device *pdev; - int retval; - - /* SEAD-3 and Cobalt platforms use same display type. */ - pdev = platform_device_alloc("cobalt-lcd", -1); - if (!pdev) - return -ENOMEM; - - retval = platform_device_add_resources(pdev, &sead3_lcd_resource, 1); - if (retval) - goto err_free_device; - - retval = platform_device_add(pdev); - if (retval) - goto err_free_device; - - return 0; - -err_free_device: - platform_device_put(pdev); - - return retval; -} - -device_initcall(sead3_lcd_add); -- GitLab From eb42d760db2ea8ab16f10e320a7a8bfff331307f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:47 +0100 Subject: [PATCH 0298/1167] FBDEV: cobalt_lcdfb: Drop SEAD3 support The SEAD3 board no longer uses the cobalt_lcdfb driver, so remove the SEAD3-specific code from it. Signed-off-by: Paul Burton Acked-by: Tomi Valkeinen Cc: Ondrej Zary Cc: Arnd Bergmann Cc: Robert Jarzmik Cc: Maciej W. Rozycki Cc: Ezequiel Garcia Cc: Tomi Valkeinen Cc: Jean-Christophe Plagniol-Villard Cc: Geert Uytterhoeven Cc: Simon Horman Cc: linux-mips@linux-mips.org Cc: linux-fbdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14060/ Signed-off-by: Ralf Baechle --- drivers/video/fbdev/Kconfig | 2 +- drivers/video/fbdev/cobalt_lcdfb.c | 42 ------------------------------ 2 files changed, 1 insertion(+), 43 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 88b008fb8a4ec..914bfb2f176bd 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -2183,7 +2183,7 @@ config FB_GOLDFISH config FB_COBALT tristate "Cobalt server LCD frame buffer support" - depends on FB && (MIPS_COBALT || MIPS_SEAD3) + depends on FB && MIPS_COBALT config FB_SH7760 bool "SH7760/SH7763/SH7720/SH7721 LCDC support" diff --git a/drivers/video/fbdev/cobalt_lcdfb.c b/drivers/video/fbdev/cobalt_lcdfb.c index 07675d6f323e7..2d3b691f3fc48 100644 --- a/drivers/video/fbdev/cobalt_lcdfb.c +++ b/drivers/video/fbdev/cobalt_lcdfb.c @@ -63,7 +63,6 @@ #define LCD_CUR_POS(x) ((x) & LCD_CUR_POS_MASK) #define LCD_TEXT_POS(x) ((x) | LCD_TEXT_MODE) -#ifdef CONFIG_MIPS_COBALT static inline void lcd_write_control(struct fb_info *info, u8 control) { writel((u32)control << 24, info->screen_base); @@ -83,47 +82,6 @@ static inline u8 lcd_read_data(struct fb_info *info) { return readl(info->screen_base + LCD_DATA_REG_OFFSET) >> 24; } -#else - -#define LCD_CTL 0x00 -#define LCD_DATA 0x08 -#define CPLD_STATUS 0x10 -#define CPLD_DATA 0x18 - -static inline void cpld_wait(struct fb_info *info) -{ - do { - } while (readl(info->screen_base + CPLD_STATUS) & 1); -} - -static inline void lcd_write_control(struct fb_info *info, u8 control) -{ - cpld_wait(info); - writel(control, info->screen_base + LCD_CTL); -} - -static inline u8 lcd_read_control(struct fb_info *info) -{ - cpld_wait(info); - readl(info->screen_base + LCD_CTL); - cpld_wait(info); - return readl(info->screen_base + CPLD_DATA) & 0xff; -} - -static inline void lcd_write_data(struct fb_info *info, u8 data) -{ - cpld_wait(info); - writel(data, info->screen_base + LCD_DATA); -} - -static inline u8 lcd_read_data(struct fb_info *info) -{ - cpld_wait(info); - readl(info->screen_base + LCD_DATA); - cpld_wait(info); - return readl(info->screen_base + CPLD_DATA) & 0xff; -} -#endif static int lcd_busy_wait(struct fb_info *info) { -- GitLab From 8ef3ff2723f8cbaec4fee3c7fa807bf8d6ccd2e5 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:48 +0100 Subject: [PATCH 0299/1167] dt-bindings: img-ascii-lcd: Document a binding for simple ASCII LCDs Add documentation for a devicetree binding for the simple ASCII LCD displays found on development boards such as the MIPS Boston, MIPS Malta & MIPS SEAD3 from Imagination Technologies. Signed-off-by: Paul Burton Acked-by: Rob Herring Cc: Mauro Carvalho Chehab Cc: Guenter Roeck Cc: David S. Miller Cc: Greg Kroah-Hartman Cc: Geert Uytterhoeven Cc: Mark Rutland Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14061/ Signed-off-by: Ralf Baechle --- .../bindings/auxdisplay/img-ascii-lcd.txt | 17 +++++++++++++++++ MAINTAINERS | 5 +++++ 2 files changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/auxdisplay/img-ascii-lcd.txt diff --git a/Documentation/devicetree/bindings/auxdisplay/img-ascii-lcd.txt b/Documentation/devicetree/bindings/auxdisplay/img-ascii-lcd.txt new file mode 100644 index 0000000000000..b69bb68992fdf --- /dev/null +++ b/Documentation/devicetree/bindings/auxdisplay/img-ascii-lcd.txt @@ -0,0 +1,17 @@ +Binding for ASCII LCD displays on Imagination Technologies boards + +Required properties: +- compatible : should be one of: + "img,boston-lcd" + "mti,malta-lcd" + "mti,sead3-lcd" + +Required properties for "img,boston-lcd": +- reg : memory region locating the device registers + +Required properties for "mti,malta-lcd" or "mti,sead3-lcd": +- regmap: phandle of the system controller containing the LCD registers +- offset: offset in bytes to the LCD registers within the system controller + +The layout of the registers & properties of the display are determined +from the compatible string, making this binding somewhat trivial. diff --git a/MAINTAINERS b/MAINTAINERS index f593300e310b8..7b24f9f30f47f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5964,6 +5964,11 @@ M: Stanislaw Gruszka S: Maintained F: drivers/usb/atm/ueagle-atm.c +IMGTEC ASCII LCD DRIVER +M: Paul Burton +S: Maintained +F: Documentation/devicetree/bindings/auxdisplay/img-ascii-lcd.txt + INA209 HARDWARE MONITOR DRIVER M: Guenter Roeck L: linux-hwmon@vger.kernel.org -- GitLab From 0cad855fbd083ee5fd0584a47c2aaa7dca936fd4 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:49 +0100 Subject: [PATCH 0300/1167] auxdisplay: img-ascii-lcd: driver for simple ASCII LCD displays Add a driver for simple ASCII LCD displays found on the MIPS Boston, Malta & SEAD3 development boards. The Boston display is an independent memory mapped device with a simple memory mapped 8 byte register space containing the 8 ASCII characters to display. The Malta display is exposed as part of the Malta board registers, and provides 8 registers each of which corresponds to one of the ASCII characters to display. The SEAD3 display is slightly more complex, exposing an interface to an S6A0069 LCD controller via registers provided by the boards CPLD. However although the displays differ in their register interface, we require similar functionality on each board so abstracting away the differences within a single driver allows us to share a significant amount of code & ensure consistent behaviour. The driver displays the Linux kernel version as the default message, but allows the message to be changed via a character device. Messages longer then the number of characters that the display can show will scroll. This provides different behaviour to the existing LCD display code for the MIPS Malta or MIPS SEAD3 platforms in the following ways: - The default string to display is not "LINUX ON MALTA" or "LINUX ON SEAD3" but "Linux" followed by the version number of the kernel (UTS_RELEASE). - Since that string tends to be significantly longer it scrolls twice as fast, moving every 500ms rather than every 1s. - The LCD won't be updated until the driver is probed, so it doesn't provide the early "LINUX" string. Signed-off-by: Paul Burton Cc: Mauro Carvalho Chehab Cc: Miguel Ojeda Sandonis Cc: Guenter Roeck Cc: David S. Miller Cc: Greg Kroah-Hartman Cc: Geert Uytterhoeven Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14062/ Signed-off-by: Ralf Baechle --- MAINTAINERS | 1 + drivers/auxdisplay/Kconfig | 9 + drivers/auxdisplay/Makefile | 1 + drivers/auxdisplay/img-ascii-lcd.c | 443 +++++++++++++++++++++++++++++ 4 files changed, 454 insertions(+) create mode 100644 drivers/auxdisplay/img-ascii-lcd.c diff --git a/MAINTAINERS b/MAINTAINERS index 7b24f9f30f47f..1f1790031dbcd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5968,6 +5968,7 @@ IMGTEC ASCII LCD DRIVER M: Paul Burton S: Maintained F: Documentation/devicetree/bindings/auxdisplay/img-ascii-lcd.txt +F: drivers/auxdisplay/img-ascii-lcd.c INA209 HARDWARE MONITOR DRIVER M: Guenter Roeck diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index c07e725ea93db..10e1b9eee10ea 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -119,4 +119,13 @@ config CFAG12864B_RATE If you compile this as a module, you can still override this value using the module parameters. +config IMG_ASCII_LCD + tristate "Imagination Technologies ASCII LCD Display" + default y if MIPS_MALTA || MIPS_SEAD3 + select SYSCON + help + Enable this to support the simple ASCII LCD displays found on + development boards such as the MIPS Boston, MIPS Malta & MIPS SEAD3 + from Imagination Technologies. + endif # AUXDISPLAY diff --git a/drivers/auxdisplay/Makefile b/drivers/auxdisplay/Makefile index 8a8936a468b9f..3127175c89df5 100644 --- a/drivers/auxdisplay/Makefile +++ b/drivers/auxdisplay/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_KS0108) += ks0108.o obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o +obj-$(CONFIG_IMG_ASCII_LCD) += img-ascii-lcd.o diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c new file mode 100644 index 0000000000000..bf43b5d2aafca --- /dev/null +++ b/drivers/auxdisplay/img-ascii-lcd.c @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct img_ascii_lcd_ctx; + +/** + * struct img_ascii_lcd_config - Configuration information about an LCD model + * @num_chars: the number of characters the LCD can display + * @external_regmap: true if registers are in a system controller, else false + * @update: function called to update the LCD + */ +struct img_ascii_lcd_config { + unsigned int num_chars; + bool external_regmap; + void (*update)(struct img_ascii_lcd_ctx *ctx); +}; + +/** + * struct img_ascii_lcd_ctx - Private data structure + * @pdev: the ASCII LCD platform device + * @base: the base address of the LCD registers + * @regmap: the regmap through which LCD registers are accessed + * @offset: the offset within regmap to the start of the LCD registers + * @cfg: pointer to the LCD model configuration + * @message: the full message to display or scroll on the LCD + * @message_len: the length of the @message string + * @scroll_pos: index of the first character of @message currently displayed + * @scroll_rate: scroll interval in jiffies + * @timer: timer used to implement scrolling + * @curr: the string currently displayed on the LCD + */ +struct img_ascii_lcd_ctx { + struct platform_device *pdev; + union { + void __iomem *base; + struct regmap *regmap; + }; + u32 offset; + const struct img_ascii_lcd_config *cfg; + char *message; + unsigned int message_len; + unsigned int scroll_pos; + unsigned int scroll_rate; + struct timer_list timer; + char curr[] __aligned(8); +}; + +/* + * MIPS Boston development board + */ + +static void boston_update(struct img_ascii_lcd_ctx *ctx) +{ + ulong val; + +#if BITS_PER_LONG == 64 + val = *((u64 *)&ctx->curr[0]); + __raw_writeq(val, ctx->base); +#elif BITS_PER_LONG == 32 + val = *((u32 *)&ctx->curr[0]); + __raw_writel(val, ctx->base); + val = *((u32 *)&ctx->curr[4]); + __raw_writel(val, ctx->base + 4); +#else +# error Not 32 or 64 bit +#endif +} + +static struct img_ascii_lcd_config boston_config = { + .num_chars = 8, + .update = boston_update, +}; + +/* + * MIPS Malta development board + */ + +static void malta_update(struct img_ascii_lcd_ctx *ctx) +{ + unsigned int i; + int err; + + for (i = 0; i < ctx->cfg->num_chars; i++) { + err = regmap_write(ctx->regmap, + ctx->offset + (i * 8), ctx->curr[i]); + if (err) + break; + } + + if (unlikely(err)) + pr_err_ratelimited("Failed to update LCD display: %d\n", err); +} + +static struct img_ascii_lcd_config malta_config = { + .num_chars = 8, + .external_regmap = true, + .update = malta_update, +}; + +/* + * MIPS SEAD3 development board + */ + +enum { + SEAD3_REG_LCD_CTRL = 0x00, +#define SEAD3_REG_LCD_CTRL_SETDRAM BIT(7) + SEAD3_REG_LCD_DATA = 0x08, + SEAD3_REG_CPLD_STATUS = 0x10, +#define SEAD3_REG_CPLD_STATUS_BUSY BIT(0) + SEAD3_REG_CPLD_DATA = 0x18, +#define SEAD3_REG_CPLD_DATA_BUSY BIT(7) +}; + +static int sead3_wait_sm_idle(struct img_ascii_lcd_ctx *ctx) +{ + unsigned int status; + int err; + + do { + err = regmap_read(ctx->regmap, + ctx->offset + SEAD3_REG_CPLD_STATUS, + &status); + if (err) + return err; + } while (status & SEAD3_REG_CPLD_STATUS_BUSY); + + return 0; + +} + +static int sead3_wait_lcd_idle(struct img_ascii_lcd_ctx *ctx) +{ + unsigned int cpld_data; + int err; + + err = sead3_wait_sm_idle(ctx); + if (err) + return err; + + do { + err = regmap_read(ctx->regmap, + ctx->offset + SEAD3_REG_LCD_CTRL, + &cpld_data); + if (err) + return err; + + err = sead3_wait_sm_idle(ctx); + if (err) + return err; + + err = regmap_read(ctx->regmap, + ctx->offset + SEAD3_REG_CPLD_DATA, + &cpld_data); + if (err) + return err; + } while (cpld_data & SEAD3_REG_CPLD_DATA_BUSY); + + return 0; +} + +static void sead3_update(struct img_ascii_lcd_ctx *ctx) +{ + unsigned int i; + int err; + + for (i = 0; i < ctx->cfg->num_chars; i++) { + err = sead3_wait_lcd_idle(ctx); + if (err) + break; + + err = regmap_write(ctx->regmap, + ctx->offset + SEAD3_REG_LCD_CTRL, + SEAD3_REG_LCD_CTRL_SETDRAM | i); + if (err) + break; + + err = sead3_wait_lcd_idle(ctx); + if (err) + break; + + err = regmap_write(ctx->regmap, + ctx->offset + SEAD3_REG_LCD_DATA, + ctx->curr[i]); + if (err) + break; + } + + if (unlikely(err)) + pr_err_ratelimited("Failed to update LCD display: %d\n", err); +} + +static struct img_ascii_lcd_config sead3_config = { + .num_chars = 16, + .external_regmap = true, + .update = sead3_update, +}; + +static const struct of_device_id img_ascii_lcd_matches[] = { + { .compatible = "img,boston-lcd", .data = &boston_config }, + { .compatible = "mti,malta-lcd", .data = &malta_config }, + { .compatible = "mti,sead3-lcd", .data = &sead3_config }, +}; + +/** + * img_ascii_lcd_scroll() - scroll the display by a character + * @arg: really a pointer to the private data structure + * + * Scroll the current message along the LCD by one character, rearming the + * timer if required. + */ +static void img_ascii_lcd_scroll(unsigned long arg) +{ + struct img_ascii_lcd_ctx *ctx = (struct img_ascii_lcd_ctx *)arg; + unsigned int i, ch = ctx->scroll_pos; + unsigned int num_chars = ctx->cfg->num_chars; + + /* update the current message string */ + for (i = 0; i < num_chars;) { + /* copy as many characters from the string as possible */ + for (; i < num_chars && ch < ctx->message_len; i++, ch++) + ctx->curr[i] = ctx->message[ch]; + + /* wrap around to the start of the string */ + ch = 0; + } + + /* update the LCD */ + ctx->cfg->update(ctx); + + /* move on to the next character */ + ctx->scroll_pos++; + ctx->scroll_pos %= ctx->message_len; + + /* rearm the timer */ + if (ctx->message_len > ctx->cfg->num_chars) + mod_timer(&ctx->timer, jiffies + ctx->scroll_rate); +} + +/** + * img_ascii_lcd_display() - set the message to be displayed + * @ctx: pointer to the private data structure + * @msg: the message to display + * @count: length of msg, or -1 + * + * Display a new message @msg on the LCD. @msg can be longer than the number of + * characters the LCD can display, in which case it will begin scrolling across + * the LCD display. + * + * Return: 0 on success, -ENOMEM on memory allocation failure + */ +static int img_ascii_lcd_display(struct img_ascii_lcd_ctx *ctx, + const char *msg, ssize_t count) +{ + char *new_msg; + + /* stop the scroll timer */ + del_timer_sync(&ctx->timer); + + if (count == -1) + count = strlen(msg); + + /* if the string ends with a newline, trim it */ + if (msg[count - 1] == '\n') + count--; + + new_msg = devm_kmalloc(&ctx->pdev->dev, count + 1, GFP_KERNEL); + if (!new_msg) + return -ENOMEM; + + memcpy(new_msg, msg, count); + new_msg[count] = 0; + + if (ctx->message) + devm_kfree(&ctx->pdev->dev, ctx->message); + + ctx->message = new_msg; + ctx->message_len = count; + ctx->scroll_pos = 0; + + /* update the LCD */ + img_ascii_lcd_scroll((unsigned long)ctx); + + return 0; +} + +/** + * message_show() - read message via sysfs + * @dev: the LCD device + * @attr: the LCD message attribute + * @buf: the buffer to read the message into + * + * Read the current message being displayed or scrolled across the LCD display + * into @buf, for reads from sysfs. + * + * Return: the number of characters written to @buf + */ +static ssize_t message_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct img_ascii_lcd_ctx *ctx = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", ctx->message); +} + +/** + * message_store() - write a new message via sysfs + * @dev: the LCD device + * @attr: the LCD message attribute + * @buf: the buffer containing the new message + * @count: the size of the message in @buf + * + * Write a new message to display or scroll across the LCD display from sysfs. + * + * Return: the size of the message on success, else -ERRNO + */ +static ssize_t message_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct img_ascii_lcd_ctx *ctx = dev_get_drvdata(dev); + int err; + + err = img_ascii_lcd_display(ctx, buf, count); + return err ?: count; +} + +static DEVICE_ATTR_RW(message); + +/** + * img_ascii_lcd_probe() - probe an LCD display device + * @pdev: the LCD platform device + * + * Probe an LCD display device, ensuring that we have the required resources in + * order to access the LCD & setting up private data as well as sysfs files. + * + * Return: 0 on success, else -ERRNO + */ +static int img_ascii_lcd_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + const struct img_ascii_lcd_config *cfg; + struct img_ascii_lcd_ctx *ctx; + struct resource *res; + int err; + + match = of_match_device(img_ascii_lcd_matches, &pdev->dev); + if (!match) + return -ENODEV; + + cfg = match->data; + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx) + cfg->num_chars, + GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (cfg->external_regmap) { + ctx->regmap = syscon_node_to_regmap(pdev->dev.parent->of_node); + if (IS_ERR(ctx->regmap)) + return PTR_ERR(ctx->regmap); + + if (of_property_read_u32(pdev->dev.of_node, "offset", + &ctx->offset)) + return -EINVAL; + } else { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ctx->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ctx->base)) + return PTR_ERR(ctx->base); + } + + ctx->pdev = pdev; + ctx->cfg = cfg; + ctx->message = NULL; + ctx->scroll_pos = 0; + ctx->scroll_rate = HZ / 2; + + /* initialise a timer for scrolling the message */ + init_timer(&ctx->timer); + ctx->timer.function = img_ascii_lcd_scroll; + ctx->timer.data = (unsigned long)ctx; + + platform_set_drvdata(pdev, ctx); + + /* display a default message */ + err = img_ascii_lcd_display(ctx, "Linux " UTS_RELEASE " ", -1); + if (err) + goto out_del_timer; + + err = device_create_file(&pdev->dev, &dev_attr_message); + if (err) + goto out_del_timer; + + return 0; +out_del_timer: + del_timer_sync(&ctx->timer); + return err; +} + +/** + * img_ascii_lcd_remove() - remove an LCD display device + * @pdev: the LCD platform device + * + * Remove an LCD display device, freeing private resources & ensuring that the + * driver stops using the LCD display registers. + * + * Return: 0 + */ +static int img_ascii_lcd_remove(struct platform_device *pdev) +{ + struct img_ascii_lcd_ctx *ctx = platform_get_drvdata(pdev); + + device_remove_file(&pdev->dev, &dev_attr_message); + del_timer_sync(&ctx->timer); + return 0; +} + +static struct platform_driver img_ascii_lcd_driver = { + .driver = { + .name = "img-ascii-lcd", + .of_match_table = img_ascii_lcd_matches, + }, + .probe = img_ascii_lcd_probe, + .remove = img_ascii_lcd_remove, +}; +module_platform_driver(img_ascii_lcd_driver); -- GitLab From 5e189564d574541c6f149ab3a1081d25eec06fd0 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:50 +0100 Subject: [PATCH 0301/1167] MIPS: SEAD3: Use img-ascii-lcd driver Probe the img-ascii-lcd driver using device tree in order to display a message on the SEAD3 board's LCD display, and remove the platform code that was formerly performing this function. This removes more platform code and moves SEAD3 further towards being entirely DT-based. Signed-off-by: Paul Burton Cc: Jacek Anaszewski Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14063/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 5 ++ arch/mips/mti-sead3/Makefile | 3 +- arch/mips/mti-sead3/sead3-display.c | 77 ----------------------------- arch/mips/mti-sead3/sead3-time.c | 2 - 4 files changed, 6 insertions(+), 81 deletions(-) delete mode 100644 arch/mips/mti-sead3/sead3-display.c diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index 32a5ab988b65b..2579ca51c0b61 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -210,6 +210,11 @@ mask = <0x80>; label = "fled7"; }; + + lcd@200 { + compatible = "mti,sead3-lcd"; + offset = <0x200>; + }; }; /* UART connected to FTDI & miniUSB socket */ diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile index cb6d620a685cf..1674b9cf75279 100644 --- a/arch/mips/mti-sead3/Makefile +++ b/arch/mips/mti-sead3/Makefile @@ -8,8 +8,7 @@ # Copyright (C) 2012 MIPS Technoligies, Inc. All rights reserved. # Steven J. Hill # -obj-y := sead3-display.o -obj-y += sead3-dtshim.o +obj-y := sead3-dtshim.o obj-y += sead3-init.o obj-y += sead3-int.o obj-y += sead3-setup.o diff --git a/arch/mips/mti-sead3/sead3-display.c b/arch/mips/mti-sead3/sead3-display.c deleted file mode 100644 index 94875991907bd..0000000000000 --- a/arch/mips/mti-sead3/sead3-display.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include -#include -#include - -static unsigned int display_count; -static unsigned int max_display_count; - -#define LCD_DISPLAY_POS_BASE 0x1f000400 -#define DISPLAY_LCDINSTRUCTION (0*2) -#define DISPLAY_LCDDATA (1*2) -#define DISPLAY_CPLDSTATUS (2*2) -#define DISPLAY_CPLDDATA (3*2) -#define LCD_SETDDRAM 0x80 -#define LCD_IR_BF 0x80 - -const char display_string[] = " LINUX ON SEAD3 "; - -static void scroll_display_message(unsigned long data); -static DEFINE_TIMER(mips_scroll_timer, scroll_display_message, HZ, 0); - -static void lcd_wait(unsigned int __iomem *display) -{ - /* Wait for CPLD state machine to become idle. */ - do { } while (__raw_readl(display + DISPLAY_CPLDSTATUS) & 1); - - do { - __raw_readl(display + DISPLAY_LCDINSTRUCTION); - - /* Wait for CPLD state machine to become idle. */ - do { } while (__raw_readl(display + DISPLAY_CPLDSTATUS) & 1); - } while (__raw_readl(display + DISPLAY_CPLDDATA) & LCD_IR_BF); -} - -void mips_display_message(const char *str) -{ - static unsigned int __iomem *display; - char ch; - int i; - - if (unlikely(display == NULL)) - display = ioremap_nocache(LCD_DISPLAY_POS_BASE, - (8 * sizeof(int))); - - for (i = 0; i < 16; i++) { - if (*str) - ch = *str++; - else - ch = ' '; - lcd_wait(display); - __raw_writel((LCD_SETDDRAM | i), - (display + DISPLAY_LCDINSTRUCTION)); - lcd_wait(display); - __raw_writel(ch, display + DISPLAY_LCDDATA); - } -} - -static void scroll_display_message(unsigned long data) -{ - mips_display_message(&display_string[display_count++]); - if (display_count == max_display_count) - display_count = 0; - mod_timer(&mips_scroll_timer, jiffies + HZ); -} - -void mips_scroll_message(void) -{ - del_timer_sync(&mips_scroll_timer); - max_display_count = strlen(display_string) + 1 - 16; - mod_timer(&mips_scroll_timer, jiffies + 1); -} diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c index a120b7a5a8fe4..10b0bf338027a 100644 --- a/arch/mips/mti-sead3/sead3-time.c +++ b/arch/mips/mti-sead3/sead3-time.c @@ -94,6 +94,4 @@ void __init plat_time_init(void) pr_debug("CPU frequency %d.%02d MHz\n", (est_freq / 1000000), (est_freq % 1000000) * 100 / 1000000); - - mips_scroll_message(); } -- GitLab From e6a54ba304b15275884b029c2234ea74c4e591d0 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 26 Aug 2016 15:17:51 +0100 Subject: [PATCH 0302/1167] MIPS: SEAD3: Remove custom read_persistent_clock The SEAD3 board defines a custom implementation of read_persistent_clock which does exactly the same dummy operation as the generic weak version. Remove the not really implemented custom version. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14064/ Signed-off-by: Ralf Baechle --- arch/mips/mti-sead3/sead3-time.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c index 10b0bf338027a..71feb51944783 100644 --- a/arch/mips/mti-sead3/sead3-time.c +++ b/arch/mips/mti-sead3/sead3-time.c @@ -63,12 +63,6 @@ static unsigned int __init estimate_cpu_frequency(void) return freq ; } -void read_persistent_clock(struct timespec *ts) -{ - ts->tv_sec = 0; - ts->tv_nsec = 0; -} - int get_c0_perfcount_int(void) { if (gic_present) -- GitLab From 690803acca14e8aa101ca5204f0a23c24d7ad8c3 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:18 +0100 Subject: [PATCH 0303/1167] irqchip: i8259: Add domain before mapping parent irq Mapping the parent IRQ will use a virq number which may conflict with the hardcoded I8259A_IRQ_BASE..I8259A_IRQ_BASE+15 range that the i8259 driver expects to be free. If this occurs then we'll hit errors when adding the i8259 IRQ domain, since one of its virq numbers will already be in use. Avoid this by adding the i8259 domain before mapping the parent IRQ, such that the i8259 virq numbers become used before the parent interrupt controller gets a chance to use any of them. Signed-off-by: Paul Burton Acked-by: Thomas Gleixner Cc: Marc Zyngier Cc: Jason Cooper Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14269/ Signed-off-by: Ralf Baechle --- drivers/irqchip/irq-i8259.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c index 6b304eb39bd22..85897fdc15273 100644 --- a/drivers/irqchip/irq-i8259.c +++ b/drivers/irqchip/irq-i8259.c @@ -370,13 +370,15 @@ int __init i8259_of_init(struct device_node *node, struct device_node *parent) struct irq_domain *domain; unsigned int parent_irq; + domain = __init_i8259_irqs(node); + parent_irq = irq_of_parse_and_map(node, 0); if (!parent_irq) { pr_err("Failed to map i8259 parent IRQ\n"); + irq_domain_remove(domain); return -ENODEV; } - domain = __init_i8259_irqs(node); irq_set_chained_handler_and_data(parent_irq, i8259_irq_dispatch, domain); return 0; -- GitLab From 19afc3d269fe66137ddb030b8ffdb8553066ba4a Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:19 +0100 Subject: [PATCH 0304/1167] irqchip: i8259: Allow platforms to override poll function The default i8259 polling function (i8259_irq) is nicely generic but is fairly costly. Platforms often provide an alternative means of polling for an i8259 interrupt, and when using the i8259 without device tree have typically just chained its parent interrupt to their own handler function. In order to allow for platform-specific polling functions to be used in cases where the driver is probed via device tree, provide an i8259_set_poll function that accepts a pointer to an alternative poll function that will override the default. Signed-off-by: Paul Burton Acked-by: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14270/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/i8259.h | 11 +++++++++++ drivers/irqchip/irq-i8259.c | 8 +++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/i8259.h b/arch/mips/include/asm/i8259.h index a7fbcd6ed13c4..b27fcc4ae4741 100644 --- a/arch/mips/include/asm/i8259.h +++ b/arch/mips/include/asm/i8259.h @@ -43,6 +43,17 @@ extern void make_8259A_irq(unsigned int irq); extern void init_i8259_irqs(void); extern int i8259_of_init(struct device_node *node, struct device_node *parent); +/** + * i8159_set_poll() - Override the i8259 polling function + * @poll: pointer to platform-specific polling function + * + * Call this to override the generic i8259 polling function, which directly + * accesses i8259 registers, with a platform specific one which may be faster + * in cases where hardware provides a more optimal means of polling for an + * interrupt. + */ +extern void i8259_set_poll(int (*poll)(void)); + /* * Do the traditional i8259 interrupt polling thing. This is for the few * cases where no better interrupt acknowledge method is available and we diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c index 85897fdc15273..1f4a3442342bb 100644 --- a/drivers/irqchip/irq-i8259.c +++ b/drivers/irqchip/irq-i8259.c @@ -38,6 +38,7 @@ static void disable_8259A_irq(struct irq_data *d); static void enable_8259A_irq(struct irq_data *d); static void mask_and_ack_8259A(struct irq_data *d); static void init_8259A(int auto_eoi); +static int (*i8259_poll)(void) = i8259_irq; static struct irq_chip i8259A_chip = { .name = "XT-PIC", @@ -51,6 +52,11 @@ static struct irq_chip i8259A_chip = { * 8259A PIC functions to handle ISA devices: */ +void i8259_set_poll(int (*poll)(void)) +{ + i8259_poll = poll; +} + /* * This contains the irq mask for both 8259A irq controllers, */ @@ -355,7 +361,7 @@ void __init init_i8259_irqs(void) static void i8259_irq_dispatch(struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); - int hwirq = i8259_irq(); + int hwirq = i8259_poll(); unsigned int irq; if (hwirq < 0) -- GitLab From 5d2949ec86a54b73a6fc2557ef784e76c0d2cba9 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:20 +0100 Subject: [PATCH 0305/1167] irqchip: i8259: Remove unused i8259A_irq_pending The i8259A_irq_pending function is unused. Remove the dead code. Signed-off-by: Paul Burton Acked-by: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14271/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/i8259.h | 1 - drivers/irqchip/irq-i8259.c | 18 ------------------ 2 files changed, 19 deletions(-) diff --git a/arch/mips/include/asm/i8259.h b/arch/mips/include/asm/i8259.h index b27fcc4ae4741..32229c77906a1 100644 --- a/arch/mips/include/asm/i8259.h +++ b/arch/mips/include/asm/i8259.h @@ -37,7 +37,6 @@ extern raw_spinlock_t i8259A_lock; -extern int i8259A_irq_pending(unsigned int irq); extern void make_8259A_irq(unsigned int irq); extern void init_i8259_irqs(void); diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c index 1f4a3442342bb..1aec12c6d9ac8 100644 --- a/drivers/irqchip/irq-i8259.c +++ b/drivers/irqchip/irq-i8259.c @@ -95,24 +95,6 @@ static void enable_8259A_irq(struct irq_data *d) raw_spin_unlock_irqrestore(&i8259A_lock, flags); } -int i8259A_irq_pending(unsigned int irq) -{ - unsigned int mask; - unsigned long flags; - int ret; - - irq -= I8259A_IRQ_BASE; - mask = 1 << irq; - raw_spin_lock_irqsave(&i8259A_lock, flags); - if (irq < 8) - ret = inb(PIC_MASTER_CMD) & mask; - else - ret = inb(PIC_SLAVE_CMD) & (mask >> 8); - raw_spin_unlock_irqrestore(&i8259A_lock, flags); - - return ret; -} - void make_8259A_irq(unsigned int irq) { disable_irq_nosync(irq); -- GitLab From 422dd256642b75808cbf447040481cac11ccbefc Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:21 +0100 Subject: [PATCH 0306/1167] MIPS: Malta: Allow PCI devices DMA to lower 2GB physical Set the PCI_BAR0 register in all configurations such that PCI devices can perform DMA to all of the bottom 2GB of the physical address space. This is imperfect if we make use of the legacy Malta memory map, but it is an improvement on the inconsistent values setup before. Signed-off-by: Paul Burton Cc: Alexander Sverdlin Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14272/ Signed-off-by: Ralf Baechle --- arch/mips/mti-malta/malta-init.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index dc2c5214809d3..0f3b881a3190f 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -242,23 +243,19 @@ void __init prom_init(void) MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_MEM_SHF | MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_BAR0_SHF); #endif -#ifndef CONFIG_EVA - /* Fix up target memory mapping. */ - MSC_READ(MSC01_PCI_BAR0, mask); - MSC_WRITE(MSC01_PCI_P2SCMSKL, mask & MSC01_PCI_BAR0_SIZE_MSK); -#else + /* * Setup the Malta max (2GB) memory for PCI DMA in host bridge - * in transparent addressing mode, starting from 0x80000000. + * in transparent addressing mode. */ - mask = PHYS_OFFSET | (1<<3); + mask = PHYS_OFFSET | PCI_BASE_ADDRESS_MEM_PREFETCH; MSC_WRITE(MSC01_PCI_BAR0, mask); - - mask = PHYS_OFFSET; MSC_WRITE(MSC01_PCI_HEAD4, mask); + + mask &= MSC01_PCI_BAR0_SIZE_MSK; MSC_WRITE(MSC01_PCI_P2SCMSKL, mask); MSC_WRITE(MSC01_PCI_P2SCMAPL, mask); -#endif + /* Don't handle target retries indefinitely. */ if ((data & MSC01_PCI_CFG_MAXRTRY_MSK) == MSC01_PCI_CFG_MAXRTRY_MSK) -- GitLab From 0051fc2e7b84500c4ecf66cda4ac0879340600ef Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:22 +0100 Subject: [PATCH 0307/1167] MIPS: Malta: Use all available DDR by default Malta boards can have more than 256MB DDR available, but we have previously only made use of up to 256MB (ie. the DDR accessible via kseg0) by default, without the user manually specifying mem= kernel parameters. This patch causes all available DDR, as reported by the bootloader via the ememsize or memsize environment variables or optionally on the command line, to be used when possible without the user needing to manually provide the memory ranges. Malta now has 2 subtly different memory maps which have to be taken into account when setting this up. The original memory map (referred to by the code as v1) has up to 2GB of DDR aliased in both the upper & lower halves of the 32 bit physical address space, with a 256MB I/O region obscuring 0x10000000-0x1fffffff only in the lower alias. The revised v2 memory map is flat with up to 4GB DDR starting from 0x0, and the I/O region obscures 256MB of DDR which becomes inacessible. The memory map in use is indicated by a register provided by the rocit2 system controller, which is checked in order to set up the kernels memory ranges accordingly. Signed-off-by: Paul Burton Cc: Masahiro Yamada Cc: Kees Cook Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14273/ Signed-off-by: Ralf Baechle --- arch/mips/mti-malta/malta-dtshim.c | 110 +++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 6 deletions(-) diff --git a/arch/mips/mti-malta/malta-dtshim.c b/arch/mips/mti-malta/malta-dtshim.c index 151f4882ec8ac..bdda3cb66668c 100644 --- a/arch/mips/mti-malta/malta-dtshim.c +++ b/arch/mips/mti-malta/malta-dtshim.c @@ -13,18 +13,64 @@ #include #include #include +#include #include #include +#include #include +#define ROCIT_REG_BASE 0x1f403000 +#define ROCIT_CONFIG_GEN1 (ROCIT_REG_BASE + 0x04) +#define ROCIT_CONFIG_GEN1_MEMMAP_SHIFT 8 +#define ROCIT_CONFIG_GEN1_MEMMAP_MASK (0xf << 8) + static unsigned char fdt_buf[16 << 10] __initdata; /* determined physical memory size, not overridden by command line args */ extern unsigned long physical_memsize; -#define MAX_MEM_ARRAY_ENTRIES 1 +enum mem_map { + MEM_MAP_V1 = 0, + MEM_MAP_V2, +}; + +#define MAX_MEM_ARRAY_ENTRIES 2 + +static __init int malta_scon(void) +{ + int scon = MIPS_REVISION_SCONID; + + if (scon != MIPS_REVISION_SCON_OTHER) + return scon; + + switch (MIPS_REVISION_CORID) { + case MIPS_REVISION_CORID_QED_RM5261: + case MIPS_REVISION_CORID_CORE_LV: + case MIPS_REVISION_CORID_CORE_FPGA: + case MIPS_REVISION_CORID_CORE_FPGAR2: + return MIPS_REVISION_SCON_GT64120; + + case MIPS_REVISION_CORID_CORE_EMUL_BON: + case MIPS_REVISION_CORID_BONITO64: + case MIPS_REVISION_CORID_CORE_20K: + return MIPS_REVISION_SCON_BONITO; + + case MIPS_REVISION_CORID_CORE_MSC: + case MIPS_REVISION_CORID_CORE_FPGA2: + case MIPS_REVISION_CORID_CORE_24K: + return MIPS_REVISION_SCON_SOCIT; + + case MIPS_REVISION_CORID_CORE_FPGA3: + case MIPS_REVISION_CORID_CORE_FPGA4: + case MIPS_REVISION_CORID_CORE_FPGA5: + case MIPS_REVISION_CORID_CORE_EMUL_MSC: + default: + return MIPS_REVISION_SCON_ROCIT; + } +} -static unsigned __init gen_fdt_mem_array(__be32 *mem_array, unsigned long size) +static unsigned __init gen_fdt_mem_array(__be32 *mem_array, unsigned long size, + enum mem_map map) { unsigned long size_preio; unsigned entries; @@ -39,11 +85,47 @@ static unsigned __init gen_fdt_mem_array(__be32 *mem_array, unsigned long size) * DDR but limits it to 2GB. */ mem_array[1] = cpu_to_be32(size); + goto done; + } + + size_preio = min_t(unsigned long, size, SZ_256M); + mem_array[1] = cpu_to_be32(size_preio); + size -= size_preio; + if (!size) + goto done; + + if (map == MEM_MAP_V2) { + /* + * We have a flat 32 bit physical memory map with DDR filling + * all 4GB of the memory map, apart from the I/O region which + * obscures 256MB from 0x10000000-0x1fffffff. + * + * Therefore we discard the 256MB behind the I/O region. + */ + if (size <= SZ_256M) + goto done; + size -= SZ_256M; + + /* Make use of the memory following the I/O region */ + entries++; + mem_array[2] = cpu_to_be32(PHYS_OFFSET + SZ_512M); + mem_array[3] = cpu_to_be32(size); } else { - size_preio = min_t(unsigned long, size, SZ_256M); - mem_array[1] = cpu_to_be32(size_preio); + /* + * We have a 32 bit physical memory map with a 2GB DDR region + * aliased in the upper & lower halves of it. The I/O region + * obscures 256MB from 0x10000000-0x1fffffff in the low alias + * but the DDR it obscures is accessible via the high alias. + * + * Simply access everything beyond the lowest 256MB of DDR using + * the high alias. + */ + entries++; + mem_array[2] = cpu_to_be32(PHYS_OFFSET + SZ_2G + SZ_256M); + mem_array[3] = cpu_to_be32(size); } +done: BUG_ON(entries > MAX_MEM_ARRAY_ENTRIES); return entries; } @@ -54,6 +136,8 @@ static void __init append_memory(void *fdt, int root_off) unsigned long memsize; unsigned mem_entries; int i, err, mem_off; + enum mem_map mem_map; + u32 config; char *var, param_name[10], *var_names[] = { "ememsize", "memsize", }; @@ -106,6 +190,20 @@ static void __init append_memory(void *fdt, int root_off) /* if the user says there's more RAM than we thought, believe them */ physical_memsize = max_t(unsigned long, physical_memsize, memsize); + /* detect the memory map in use */ + if (malta_scon() == MIPS_REVISION_SCON_ROCIT) { + /* ROCit has a register indicating the memory map in use */ + config = readl((void __iomem *)CKSEG1ADDR(ROCIT_CONFIG_GEN1)); + mem_map = config & ROCIT_CONFIG_GEN1_MEMMAP_MASK; + mem_map >>= ROCIT_CONFIG_GEN1_MEMMAP_SHIFT; + } else { + /* if not using ROCit, presume the v1 memory map */ + mem_map = MEM_MAP_V1; + } + if (mem_map > MEM_MAP_V2) + panic("Unsupported physical memory map v%u detected", + (unsigned int)mem_map); + /* append memory to the DT */ mem_off = fdt_add_subnode(fdt, root_off, "memory"); if (mem_off < 0) @@ -115,13 +213,13 @@ static void __init append_memory(void *fdt, int root_off) if (err) panic("Unable to set memory node device_type: %d", err); - mem_entries = gen_fdt_mem_array(mem_array, physical_memsize); + mem_entries = gen_fdt_mem_array(mem_array, physical_memsize, mem_map); err = fdt_setprop(fdt, mem_off, "reg", mem_array, mem_entries * 2 * sizeof(mem_array[0])); if (err) panic("Unable to set memory regs property: %d", err); - mem_entries = gen_fdt_mem_array(mem_array, memsize); + mem_entries = gen_fdt_mem_array(mem_array, memsize, mem_map); err = fdt_setprop(fdt, mem_off, "linux,usable-memory", mem_array, mem_entries * 2 * sizeof(mem_array[0])); if (err) -- GitLab From 38ec82fe21cd99ad4d7f0dc883ef7ce9e9837176 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:23 +0100 Subject: [PATCH 0308/1167] MIPS: Malta: Probe interrupt controllers via DT Probe the CPU, GIC & i8259 interrupt controllers present in the Malta system using device tree. This enables interrupts to be provided to devices using device tree as they are moved over to being probed using it. Since Malta is very configurable it's unknown whether a GIC will be present at compile time. In order to support both cases the malta_dt_shim code is added in order to detect whether a GIC is present, adjusting the DT to route interrupts correctly and nop out the GIC node if no GIC is found. Signed-off-by: Paul Burton Cc: Masahiro Yamada Cc: Kees Cook Cc: Rob Herring Cc: Mark Rutland Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14274/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + arch/mips/boot/dts/mti/malta.dts | 41 +++++++++++++ arch/mips/mti-malta/malta-dtshim.c | 77 ++++++++++++++++++++++++ arch/mips/mti-malta/malta-int.c | 96 ++---------------------------- 4 files changed, 124 insertions(+), 91 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 7ec9ed7ab67b7..400cd3695ecc8 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -479,6 +479,7 @@ config MIPS_MALTA select SYS_SUPPORTS_ZBOOT select SYS_SUPPORTS_RELOCATABLE select USE_OF + select LIBFDT select ZONE_DMA32 if 64BIT select BUILTIN_DTB select LIBFDT diff --git a/arch/mips/boot/dts/mti/malta.dts b/arch/mips/boot/dts/mti/malta.dts index b18c46637d21b..af765afce8251 100644 --- a/arch/mips/boot/dts/mti/malta.dts +++ b/arch/mips/boot/dts/mti/malta.dts @@ -1,5 +1,8 @@ /dts-v1/; +#include +#include + /memreserve/ 0x00000000 0x00001000; /* YAMON exception vectors */ /memreserve/ 0x00001000 0x000ef000; /* YAMON */ /memreserve/ 0x000f0000 0x00010000; /* PIIX4 ISA memory */ @@ -8,4 +11,42 @@ #address-cells = <1>; #size-cells = <1>; compatible = "mti,malta"; + + cpu_intc: interrupt-controller { + compatible = "mti,cpu-interrupt-controller"; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + gic: interrupt-controller@1bdc0000 { + compatible = "mti,gic"; + reg = <0x1bdc0000 0x20000>; + + interrupt-controller; + #interrupt-cells = <3>; + + /* + * Declare the interrupt-parent even though the mti,gic + * binding doesn't require it, such that the kernel can + * figure out that cpu_intc is the root interrupt + * controller & should be probed first. + */ + interrupt-parent = <&cpu_intc>; + + timer { + compatible = "mti,gic-timer"; + interrupts = ; + }; + }; + + i8259: interrupt-controller@20 { + compatible = "intel,i8259"; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&gic>; + interrupts = ; + }; }; diff --git a/arch/mips/mti-malta/malta-dtshim.c b/arch/mips/mti-malta/malta-dtshim.c index bdda3cb66668c..c398582c316fc 100644 --- a/arch/mips/mti-malta/malta-dtshim.c +++ b/arch/mips/mti-malta/malta-dtshim.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #define ROCIT_REG_BASE 0x1f403000 @@ -226,6 +228,80 @@ static void __init append_memory(void *fdt, int root_off) panic("Unable to set linux,usable-memory property: %d", err); } +static void __init remove_gic(void *fdt) +{ + int err, gic_off, i8259_off, cpu_off; + void __iomem *biu_base; + uint32_t cpu_phandle, sc_cfg; + + /* if we have a CM which reports a GIC is present, leave the DT alone */ + err = mips_cm_probe(); + if (!err && (read_gcr_gic_status() & CM_GCR_GIC_STATUS_GICEX_MSK)) + return; + + if (malta_scon() == MIPS_REVISION_SCON_ROCIT) { + /* + * On systems using the RocIT system controller a GIC may be + * present without a CM. Detect whether that is the case. + */ + biu_base = ioremap_nocache(MSC01_BIU_REG_BASE, + MSC01_BIU_ADDRSPACE_SZ); + sc_cfg = __raw_readl(biu_base + MSC01_SC_CFG_OFS); + if (sc_cfg & MSC01_SC_CFG_GICPRES_MSK) { + /* enable the GIC at the system controller level */ + sc_cfg |= BIT(MSC01_SC_CFG_GICENA_SHF); + __raw_writel(sc_cfg, biu_base + MSC01_SC_CFG_OFS); + return; + } + } + + gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic"); + if (gic_off < 0) { + pr_warn("malta-dtshim: unable to find DT GIC node: %d\n", + gic_off); + return; + } + + err = fdt_nop_node(fdt, gic_off); + if (err) + pr_warn("malta-dtshim: unable to nop GIC node\n"); + + i8259_off = fdt_node_offset_by_compatible(fdt, -1, "intel,i8259"); + if (i8259_off < 0) { + pr_warn("malta-dtshim: unable to find DT i8259 node: %d\n", + i8259_off); + return; + } + + cpu_off = fdt_node_offset_by_compatible(fdt, -1, + "mti,cpu-interrupt-controller"); + if (cpu_off < 0) { + pr_warn("malta-dtshim: unable to find CPU intc node: %d\n", + cpu_off); + return; + } + + cpu_phandle = fdt_get_phandle(fdt, cpu_off); + if (!cpu_phandle) { + pr_warn("malta-dtshim: unable to get CPU intc phandle\n"); + return; + } + + err = fdt_setprop_u32(fdt, i8259_off, "interrupt-parent", cpu_phandle); + if (err) { + pr_warn("malta-dtshim: unable to set i8259 interrupt-parent: %d\n", + err); + return; + } + + err = fdt_setprop_u32(fdt, i8259_off, "interrupts", 2); + if (err) { + pr_warn("malta-dtshim: unable to set i8259 interrupts: %d\n", + err); + return; + } +} + void __init *malta_dt_shim(void *fdt) { int root_off, len, err; @@ -251,6 +327,7 @@ void __init *malta_dt_shim(void *fdt) return fdt; append_memory(fdt_buf, root_off); + remove_gic(fdt_buf); err = fdt_pack(fdt_buf); if (err) diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index c6a6c7afddab4..9f83224292d9b 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -14,11 +14,13 @@ */ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -37,10 +39,6 @@ #include #include -static void __iomem *_msc01_biu_base; - -static DEFINE_RAW_SPINLOCK(mips_irq_lock); - static inline int mips_pcibios_iack(void) { int irq; @@ -85,49 +83,6 @@ static inline int mips_pcibios_iack(void) return irq; } -static inline int get_int(void) -{ - unsigned long flags; - int irq; - raw_spin_lock_irqsave(&mips_irq_lock, flags); - - irq = mips_pcibios_iack(); - - /* - * The only way we can decide if an interrupt is spurious - * is by checking the 8259 registers. This needs a spinlock - * on an SMP system, so leave it up to the generic code... - */ - - raw_spin_unlock_irqrestore(&mips_irq_lock, flags); - - return irq; -} - -static void malta_hw0_irqdispatch(void) -{ - int irq; - - irq = get_int(); - if (irq < 0) { - /* interrupt has already been cleared */ - return; - } - - do_IRQ(MALTA_INT_BASE + irq); - -#ifdef CONFIG_MIPS_VPE_APSP_API_MT - if (aprp_hook) - aprp_hook(); -#endif -} - -static irqreturn_t i8259_handler(int irq, void *dev_id) -{ - malta_hw0_irqdispatch(); - return IRQ_HANDLED; -} - static void corehi_irqdispatch(void) { unsigned int intedge, intsteer, pcicmd, pcibadaddr; @@ -240,12 +195,6 @@ static struct irqaction irq_call = { }; #endif /* CONFIG_MIPS_MT_SMP */ -static struct irqaction i8259irq = { - .handler = i8259_handler, - .name = "XT-PIC cascade", - .flags = IRQF_NO_THREAD, -}; - static struct irqaction corehi_irqaction = { .handler = corehi_handler, .name = "CoreHi", @@ -281,28 +230,10 @@ void __init arch_init_ipiirq(int irq, struct irqaction *action) void __init arch_init_irq(void) { - int corehi_irq, i8259_irq; + int corehi_irq; - init_i8259_irqs(); - - if (!cpu_has_veic) - mips_cpu_irq_init(); - - if (mips_cm_present()) { - write_gcr_gic_base(GIC_BASE_ADDR | CM_GCR_GIC_BASE_GICEN_MSK); - gic_present = 1; - } else { - if (mips_revision_sconid == MIPS_REVISION_SCON_ROCIT) { - _msc01_biu_base = ioremap_nocache(MSC01_BIU_REG_BASE, - MSC01_BIU_ADDRSPACE_SZ); - gic_present = - (__raw_readl(_msc01_biu_base + MSC01_SC_CFG_OFS) & - MSC01_SC_CFG_GICPRES_MSK) >> - MSC01_SC_CFG_GICPRES_SHF; - } - } - if (gic_present) - pr_debug("GIC present\n"); + i8259_set_poll(mips_pcibios_iack); + irqchip_init(); switch (mips_revision_sconid) { case MIPS_REVISION_SCON_SOCIT: @@ -330,18 +261,6 @@ void __init arch_init_irq(void) } if (gic_present) { - int i; - - gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, MIPSCPU_INT_GIC, - MIPS_GIC_IRQ_BASE); - if (!mips_cm_present()) { - /* Enable the GIC */ - i = __raw_readl(_msc01_biu_base + MSC01_SC_CFG_OFS); - __raw_writel(i | (0x1 << MSC01_SC_CFG_GICENA_SHF), - _msc01_biu_base + MSC01_SC_CFG_OFS); - pr_debug("GIC Enabled\n"); - } - i8259_irq = MIPS_GIC_IRQ_BASE + GIC_INT_I8259A; corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI; } else { #if defined(CONFIG_MIPS_MT_SMP) @@ -361,19 +280,14 @@ void __init arch_init_irq(void) arch_init_ipiirq(cpu_ipi_call_irq, &irq_call); #endif if (cpu_has_veic) { - set_vi_handler(MSC01E_INT_I8259A, - malta_hw0_irqdispatch); set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch); - i8259_irq = MSC01E_INT_BASE + MSC01E_INT_I8259A; corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI; } else { - i8259_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_I8259A; corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI; } } - setup_irq(i8259_irq, &i8259irq); setup_irq(corehi_irq, &corehi_irqaction); } -- GitLab From ecd76eded07d1ba58bba410ec4bcbd8630fb9b16 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:24 +0100 Subject: [PATCH 0309/1167] of/platform: Probe "isa" busses by default Since commit 44a7185c2ae6 ("of/platform: Add common method to populate default bus") platforms calling of_platform_bus_probe from an initcall is either a rather unsafe race with of_platform_default_populate_init or a no-op. The MIPS Malta board needs to probe devices under an ISA bus, which we do support in the of_busses array but until now haven't included in of_default_bus_match_table. Add an "isa" entry to of_default_bus_match_table such that we can just accept use of of_platform_default_populate_init & remove the Malta-specific match table in a later patch. Signed-off-by: Paul Burton Acked-by: Rob Herring Cc: Frank Rowand Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14275/ Signed-off-by: Ralf Baechle --- drivers/of/platform.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index f39ccd5aa7012..d85e4318b0992 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -29,6 +29,7 @@ const struct of_device_id of_default_bus_match_table[] = { { .compatible = "simple-bus", }, { .compatible = "simple-mfd", }, + { .compatible = "isa", }, #ifdef CONFIG_ARM_AMBA { .compatible = "arm,amba-bus", }, #endif /* CONFIG_ARM_AMBA */ -- GitLab From eea1645bb8645cdf40b788dc6f2cbe2309e82411 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:25 +0100 Subject: [PATCH 0310/1167] MIPS: Malta: Remove custom DT match table Since commit 44a7185c2ae6 ("of/platform: Add common method to populate default bus") the Malta publish_devices initcall has essentially been a no-op. Remove it. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14276/ Signed-off-by: Ralf Baechle --- arch/mips/mti-malta/malta-dt.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/arch/mips/mti-malta/malta-dt.c b/arch/mips/mti-malta/malta-dt.c index 47a22889285f3..4822943100f30 100644 --- a/arch/mips/mti-malta/malta-dt.c +++ b/arch/mips/mti-malta/malta-dt.c @@ -17,18 +17,3 @@ void __init device_tree_init(void) { unflatten_and_copy_device_tree(); } - -static const struct of_device_id bus_ids[] __initconst = { - { .compatible = "simple-bus", }, - { .compatible = "isa", }, - {}, -}; - -static int __init publish_devices(void) -{ - if (!of_have_populated_dt()) - return 0; - - return of_platform_bus_probe(NULL, bus_ids, NULL); -} -device_initcall(publish_devices); -- GitLab From 0a46ffa3604ec64b6a6784f134267c49ec224b75 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:26 +0100 Subject: [PATCH 0311/1167] MIPS: Malta: Probe RTC via DT Add the DT node required to probe the RTC, and remove the platform code that was previously doing it. Signed-off-by: Paul Burton Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14277/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/malta.dts | 15 +++++++++++++++ arch/mips/mti-malta/malta-platform.c | 21 --------------------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/arch/mips/boot/dts/mti/malta.dts b/arch/mips/boot/dts/mti/malta.dts index af765afce8251..fecbca8ca6910 100644 --- a/arch/mips/boot/dts/mti/malta.dts +++ b/arch/mips/boot/dts/mti/malta.dts @@ -49,4 +49,19 @@ interrupt-parent = <&gic>; interrupts = ; }; + + isa { + compatible = "isa"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <1 0 0 0x1000>; + + rtc@70 { + compatible = "motorola,mc146818"; + reg = <1 0x70 0x8>; + + interrupt-parent = <&i8259>; + interrupts = <8>; + }; + }; }; diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c index 20a53e73b28ec..4e003b900fa2e 100644 --- a/arch/mips/mti-malta/malta-platform.c +++ b/arch/mips/mti-malta/malta-platform.c @@ -23,7 +23,6 @@ */ #include #include -#include #include #include #include @@ -68,25 +67,6 @@ static struct platform_device malta_uart8250_device = { }, }; -struct resource malta_rtc_resources[] = { - { - .start = RTC_PORT(0), - .end = RTC_PORT(7), - .flags = IORESOURCE_IO, - }, { - .start = RTC_IRQ, - .end = RTC_IRQ, - .flags = IORESOURCE_IRQ, - } -}; - -static struct platform_device malta_rtc_device = { - .name = "rtc_cmos", - .id = -1, - .resource = malta_rtc_resources, - .num_resources = ARRAY_SIZE(malta_rtc_resources), -}; - static struct mtd_partition malta_mtd_partitions[] = { { .name = "YAMON", @@ -129,7 +109,6 @@ static struct platform_device malta_flash_device = { static struct platform_device *malta_devices[] __initdata = { &malta_uart8250_device, - &malta_rtc_device, &malta_flash_device, }; -- GitLab From 97af8e1cb31870c6f4ca175d5eada7be5cc65e0f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:27 +0100 Subject: [PATCH 0312/1167] MIPS: Malta: Probe pflash via DT Add the DT nodes required to probe the CFI compatible parallel monitor flash found on the Malta development board, and remove the platform code that was previously doing it. Delete the now-empty malta-platform.c file. Adjust the Malta defconfigs that enable MTD & the pflash/CFI driver to enable CONFIG_MTD_PHYSMAP_OF rather than CONFIG_MTD_PHYSMAP in order to preserve their behaviour. Signed-off-by: Paul Burton Cc: Bartlomiej Zolnierkiewicz Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14278/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/malta.dts | 31 +++++++++++++++ arch/mips/configs/malta_defconfig | 2 +- arch/mips/configs/malta_kvm_defconfig | 2 +- arch/mips/configs/malta_kvm_guest_defconfig | 2 +- arch/mips/configs/maltaup_xpa_defconfig | 2 +- arch/mips/mti-malta/malta-platform.c | 44 --------------------- 6 files changed, 35 insertions(+), 48 deletions(-) diff --git a/arch/mips/boot/dts/mti/malta.dts b/arch/mips/boot/dts/mti/malta.dts index fecbca8ca6910..48783b13f8891 100644 --- a/arch/mips/boot/dts/mti/malta.dts +++ b/arch/mips/boot/dts/mti/malta.dts @@ -50,6 +50,37 @@ interrupts = ; }; + flash@1e000000 { + compatible = "intel,dt28f160", "cfi-flash"; + reg = <0x1e000000 0x400000>; + bank-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + yamon@0 { + label = "YAMON"; + reg = <0x0 0x100000>; + read-only; + }; + + user-fs@100000 { + label = "User FS"; + reg = <0x100000 0x2e0000>; + }; + + board-config@3e0000 { + label = "Board Config"; + reg = <0x3e0000 0x20000>; + read-only; + }; + }; + }; + isa { compatible = "isa"; #address-cells = <2>; diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 5afb4840aec75..d5d4816a1dd80 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -230,7 +230,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y -CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_UBI=m CONFIG_MTD_UBI_GLUEBI=m CONFIG_BLK_DEV_FD=m diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig index 98f13879bb8fd..ef6ef24c6213d 100644 --- a/arch/mips/configs/malta_kvm_defconfig +++ b/arch/mips/configs/malta_kvm_defconfig @@ -235,7 +235,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y -CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_UBI=m CONFIG_MTD_UBI_GLUEBI=m CONFIG_BLK_DEV_FD=m diff --git a/arch/mips/configs/malta_kvm_guest_defconfig b/arch/mips/configs/malta_kvm_guest_defconfig index 3b5d5913f548c..3a49a770eb413 100644 --- a/arch/mips/configs/malta_kvm_guest_defconfig +++ b/arch/mips/configs/malta_kvm_guest_defconfig @@ -234,7 +234,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y -CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_UBI=m CONFIG_MTD_UBI_GLUEBI=m CONFIG_BLK_DEV_FD=m diff --git a/arch/mips/configs/maltaup_xpa_defconfig b/arch/mips/configs/maltaup_xpa_defconfig index 7322157327516..62e05eb3bb54a 100644 --- a/arch/mips/configs/maltaup_xpa_defconfig +++ b/arch/mips/configs/maltaup_xpa_defconfig @@ -231,7 +231,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y -CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_UBI=m CONFIG_MTD_UBI_GLUEBI=m CONFIG_BLK_DEV_FD=m diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c index 4e003b900fa2e..516e1233d771c 100644 --- a/arch/mips/mti-malta/malta-platform.c +++ b/arch/mips/mti-malta/malta-platform.c @@ -25,11 +25,8 @@ #include #include #include -#include -#include #include #include -#include #define SMC_PORT(base, int) \ { \ @@ -67,49 +64,8 @@ static struct platform_device malta_uart8250_device = { }, }; -static struct mtd_partition malta_mtd_partitions[] = { - { - .name = "YAMON", - .offset = 0x0, - .size = 0x100000, - .mask_flags = MTD_WRITEABLE - }, { - .name = "User FS", - .offset = 0x100000, - .size = 0x2e0000 - }, { - .name = "Board Config", - .offset = 0x3e0000, - .size = 0x020000, - .mask_flags = MTD_WRITEABLE - } -}; - -static struct physmap_flash_data malta_flash_data = { - .width = 4, - .nr_parts = ARRAY_SIZE(malta_mtd_partitions), - .parts = malta_mtd_partitions -}; - -static struct resource malta_flash_resource = { - .start = 0x1e000000, - .end = 0x1e3fffff, - .flags = IORESOURCE_MEM -}; - -static struct platform_device malta_flash_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &malta_flash_data, - }, - .num_resources = 1, - .resource = &malta_flash_resource, -}; - static struct platform_device *malta_devices[] __initdata = { &malta_uart8250_device, - &malta_flash_device, }; static int __init malta_add_devices(void) -- GitLab From 10b6ea0959de2c42b9f105c88b51a54c4dd961c2 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:28 +0100 Subject: [PATCH 0313/1167] MIPS: Malta: Use syscon-reboot driver to reboot Make use of the generic syscon-reboot driver to reboot the Malta board, reducing the amount of platform code it requires. Signed-off-by: Paul Burton Cc: Stephan Linz Cc: Jacek Anaszewski Cc: Bartlomiej Zolnierkiewicz Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14279/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/malta.dts | 12 ++++++++++++ arch/mips/configs/malta_defconfig | 2 ++ arch/mips/configs/malta_kvm_defconfig | 2 ++ arch/mips/configs/malta_kvm_guest_defconfig | 2 ++ arch/mips/configs/malta_qemu_32r6_defconfig | 2 ++ arch/mips/configs/maltaaprp_defconfig | 2 ++ arch/mips/configs/maltasmvp_defconfig | 2 ++ arch/mips/configs/maltasmvp_eva_defconfig | 2 ++ arch/mips/configs/maltaup_defconfig | 2 ++ arch/mips/configs/maltaup_xpa_defconfig | 2 ++ arch/mips/mti-malta/malta-reset.c | 15 ++------------- 11 files changed, 32 insertions(+), 13 deletions(-) diff --git a/arch/mips/boot/dts/mti/malta.dts b/arch/mips/boot/dts/mti/malta.dts index 48783b13f8891..f604a272d91dc 100644 --- a/arch/mips/boot/dts/mti/malta.dts +++ b/arch/mips/boot/dts/mti/malta.dts @@ -81,6 +81,18 @@ }; }; + fpga_regs: system-controller@1f000000 { + compatible = "mti,malta-fpga", "syscon", "simple-mfd"; + reg = <0x1f000000 0x1000>; + + reboot { + compatible = "syscon-reboot"; + regmap = <&fpga_regs>; + offset = <0x500>; + mask = <0x4d>; + }; + }; + isa { compatible = "isa"; #address-cells = <2>; diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index d5d4816a1dd80..58d43f3c348d0 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -318,6 +318,8 @@ CONFIG_LIBERTAS=m # CONFIG_SERIO_I8042 is not set CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y CONFIG_FB_CIRRUS=y diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig index ef6ef24c6213d..c8f7e2835840d 100644 --- a/arch/mips/configs/malta_kvm_defconfig +++ b/arch/mips/configs/malta_kvm_defconfig @@ -331,6 +331,8 @@ CONFIG_LIBERTAS=m # CONFIG_SERIO_I8042 is not set CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y CONFIG_FB_CIRRUS=y diff --git a/arch/mips/configs/malta_kvm_guest_defconfig b/arch/mips/configs/malta_kvm_guest_defconfig index 3a49a770eb413..d2f54e55356c8 100644 --- a/arch/mips/configs/malta_kvm_guest_defconfig +++ b/arch/mips/configs/malta_kvm_guest_defconfig @@ -331,6 +331,8 @@ CONFIG_LIBERTAS=m # CONFIG_SERIO_I8042 is not set CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y CONFIG_FB_CIRRUS=y diff --git a/arch/mips/configs/malta_qemu_32r6_defconfig b/arch/mips/configs/malta_qemu_32r6_defconfig index 65f140e1e872a..cbf37dd0c4908 100644 --- a/arch/mips/configs/malta_qemu_32r6_defconfig +++ b/arch/mips/configs/malta_qemu_32r6_defconfig @@ -132,6 +132,8 @@ CONFIG_LEGACY_PTY_COUNT=4 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_HW_RANDOM=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y CONFIG_FIRMWARE_EDID=y diff --git a/arch/mips/configs/maltaaprp_defconfig b/arch/mips/configs/maltaaprp_defconfig index 799c4338fd5e0..35f6ba260df8f 100644 --- a/arch/mips/configs/maltaaprp_defconfig +++ b/arch/mips/configs/maltaaprp_defconfig @@ -132,6 +132,8 @@ CONFIG_LEGACY_PTY_COUNT=16 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_HW_RANDOM=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y diff --git a/arch/mips/configs/maltasmvp_defconfig b/arch/mips/configs/maltasmvp_defconfig index ac0eb4daf1010..900f14543eeb9 100644 --- a/arch/mips/configs/maltasmvp_defconfig +++ b/arch/mips/configs/maltasmvp_defconfig @@ -134,6 +134,8 @@ CONFIG_LEGACY_PTY_COUNT=4 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_HW_RANDOM=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y CONFIG_FIRMWARE_EDID=y diff --git a/arch/mips/configs/maltasmvp_eva_defconfig b/arch/mips/configs/maltasmvp_eva_defconfig index 31846000530fb..8e2738b5e180a 100644 --- a/arch/mips/configs/maltasmvp_eva_defconfig +++ b/arch/mips/configs/maltasmvp_eva_defconfig @@ -137,6 +137,8 @@ CONFIG_LEGACY_PTY_COUNT=4 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_HW_RANDOM=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y diff --git a/arch/mips/configs/maltaup_defconfig b/arch/mips/configs/maltaup_defconfig index a79107da0675b..6dc4e309a6918 100644 --- a/arch/mips/configs/maltaup_defconfig +++ b/arch/mips/configs/maltaup_defconfig @@ -131,6 +131,8 @@ CONFIG_LEGACY_PTY_COUNT=16 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_HW_RANDOM=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y diff --git a/arch/mips/configs/maltaup_xpa_defconfig b/arch/mips/configs/maltaup_xpa_defconfig index 62e05eb3bb54a..3d0d9cb9673f8 100644 --- a/arch/mips/configs/maltaup_xpa_defconfig +++ b/arch/mips/configs/maltaup_xpa_defconfig @@ -326,6 +326,8 @@ CONFIG_LIBERTAS=m # CONFIG_SERIO_I8042 is not set CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y CONFIG_FB_CIRRUS=y diff --git a/arch/mips/mti-malta/malta-reset.c b/arch/mips/mti-malta/malta-reset.c index 2fd2cc2c5034f..04d6b9c8a946f 100644 --- a/arch/mips/mti-malta/malta-reset.c +++ b/arch/mips/mti-malta/malta-reset.c @@ -8,21 +8,11 @@ */ #include #include +#include #include #include -#define SOFTRES_REG 0x1f000500 -#define GORESET 0x42 - -static void mips_machine_restart(char *command) -{ - unsigned int __iomem *softres_reg = - ioremap(SOFTRES_REG, sizeof(unsigned int)); - - __raw_writel(GORESET, softres_reg); -} - static void mips_machine_halt(void) { while (true); @@ -33,12 +23,11 @@ static void mips_machine_power_off(void) mips_pm_suspend(PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_SOFF); pr_info("Failed to power down, resetting\n"); - mips_machine_restart(NULL); + machine_restart(NULL); } static int __init mips_reboot_setup(void) { - _machine_restart = mips_machine_restart; _machine_halt = mips_machine_halt; pm_power_off = mips_machine_power_off; -- GitLab From c834469b88cd0a54b313012e9f023937c68a5704 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:29 +0100 Subject: [PATCH 0314/1167] MIPS: Malta: Remove custom halt implementation The arch code will hang the machine with an infinite loop if the board doesn't provide an impelementation of halt - let it, rather than duplicating it. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14280/ Signed-off-by: Ralf Baechle --- arch/mips/mti-malta/malta-reset.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/mips/mti-malta/malta-reset.c b/arch/mips/mti-malta/malta-reset.c index 04d6b9c8a946f..dd6f62ad44172 100644 --- a/arch/mips/mti-malta/malta-reset.c +++ b/arch/mips/mti-malta/malta-reset.c @@ -13,11 +13,6 @@ #include #include -static void mips_machine_halt(void) -{ - while (true); -} - static void mips_machine_power_off(void) { mips_pm_suspend(PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_SOFF); @@ -28,7 +23,6 @@ static void mips_machine_power_off(void) static int __init mips_reboot_setup(void) { - _machine_halt = mips_machine_halt; pm_power_off = mips_machine_power_off; return 0; -- GitLab From 7bbe59ddbb9fae90eef0248416976d4e5f6b1a2d Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Fri, 19 Aug 2016 11:52:26 +0900 Subject: [PATCH 0315/1167] MIPS: BMIPS: Add support PWM device nodes Adds PWM device nodes to BCM7xxx MIPS based SoCs. Signed-off-by: Jaedon Shin Reviewed-by: Florian Fainelli Cc: Jonas Gorski Cc: Kevin Cernekee Cc: Rob Herring Cc: MIPS Mailing List Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14000/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/brcm/bcm7125.dtsi | 14 ++++++++++++++ arch/mips/boot/dts/brcm/bcm7346.dtsi | 22 ++++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm7358.dtsi | 22 ++++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm7360.dtsi | 14 ++++++++++++++ arch/mips/boot/dts/brcm/bcm7362.dtsi | 14 ++++++++++++++ arch/mips/boot/dts/brcm/bcm7420.dtsi | 22 ++++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm7425.dtsi | 22 ++++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm7435.dtsi | 22 ++++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm97125cbmb.dts | 4 ++++ arch/mips/boot/dts/brcm/bcm97346dbsmb.dts | 8 ++++++++ arch/mips/boot/dts/brcm/bcm97358svmb.dts | 8 ++++++++ arch/mips/boot/dts/brcm/bcm97360svmb.dts | 4 ++++ arch/mips/boot/dts/brcm/bcm97362svmb.dts | 4 ++++ arch/mips/boot/dts/brcm/bcm97420c.dts | 8 ++++++++ arch/mips/boot/dts/brcm/bcm97425svmb.dts | 8 ++++++++ arch/mips/boot/dts/brcm/bcm97435svmb.dts | 8 ++++++++ 16 files changed, 204 insertions(+) diff --git a/arch/mips/boot/dts/brcm/bcm7125.dtsi b/arch/mips/boot/dts/brcm/bcm7125.dtsi index 550e1d9e3ee03..97191f6bca28a 100644 --- a/arch/mips/boot/dts/brcm/bcm7125.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7125.dtsi @@ -40,6 +40,12 @@ #clock-cells = <0>; clock-frequency = <81000000>; }; + + upg_clk: upg_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; rdb { @@ -183,6 +189,14 @@ status = "disabled"; }; + pwma: pwm@406580 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406580 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + ehci0: usb@488300 { compatible = "brcm,bcm7125-ehci", "generic-ehci"; reg = <0x488300 0x100>; diff --git a/arch/mips/boot/dts/brcm/bcm7346.dtsi b/arch/mips/boot/dts/brcm/bcm7346.dtsi index ec959061d52e3..eb7b19a32e3ec 100644 --- a/arch/mips/boot/dts/brcm/bcm7346.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7346.dtsi @@ -40,6 +40,12 @@ #clock-cells = <0>; clock-frequency = <81000000>; }; + + upg_clk: upg_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; rdb { @@ -210,6 +216,22 @@ status = "disabled"; }; + pwma: pwm@406580 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406580 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + + pwmb: pwm@406800 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406800 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + enet0: ethernet@430000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7358.dtsi b/arch/mips/boot/dts/brcm/bcm7358.dtsi index ca57fb5eb1222..b2276b1e12d44 100644 --- a/arch/mips/boot/dts/brcm/bcm7358.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7358.dtsi @@ -34,6 +34,12 @@ #clock-cells = <0>; clock-frequency = <81000000>; }; + + upg_clk: upg_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; rdb { @@ -194,6 +200,22 @@ status = "disabled"; }; + pwma: pwm@406400 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406400 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + + pwmb: pwm@406700 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406700 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + enet0: ethernet@430000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7360.dtsi b/arch/mips/boot/dts/brcm/bcm7360.dtsi index 1c0c3d438c7ac..e414af1e14ff4 100644 --- a/arch/mips/boot/dts/brcm/bcm7360.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7360.dtsi @@ -34,6 +34,12 @@ #clock-cells = <0>; clock-frequency = <81000000>; }; + + upg_clk: upg_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; rdb { @@ -194,6 +200,14 @@ status = "disabled"; }; + pwma: pwm@406400 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406400 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + enet0: ethernet@430000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7362.dtsi b/arch/mips/boot/dts/brcm/bcm7362.dtsi index 6b4713add4b8a..3bd1c0111d438 100644 --- a/arch/mips/boot/dts/brcm/bcm7362.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7362.dtsi @@ -40,6 +40,12 @@ #clock-cells = <0>; clock-frequency = <81000000>; }; + + upg_clk: upg_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; rdb { @@ -190,6 +196,14 @@ status = "disabled"; }; + pwma: pwm@406400 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406400 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + enet0: ethernet@430000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7420.dtsi b/arch/mips/boot/dts/brcm/bcm7420.dtsi index 0586bf662571e..27c3d45556b9e 100644 --- a/arch/mips/boot/dts/brcm/bcm7420.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7420.dtsi @@ -40,6 +40,12 @@ #clock-cells = <0>; clock-frequency = <81000000>; }; + + upg_clk: upg_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; rdb { @@ -191,6 +197,22 @@ status = "disabled"; }; + pwma: pwm@406580 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406580 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + + pwmb: pwm@406880 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406880 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + enet0: ethernet@468000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7425.dtsi b/arch/mips/boot/dts/brcm/bcm7425.dtsi index c1c15edaf829b..9ab65d64e948d 100644 --- a/arch/mips/boot/dts/brcm/bcm7425.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7425.dtsi @@ -40,6 +40,12 @@ #clock-cells = <0>; clock-frequency = <81000000>; }; + + upg_clk: upg_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; rdb { @@ -209,6 +215,22 @@ status = "disabled"; }; + pwma: pwm@406580 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406580 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + + pwmb: pwm@406800 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406800 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + enet0: ethernet@b80000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7435.dtsi b/arch/mips/boot/dts/brcm/bcm7435.dtsi index a874d3a0e2ee6..7801169416e74 100644 --- a/arch/mips/boot/dts/brcm/bcm7435.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7435.dtsi @@ -52,6 +52,12 @@ #clock-cells = <0>; clock-frequency = <81000000>; }; + + upg_clk: upg_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; rdb { @@ -224,6 +230,22 @@ status = "disabled"; }; + pwma: pwm@406580 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406580 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + + pwmb: pwm@406800 { + compatible = "brcm,bcm7038-pwm"; + reg = <0x406800 0x28>; + #pwm-cells = <2>; + clocks = <&upg_clk>; + status = "disabled"; + }; + enet0: ethernet@b80000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm97125cbmb.dts b/arch/mips/boot/dts/brcm/bcm97125cbmb.dts index f2449d147c6da..5c24eacd72ddc 100644 --- a/arch/mips/boot/dts/brcm/bcm97125cbmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97125cbmb.dts @@ -45,6 +45,10 @@ status = "okay"; }; +&pwma { + status = "okay"; +}; + /* FIXME: USB is wonky; disable it for now */ &ehci0 { status = "disabled"; diff --git a/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts b/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts index d3d28816a0270..2c55ab094a297 100644 --- a/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts @@ -49,6 +49,14 @@ status = "okay"; }; +&pwma { + status = "okay"; +}; + +&pwmb { + status = "okay"; +}; + &enet0 { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97358svmb.dts b/arch/mips/boot/dts/brcm/bcm97358svmb.dts index 02ce6b429dc47..757fe9d5f4dff 100644 --- a/arch/mips/boot/dts/brcm/bcm97358svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97358svmb.dts @@ -45,6 +45,14 @@ status = "okay"; }; +&pwma { + status = "okay"; +}; + +&pwmb { + status = "okay"; +}; + &enet0 { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97360svmb.dts b/arch/mips/boot/dts/brcm/bcm97360svmb.dts index 73124be9548ae..496e6ed9fae30 100644 --- a/arch/mips/boot/dts/brcm/bcm97360svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97360svmb.dts @@ -45,6 +45,10 @@ status = "okay"; }; +&pwma { + status = "okay"; +}; + &enet0 { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97362svmb.dts b/arch/mips/boot/dts/brcm/bcm97362svmb.dts index 3cfcaebe7f79d..b880c018f3d8f 100644 --- a/arch/mips/boot/dts/brcm/bcm97362svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97362svmb.dts @@ -41,6 +41,10 @@ status = "okay"; }; +&pwma { + status = "okay"; +}; + &enet0 { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97420c.dts b/arch/mips/boot/dts/brcm/bcm97420c.dts index 600d57abee05c..e66271af055e7 100644 --- a/arch/mips/boot/dts/brcm/bcm97420c.dts +++ b/arch/mips/boot/dts/brcm/bcm97420c.dts @@ -51,6 +51,14 @@ status = "okay"; }; +&pwma { + status = "okay"; +}; + +&pwmb { + status = "okay"; +}; + /* FIXME: MAC driver comes up but cannot attach to PHY */ &enet0 { status = "disabled"; diff --git a/arch/mips/boot/dts/brcm/bcm97425svmb.dts b/arch/mips/boot/dts/brcm/bcm97425svmb.dts index 119c714805cbc..f091e91b11c53 100644 --- a/arch/mips/boot/dts/brcm/bcm97425svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97425svmb.dts @@ -51,6 +51,14 @@ status = "okay"; }; +&pwma { + status = "okay"; +}; + +&pwmb { + status = "okay"; +}; + &enet0 { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97435svmb.dts b/arch/mips/boot/dts/brcm/bcm97435svmb.dts index 43e3ba27f07ba..9db84f2a66644 100644 --- a/arch/mips/boot/dts/brcm/bcm97435svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97435svmb.dts @@ -51,6 +51,14 @@ status = "okay"; }; +&pwma { + status = "okay"; +}; + +&pwmb { + status = "okay"; +}; + &enet0 { status = "okay"; }; -- GitLab From c707844d4b876f74f2adf036f98f6787d76d2905 Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Fri, 19 Aug 2016 11:52:27 +0900 Subject: [PATCH 0316/1167] MIPS: BMIPS: Add support GPIO device nodes Adds GPIO device nodes to BCM7xxx MIPS based SoCs. Signed-off-by: Jaedon Shin Cc: Florian Fainelli Cc: Jonas Gorski Cc: Kevin Cernekee Cc: Rob Herring Cc: MIPS Mailing List Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14001/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/brcm/bcm7125.dtsi | 12 +++++++++ arch/mips/boot/dts/brcm/bcm7346.dtsi | 37 ++++++++++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm7358.dtsi | 37 ++++++++++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm7360.dtsi | 37 ++++++++++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm7362.dtsi | 37 ++++++++++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm7420.dtsi | 12 +++++++++ arch/mips/boot/dts/brcm/bcm7425.dtsi | 37 ++++++++++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm7435.dtsi | 37 ++++++++++++++++++++++++++++ 8 files changed, 246 insertions(+) diff --git a/arch/mips/boot/dts/brcm/bcm7125.dtsi b/arch/mips/boot/dts/brcm/bcm7125.dtsi index 97191f6bca28a..746ed06c85de6 100644 --- a/arch/mips/boot/dts/brcm/bcm7125.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7125.dtsi @@ -197,6 +197,18 @@ status = "disabled"; }; + upg_gio: gpio@406700 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x406700 0x80>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_irq0_intc>; + interrupts = <6>; + brcm,gpio-bank-widths = <32 32 32 18>; + }; + ehci0: usb@488300 { compatible = "brcm,bcm7125-ehci", "generic-ehci"; reg = <0x488300 0x100>; diff --git a/arch/mips/boot/dts/brcm/bcm7346.dtsi b/arch/mips/boot/dts/brcm/bcm7346.dtsi index eb7b19a32e3ec..0105e4e5130b6 100644 --- a/arch/mips/boot/dts/brcm/bcm7346.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7346.dtsi @@ -232,6 +232,43 @@ status = "disabled"; }; + aon_pm_l2_intc: interrupt-controller@408440 { + compatible = "brcm,l2-intc"; + reg = <0x408440 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <53>; + brcm,irq-can-wake; + }; + + upg_gio: gpio@406700 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x406700 0x60>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_irq0_intc>; + interrupts = <6>; + brcm,gpio-bank-widths = <32 32 16>; + }; + + upg_gio_aon: gpio@408c00 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x408c00 0x60>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_aon_irq0_intc>; + interrupts = <6>; + interrupts-extended = <&upg_aon_irq0_intc 6>, + <&aon_pm_l2_intc 5>; + wakeup-source; + brcm,gpio-bank-widths = <27 32 2>; + }; + enet0: ethernet@430000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7358.dtsi b/arch/mips/boot/dts/brcm/bcm7358.dtsi index b2276b1e12d44..aec1b2e7e2ab7 100644 --- a/arch/mips/boot/dts/brcm/bcm7358.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7358.dtsi @@ -216,6 +216,43 @@ status = "disabled"; }; + aon_pm_l2_intc: interrupt-controller@408240 { + compatible = "brcm,l2-intc"; + reg = <0x408240 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <50>; + brcm,irq-can-wake; + }; + + upg_gio: gpio@406500 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x406500 0xa0>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_irq0_intc>; + interrupts = <6>; + brcm,gpio-bank-widths = <32 32 32 29 4>; + }; + + upg_gio_aon: gpio@408c00 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x408c00 0x60>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_aon_irq0_intc>; + interrupts = <6>; + interrupts-extended = <&upg_aon_irq0_intc 6>, + <&aon_pm_l2_intc 5>; + wakeup-source; + brcm,gpio-bank-widths = <21 32 2>; + }; + enet0: ethernet@430000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7360.dtsi b/arch/mips/boot/dts/brcm/bcm7360.dtsi index e414af1e14ff4..f0f63cb2bd2be 100644 --- a/arch/mips/boot/dts/brcm/bcm7360.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7360.dtsi @@ -208,6 +208,43 @@ status = "disabled"; }; + aon_pm_l2_intc: interrupt-controller@408440 { + compatible = "brcm,l2-intc"; + reg = <0x408440 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <50>; + brcm,irq-can-wake; + }; + + upg_gio: gpio@406500 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x406500 0xa0>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_irq0_intc>; + interrupts = <6>; + brcm,gpio-bank-widths = <32 32 32 29 4>; + }; + + upg_gio_aon: gpio@408c00 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x408c00 0x60>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_aon_irq0_intc>; + interrupts = <6>; + interrupts-extended = <&upg_aon_irq0_intc 6>, + <&aon_pm_l2_intc 5>; + wakeup-source; + brcm,gpio-bank-widths = <21 32 2>; + }; + enet0: ethernet@430000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7362.dtsi b/arch/mips/boot/dts/brcm/bcm7362.dtsi index 3bd1c0111d438..ac42b98e31bb6 100644 --- a/arch/mips/boot/dts/brcm/bcm7362.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7362.dtsi @@ -204,6 +204,43 @@ status = "disabled"; }; + aon_pm_l2_intc: interrupt-controller@408440 { + compatible = "brcm,l2-intc"; + reg = <0x408440 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <50>; + brcm,irq-can-wake; + }; + + upg_gio: gpio@406500 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x406500 0xa0>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_irq0_intc>; + interrupts = <6>; + brcm,gpio-bank-widths = <32 32 32 29 4>; + }; + + upg_gio_aon: gpio@408c00 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x408c00 0x60>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_aon_irq0_intc>; + interrupts = <6>; + interrupts-extended = <&upg_aon_irq0_intc 6>, + <&aon_pm_l2_intc 5>; + wakeup-source; + brcm,gpio-bank-widths = <21 32 2>; + }; + enet0: ethernet@430000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7420.dtsi b/arch/mips/boot/dts/brcm/bcm7420.dtsi index 27c3d45556b9e..0d391d77c7802 100644 --- a/arch/mips/boot/dts/brcm/bcm7420.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7420.dtsi @@ -213,6 +213,18 @@ status = "disabled"; }; + upg_gio: gpio@406700 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x406700 0x80>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_irq0_intc>; + interrupts = <6>; + brcm,gpio-bank-widths = <32 32 32 27>; + }; + enet0: ethernet@468000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7425.dtsi b/arch/mips/boot/dts/brcm/bcm7425.dtsi index 9ab65d64e948d..8b05b98f2a9c8 100644 --- a/arch/mips/boot/dts/brcm/bcm7425.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7425.dtsi @@ -231,6 +231,43 @@ status = "disabled"; }; + aon_pm_l2_intc: interrupt-controller@408440 { + compatible = "brcm,l2-intc"; + reg = <0x408440 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <49>; + brcm,irq-can-wake; + }; + + upg_gio: gpio@406700 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x406700 0x80>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_irq0_intc>; + interrupts = <6>; + brcm,gpio-bank-widths = <32 32 32 21>; + }; + + upg_gio_aon: gpio@4094c0 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x4094c0 0x40>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_aon_irq0_intc>; + interrupts = <6>; + interrupts-extended = <&upg_aon_irq0_intc 6>, + <&aon_pm_l2_intc 5>; + wakeup-source; + brcm,gpio-bank-widths = <18 4>; + }; + enet0: ethernet@b80000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7435.dtsi b/arch/mips/boot/dts/brcm/bcm7435.dtsi index 7801169416e74..b7bb1024089ce 100644 --- a/arch/mips/boot/dts/brcm/bcm7435.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7435.dtsi @@ -246,6 +246,43 @@ status = "disabled"; }; + aon_pm_l2_intc: interrupt-controller@408440 { + compatible = "brcm,l2-intc"; + reg = <0x408440 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <54>; + brcm,irq-can-wake; + }; + + upg_gio: gpio@406700 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x406700 0x80>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_irq0_intc>; + interrupts = <6>; + brcm,gpio-bank-widths = <32 32 32 21>; + }; + + upg_gio_aon: gpio@4094c0 { + compatible = "brcm,brcmstb-gpio"; + reg = <0x4094c0 0x40>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + interrupt-parent = <&upg_aon_irq0_intc>; + interrupts = <6>; + interrupts-extended = <&upg_aon_irq0_intc 6>, + <&aon_pm_l2_intc 5>; + wakeup-source; + brcm,gpio-bank-widths = <18 4>; + }; + enet0: ethernet@b80000 { phy-mode = "internal"; phy-handle = <&phy1>; -- GitLab From b2420e2762e36ec3aab0c0b6b9ee277f7b1b48e2 Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Fri, 19 Aug 2016 11:52:28 +0900 Subject: [PATCH 0317/1167] MIPS: BMIPS: Add support SDHCI device nodes Adds SDHCI device nodes to BCM7xxx MIPS based SoCs. Signed-off-by: Jaedon Shin Reviewed-by: Florian Fainelli Cc: Jonas Gorski Cc: Kevin Cernekee Cc: Rob Herring Cc: MIPS Mailing List Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14002/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/brcm/bcm7346.dtsi | 8 ++++++++ arch/mips/boot/dts/brcm/bcm7360.dtsi | 8 ++++++++ arch/mips/boot/dts/brcm/bcm7362.dtsi | 8 ++++++++ arch/mips/boot/dts/brcm/bcm7425.dtsi | 20 ++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm7435.dtsi | 20 ++++++++++++++++++++ arch/mips/boot/dts/brcm/bcm97346dbsmb.dts | 4 ++++ arch/mips/boot/dts/brcm/bcm97360svmb.dts | 4 ++++ arch/mips/boot/dts/brcm/bcm97362svmb.dts | 4 ++++ arch/mips/boot/dts/brcm/bcm97425svmb.dts | 8 ++++++++ arch/mips/boot/dts/brcm/bcm97435svmb.dts | 8 ++++++++ 10 files changed, 92 insertions(+) diff --git a/arch/mips/boot/dts/brcm/bcm7346.dtsi b/arch/mips/boot/dts/brcm/bcm7346.dtsi index 0105e4e5130b6..0da4f8a3744b2 100644 --- a/arch/mips/boot/dts/brcm/bcm7346.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7346.dtsi @@ -411,5 +411,13 @@ #phy-cells = <0>; }; }; + + sdhci0: sdhci@413500 { + compatible = "brcm,bcm7425-sdhci"; + reg = <0x413500 0x100>; + interrupt-parent = <&periph_intc>; + interrupts = <85>; + status = "disabled"; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm7360.dtsi b/arch/mips/boot/dts/brcm/bcm7360.dtsi index f0f63cb2bd2be..9f72d34904279 100644 --- a/arch/mips/boot/dts/brcm/bcm7360.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7360.dtsi @@ -330,5 +330,13 @@ #phy-cells = <0>; }; }; + + sdhci0: sdhci@410000 { + compatible = "brcm,bcm7425-sdhci"; + reg = <0x410000 0x100>; + interrupt-parent = <&periph_intc>; + interrupts = <82>; + status = "disabled"; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm7362.dtsi b/arch/mips/boot/dts/brcm/bcm7362.dtsi index ac42b98e31bb6..ff734f45df92a 100644 --- a/arch/mips/boot/dts/brcm/bcm7362.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7362.dtsi @@ -326,5 +326,13 @@ #phy-cells = <0>; }; }; + + sdhci0: sdhci@410000 { + compatible = "brcm,bcm7425-sdhci"; + reg = <0x410000 0x100>; + interrupt-parent = <&periph_intc>; + interrupts = <82>; + status = "disabled"; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm7425.dtsi b/arch/mips/boot/dts/brcm/bcm7425.dtsi index 8b05b98f2a9c8..1c8d3b4033a04 100644 --- a/arch/mips/boot/dts/brcm/bcm7425.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7425.dtsi @@ -410,5 +410,25 @@ #phy-cells = <0>; }; }; + + sdhci0: sdhci@419000 { + compatible = "brcm,bcm7425-sdhci"; + reg = <0x419000 0x100>; + interrupt-parent = <&periph_intc>; + interrupts = <43>; + sd-uhs-sdr50; + mmc-hs200-1_8v; + status = "disabled"; + }; + + sdhci1: sdhci@419200 { + compatible = "brcm,bcm7425-sdhci"; + reg = <0x419200 0x100>; + interrupt-parent = <&periph_intc>; + interrupts = <44>; + sd-uhs-sdr50; + mmc-hs200-1_8v; + status = "disabled"; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm7435.dtsi b/arch/mips/boot/dts/brcm/bcm7435.dtsi index b7bb1024089ce..2b28d91762ef2 100644 --- a/arch/mips/boot/dts/brcm/bcm7435.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7435.dtsi @@ -425,5 +425,25 @@ #phy-cells = <0>; }; }; + + sdhci0: sdhci@41a000 { + compatible = "brcm,bcm7425-sdhci"; + reg = <0x41a000 0x100>; + interrupt-parent = <&periph_intc>; + interrupts = <47>; + sd-uhs-sdr50; + mmc-hs200-1_8v; + status = "disabled"; + }; + + sdhci1: sdhci@41a200 { + compatible = "brcm,bcm7425-sdhci"; + reg = <0x41a200 0x100>; + interrupt-parent = <&periph_intc>; + interrupts = <48>; + sd-uhs-sdr50; + mmc-hs200-1_8v; + status = "disabled"; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts b/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts index 2c55ab094a297..27c9f127a7ca3 100644 --- a/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts @@ -100,3 +100,7 @@ &sata_phy { status = "okay"; }; + +&sdhci0 { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm97360svmb.dts b/arch/mips/boot/dts/brcm/bcm97360svmb.dts index 496e6ed9fae30..bed821b030139 100644 --- a/arch/mips/boot/dts/brcm/bcm97360svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97360svmb.dts @@ -68,3 +68,7 @@ &sata_phy { status = "okay"; }; + +&sdhci0 { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm97362svmb.dts b/arch/mips/boot/dts/brcm/bcm97362svmb.dts index b880c018f3d8f..1b9bc4b2d9ae6 100644 --- a/arch/mips/boot/dts/brcm/bcm97362svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97362svmb.dts @@ -64,3 +64,7 @@ &sata_phy { status = "okay"; }; + +&sdhci0 { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm97425svmb.dts b/arch/mips/boot/dts/brcm/bcm97425svmb.dts index f091e91b11c53..1c6b74daef564 100644 --- a/arch/mips/boot/dts/brcm/bcm97425svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97425svmb.dts @@ -94,3 +94,11 @@ &ohci3 { status = "okay"; }; + +&sdhci0 { + status = "okay"; +}; + +&sdhci1 { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm97435svmb.dts b/arch/mips/boot/dts/brcm/bcm97435svmb.dts index 9db84f2a66644..64bb1988dbc83 100644 --- a/arch/mips/boot/dts/brcm/bcm97435svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97435svmb.dts @@ -102,3 +102,11 @@ &sata_phy { status = "okay"; }; + +&sdhci0 { + status = "okay"; +}; + +&sdhci1 { + status = "okay"; +}; -- GitLab From cfc8be04c36a1a6546b6f9cb8f02fd9f215c9d38 Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Fri, 19 Aug 2016 11:52:29 +0900 Subject: [PATCH 0318/1167] MIPS: BMIPS: Add support NAND device nodes Adds NAND device nodes to BCM7xxx MIPS based SoCs. Signed-off-by: Jaedon Shin Cc: Florian Fainelli Cc: Jonas Gorski Cc: Kevin Cernekee Cc: Rob Herring Cc: MIPS Mailing List Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14003/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/brcm/bcm7346.dtsi | 20 +++++++++++++++ arch/mips/boot/dts/brcm/bcm7358.dtsi | 20 +++++++++++++++ arch/mips/boot/dts/brcm/bcm7360.dtsi | 20 +++++++++++++++ arch/mips/boot/dts/brcm/bcm7362.dtsi | 20 +++++++++++++++ arch/mips/boot/dts/brcm/bcm7425.dtsi | 20 +++++++++++++++ arch/mips/boot/dts/brcm/bcm7435.dtsi | 20 +++++++++++++++ arch/mips/boot/dts/brcm/bcm97346dbsmb.dts | 5 ++++ arch/mips/boot/dts/brcm/bcm97358svmb.dts | 5 ++++ arch/mips/boot/dts/brcm/bcm97362svmb.dts | 5 ++++ arch/mips/boot/dts/brcm/bcm97425svmb.dts | 5 ++++ arch/mips/boot/dts/brcm/bcm97435svmb.dts | 5 ++++ .../dts/brcm/bcm97xxx-nand-cs1-bch24.dtsi | 25 +++++++++++++++++++ .../boot/dts/brcm/bcm97xxx-nand-cs1-bch4.dtsi | 25 +++++++++++++++++++ 13 files changed, 195 insertions(+) create mode 100644 arch/mips/boot/dts/brcm/bcm97xxx-nand-cs1-bch24.dtsi create mode 100644 arch/mips/boot/dts/brcm/bcm97xxx-nand-cs1-bch4.dtsi diff --git a/arch/mips/boot/dts/brcm/bcm7346.dtsi b/arch/mips/boot/dts/brcm/bcm7346.dtsi index 0da4f8a3744b2..72d9cffa8927f 100644 --- a/arch/mips/boot/dts/brcm/bcm7346.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7346.dtsi @@ -372,6 +372,26 @@ status = "disabled"; }; + hif_l2_intc: interrupt-controller@411000 { + compatible = "brcm,l2-intc"; + reg = <0x411000 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <30>; + }; + + nand: nand@412800 { + compatible = "brcm,brcmnand-v5.0", "brcm,brcmnand"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "nand"; + reg = <0x412800 0x400>; + interrupt-parent = <&hif_l2_intc>; + interrupts = <24>; + status = "disabled"; + }; + sata: sata@181000 { compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci"; reg-names = "ahci", "top-ctrl"; diff --git a/arch/mips/boot/dts/brcm/bcm7358.dtsi b/arch/mips/boot/dts/brcm/bcm7358.dtsi index aec1b2e7e2ab7..7f78bfab164be 100644 --- a/arch/mips/boot/dts/brcm/bcm7358.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7358.dtsi @@ -298,5 +298,25 @@ interrupts = <66>; status = "disabled"; }; + + hif_l2_intc: interrupt-controller@411000 { + compatible = "brcm,l2-intc"; + reg = <0x411000 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <30>; + }; + + nand: nand@412800 { + compatible = "brcm,brcmnand-v5.0", "brcm,brcmnand"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "nand"; + reg = <0x412800 0x400>; + interrupt-parent = <&hif_l2_intc>; + interrupts = <24>; + status = "disabled"; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm7360.dtsi b/arch/mips/boot/dts/brcm/bcm7360.dtsi index 9f72d34904279..64b9fd90941d2 100644 --- a/arch/mips/boot/dts/brcm/bcm7360.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7360.dtsi @@ -291,6 +291,26 @@ status = "disabled"; }; + hif_l2_intc: interrupt-controller@411000 { + compatible = "brcm,l2-intc"; + reg = <0x411000 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <30>; + }; + + nand: nand@412800 { + compatible = "brcm,brcmnand-v5.0", "brcm,brcmnand"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "nand"; + reg = <0x412800 0x400>; + interrupt-parent = <&hif_l2_intc>; + interrupts = <24>; + status = "disabled"; + }; + sata: sata@181000 { compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci"; reg-names = "ahci", "top-ctrl"; diff --git a/arch/mips/boot/dts/brcm/bcm7362.dtsi b/arch/mips/boot/dts/brcm/bcm7362.dtsi index ff734f45df92a..784d587252274 100644 --- a/arch/mips/boot/dts/brcm/bcm7362.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7362.dtsi @@ -287,6 +287,26 @@ status = "disabled"; }; + hif_l2_intc: interrupt-controller@411000 { + compatible = "brcm,l2-intc"; + reg = <0x411000 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <30>; + }; + + nand: nand@412800 { + compatible = "brcm,brcmnand-v5.0", "brcm,brcmnand"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "nand"; + reg = <0x412800 0x400>; + interrupt-parent = <&hif_l2_intc>; + interrupts = <24>; + status = "disabled"; + }; + sata: sata@181000 { compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci"; reg-names = "ahci", "top-ctrl"; diff --git a/arch/mips/boot/dts/brcm/bcm7425.dtsi b/arch/mips/boot/dts/brcm/bcm7425.dtsi index 1c8d3b4033a04..7124c98224793 100644 --- a/arch/mips/boot/dts/brcm/bcm7425.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7425.dtsi @@ -371,6 +371,26 @@ status = "disabled"; }; + hif_l2_intc: interrupt-controller@41a000 { + compatible = "brcm,l2-intc"; + reg = <0x41a000 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <24>; + }; + + nand: nand@41b800 { + compatible = "brcm,brcmnand-v5.0", "brcm,brcmnand"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "nand"; + reg = <0x41b800 0x400>; + interrupt-parent = <&hif_l2_intc>; + interrupts = <24>; + status = "disabled"; + }; + sata: sata@181000 { compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci"; reg-names = "ahci", "top-ctrl"; diff --git a/arch/mips/boot/dts/brcm/bcm7435.dtsi b/arch/mips/boot/dts/brcm/bcm7435.dtsi index 2b28d91762ef2..a3648964be3a0 100644 --- a/arch/mips/boot/dts/brcm/bcm7435.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7435.dtsi @@ -386,6 +386,26 @@ status = "disabled"; }; + hif_l2_intc: interrupt-controller@41b000 { + compatible = "brcm,l2-intc"; + reg = <0x41b000 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&periph_intc>; + interrupts = <24>; + }; + + nand: nand@41c800 { + compatible = "brcm,brcmnand-v6.2", "brcm,brcmnand"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "nand", "flash-dma"; + reg = <0x41c800 0x600>, <0x41d000 0x100>; + interrupt-parent = <&hif_l2_intc>; + interrupts = <24>, <4>; + status = "disabled"; + }; + sata: sata@181000 { compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci"; reg-names = "ahci", "top-ctrl"; diff --git a/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts b/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts index 27c9f127a7ca3..e67eaf30de3d1 100644 --- a/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts @@ -1,6 +1,7 @@ /dts-v1/; /include/ "bcm7346.dtsi" +/include/ "bcm97xxx-nand-cs1-bch24.dtsi" / { compatible = "brcm,bcm97346dbsmb", "brcm,bcm7346"; @@ -93,6 +94,10 @@ status = "okay"; }; +&nand { + status = "okay"; +}; + &sata { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97358svmb.dts b/arch/mips/boot/dts/brcm/bcm97358svmb.dts index 757fe9d5f4dff..ee4607fae47ac 100644 --- a/arch/mips/boot/dts/brcm/bcm97358svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97358svmb.dts @@ -1,6 +1,7 @@ /dts-v1/; /include/ "bcm7358.dtsi" +/include/ "bcm97xxx-nand-cs1-bch4.dtsi" / { compatible = "brcm,bcm97358svmb", "brcm,bcm7358"; @@ -64,3 +65,7 @@ &ohci0 { status = "okay"; }; + +&nand { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm97362svmb.dts b/arch/mips/boot/dts/brcm/bcm97362svmb.dts index 1b9bc4b2d9ae6..68fd823868e07 100644 --- a/arch/mips/boot/dts/brcm/bcm97362svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97362svmb.dts @@ -1,6 +1,7 @@ /dts-v1/; /include/ "bcm7362.dtsi" +/include/ "bcm97xxx-nand-cs1-bch4.dtsi" / { compatible = "brcm,bcm97362svmb", "brcm,bcm7362"; @@ -57,6 +58,10 @@ status = "okay"; }; +&nand { + status = "okay"; +}; + &sata { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97425svmb.dts b/arch/mips/boot/dts/brcm/bcm97425svmb.dts index 1c6b74daef564..f95ba1bf3e580 100644 --- a/arch/mips/boot/dts/brcm/bcm97425svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97425svmb.dts @@ -1,6 +1,7 @@ /dts-v1/; /include/ "bcm7425.dtsi" +/include/ "bcm97xxx-nand-cs1-bch24.dtsi" / { compatible = "brcm,bcm97425svmb", "brcm,bcm7425"; @@ -95,6 +96,10 @@ status = "okay"; }; +&nand { + status = "okay"; +}; + &sdhci0 { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97435svmb.dts b/arch/mips/boot/dts/brcm/bcm97435svmb.dts index 64bb1988dbc83..fb37b7111bf4f 100644 --- a/arch/mips/boot/dts/brcm/bcm97435svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97435svmb.dts @@ -1,6 +1,7 @@ /dts-v1/; /include/ "bcm7435.dtsi" +/include/ "bcm97xxx-nand-cs1-bch24.dtsi" / { compatible = "brcm,bcm97435svmb", "brcm,bcm7435"; @@ -95,6 +96,10 @@ status = "okay"; }; +&nand { + status = "okay"; +}; + &sata { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97xxx-nand-cs1-bch24.dtsi b/arch/mips/boot/dts/brcm/bcm97xxx-nand-cs1-bch24.dtsi new file mode 100644 index 0000000000000..3c24f97de9223 --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm97xxx-nand-cs1-bch24.dtsi @@ -0,0 +1,25 @@ +&nand { + nandcs@1 { + compatible = "brcm,nandcs"; + reg = <1>; + nand-on-flash-bbt; + + nand-ecc-strength = <24>; + nand-ecc-step-size = <1024>; + brcm,nand-oob-sector-size = <27>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + flash1.rootfs@0 { + reg = <0x0 0x10000000>; + }; + + flash1.kernel@10000000 { + reg = <0x10000000 0x400000>; + }; + }; + }; +}; diff --git a/arch/mips/boot/dts/brcm/bcm97xxx-nand-cs1-bch4.dtsi b/arch/mips/boot/dts/brcm/bcm97xxx-nand-cs1-bch4.dtsi new file mode 100644 index 0000000000000..cb531816ef4ce --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm97xxx-nand-cs1-bch4.dtsi @@ -0,0 +1,25 @@ +&nand { + nandcs@1 { + compatible = "brcm,nandcs"; + reg = <1>; + nand-on-flash-bbt; + + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + brcm,nand-oob-sector-size = <16>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + flash1.rootfs@0 { + reg = <0x0 0x10000000>; + }; + + flash1.kernel@10000000 { + reg = <0x10000000 0x400000>; + }; + }; + }; +}; -- GitLab From a2c510a2d0418ce15cd739d0a177ce53b06e5695 Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Fri, 19 Aug 2016 11:52:30 +0900 Subject: [PATCH 0319/1167] MIPS: BMIPS: Use interrupt-controller node name Changes node names of the interrupt-controller device nodes to interrupt-controller instead of label strings. Signed-off-by: Jaedon Shin Cc: Florian Fainelli Cc: Jonas Gorski Cc: Kevin Cernekee Cc: Rob Herring Cc: MIPS Mailing List Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14004/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/brcm/bcm7125.dtsi | 8 ++++---- arch/mips/boot/dts/brcm/bcm7346.dtsi | 10 +++++----- arch/mips/boot/dts/brcm/bcm7358.dtsi | 10 +++++----- arch/mips/boot/dts/brcm/bcm7360.dtsi | 10 +++++----- arch/mips/boot/dts/brcm/bcm7362.dtsi | 10 +++++----- arch/mips/boot/dts/brcm/bcm7420.dtsi | 8 ++++---- arch/mips/boot/dts/brcm/bcm7425.dtsi | 10 +++++----- arch/mips/boot/dts/brcm/bcm7435.dtsi | 10 +++++----- 8 files changed, 38 insertions(+), 38 deletions(-) diff --git a/arch/mips/boot/dts/brcm/bcm7125.dtsi b/arch/mips/boot/dts/brcm/bcm7125.dtsi index 746ed06c85de6..bbd00f65ce397 100644 --- a/arch/mips/boot/dts/brcm/bcm7125.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7125.dtsi @@ -26,7 +26,7 @@ uart0 = &uart0; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -55,7 +55,7 @@ compatible = "simple-bus"; ranges = <0 0x10000000 0x01000000>; - periph_intc: periph_intc@441400 { + periph_intc: interrupt-controller@441400 { compatible = "brcm,bcm7038-l1-intc"; reg = <0x441400 0x30>, <0x441600 0x30>; @@ -66,7 +66,7 @@ interrupts = <2>, <3>; }; - sun_l2_intc: sun_l2_intc@401800 { + sun_l2_intc: interrupt-controller@401800 { compatible = "brcm,l2-intc"; reg = <0x401800 0x30>; interrupt-controller; @@ -87,7 +87,7 @@ "avd_0", "jtag_0"; }; - upg_irq0_intc: upg_irq0_intc@406780 { + upg_irq0_intc: interrupt-controller@406780 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; diff --git a/arch/mips/boot/dts/brcm/bcm7346.dtsi b/arch/mips/boot/dts/brcm/bcm7346.dtsi index 72d9cffa8927f..4bbcc95f1c15d 100644 --- a/arch/mips/boot/dts/brcm/bcm7346.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7346.dtsi @@ -26,7 +26,7 @@ uart0 = &uart0; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -55,7 +55,7 @@ compatible = "simple-bus"; ranges = <0 0x10000000 0x01000000>; - periph_intc: periph_intc@411400 { + periph_intc: interrupt-controller@411400 { compatible = "brcm,bcm7038-l1-intc"; reg = <0x411400 0x30>, <0x411600 0x30>; @@ -66,7 +66,7 @@ interrupts = <2>, <3>; }; - sun_l2_intc: sun_l2_intc@403000 { + sun_l2_intc: interrupt-controller@403000 { compatible = "brcm,l2-intc"; reg = <0x403000 0x30>; interrupt-controller; @@ -87,7 +87,7 @@ "jtag_0", "svd_0"; }; - upg_irq0_intc: upg_irq0_intc@406780 { + upg_irq0_intc: interrupt-controller@406780 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; @@ -102,7 +102,7 @@ interrupt-names = "upg_main", "upg_bsc"; }; - upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { + upg_aon_irq0_intc: interrupt-controller@408b80 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x408b80 0x8>; diff --git a/arch/mips/boot/dts/brcm/bcm7358.dtsi b/arch/mips/boot/dts/brcm/bcm7358.dtsi index 7f78bfab164be..3e42535c8d290 100644 --- a/arch/mips/boot/dts/brcm/bcm7358.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7358.dtsi @@ -20,7 +20,7 @@ uart0 = &uart0; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -49,7 +49,7 @@ compatible = "simple-bus"; ranges = <0 0x10000000 0x01000000>; - periph_intc: periph_intc@411400 { + periph_intc: interrupt-controller@411400 { compatible = "brcm,bcm7038-l1-intc"; reg = <0x411400 0x30>; @@ -60,7 +60,7 @@ interrupts = <2>; }; - sun_l2_intc: sun_l2_intc@403000 { + sun_l2_intc: interrupt-controller@403000 { compatible = "brcm,l2-intc"; reg = <0x403000 0x30>; interrupt-controller; @@ -81,7 +81,7 @@ "avd_0", "jtag_0"; }; - upg_irq0_intc: upg_irq0_intc@406600 { + upg_irq0_intc: interrupt-controller@406600 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x406600 0x8>; @@ -96,7 +96,7 @@ interrupt-names = "upg_main", "upg_bsc"; }; - upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { + upg_aon_irq0_intc: interrupt-controller@408b80 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x408b80 0x8>; diff --git a/arch/mips/boot/dts/brcm/bcm7360.dtsi b/arch/mips/boot/dts/brcm/bcm7360.dtsi index 64b9fd90941d2..112a5571c5961 100644 --- a/arch/mips/boot/dts/brcm/bcm7360.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7360.dtsi @@ -20,7 +20,7 @@ uart0 = &uart0; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -49,7 +49,7 @@ compatible = "simple-bus"; ranges = <0 0x10000000 0x01000000>; - periph_intc: periph_intc@411400 { + periph_intc: interrupt-controller@411400 { compatible = "brcm,bcm7038-l1-intc"; reg = <0x411400 0x30>; @@ -60,7 +60,7 @@ interrupts = <2>; }; - sun_l2_intc: sun_l2_intc@403000 { + sun_l2_intc: interrupt-controller@403000 { compatible = "brcm,l2-intc"; reg = <0x403000 0x30>; interrupt-controller; @@ -81,7 +81,7 @@ "avd_0", "jtag_0"; }; - upg_irq0_intc: upg_irq0_intc@406600 { + upg_irq0_intc: interrupt-controller@406600 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x406600 0x8>; @@ -96,7 +96,7 @@ interrupt-names = "upg_main", "upg_bsc"; }; - upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { + upg_aon_irq0_intc: interrupt-controller@408b80 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x408b80 0x8>; diff --git a/arch/mips/boot/dts/brcm/bcm7362.dtsi b/arch/mips/boot/dts/brcm/bcm7362.dtsi index 784d587252274..34abfb0b07e79 100644 --- a/arch/mips/boot/dts/brcm/bcm7362.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7362.dtsi @@ -26,7 +26,7 @@ uart0 = &uart0; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -55,7 +55,7 @@ compatible = "simple-bus"; ranges = <0 0x10000000 0x01000000>; - periph_intc: periph_intc@411400 { + periph_intc: interrupt-controller@411400 { compatible = "brcm,bcm7038-l1-intc"; reg = <0x411400 0x30>, <0x411600 0x30>; @@ -66,7 +66,7 @@ interrupts = <2>, <3>; }; - sun_l2_intc: sun_l2_intc@403000 { + sun_l2_intc: interrupt-controller@403000 { compatible = "brcm,l2-intc"; reg = <0x403000 0x30>; interrupt-controller; @@ -87,7 +87,7 @@ "avd_0", "jtag_0"; }; - upg_irq0_intc: upg_irq0_intc@406600 { + upg_irq0_intc: interrupt-controller@406600 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x406600 0x8>; @@ -102,7 +102,7 @@ interrupt-names = "upg_main", "upg_bsc"; }; - upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { + upg_aon_irq0_intc: interrupt-controller@408b80 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x408b80 0x8>; diff --git a/arch/mips/boot/dts/brcm/bcm7420.dtsi b/arch/mips/boot/dts/brcm/bcm7420.dtsi index 0d391d77c7802..b143723c674e8 100644 --- a/arch/mips/boot/dts/brcm/bcm7420.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7420.dtsi @@ -26,7 +26,7 @@ uart0 = &uart0; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -55,7 +55,7 @@ compatible = "simple-bus"; ranges = <0 0x10000000 0x01000000>; - periph_intc: periph_intc@441400 { + periph_intc: interrupt-controller@441400 { compatible = "brcm,bcm7038-l1-intc"; reg = <0x441400 0x30>, <0x441600 0x30>; @@ -66,7 +66,7 @@ interrupts = <2>, <3>; }; - sun_l2_intc: sun_l2_intc@401800 { + sun_l2_intc: interrupt-controller@401800 { compatible = "brcm,l2-intc"; reg = <0x401800 0x30>; interrupt-controller; @@ -88,7 +88,7 @@ "jtag_0"; }; - upg_irq0_intc: upg_irq0_intc@406780 { + upg_irq0_intc: interrupt-controller@406780 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; diff --git a/arch/mips/boot/dts/brcm/bcm7425.dtsi b/arch/mips/boot/dts/brcm/bcm7425.dtsi index 7124c98224793..2488d2f61f601 100644 --- a/arch/mips/boot/dts/brcm/bcm7425.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7425.dtsi @@ -26,7 +26,7 @@ uart0 = &uart0; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -55,7 +55,7 @@ compatible = "simple-bus"; ranges = <0 0x10000000 0x01000000>; - periph_intc: periph_intc@41a400 { + periph_intc: interrupt-controller@41a400 { compatible = "brcm,bcm7038-l1-intc"; reg = <0x41a400 0x30>, <0x41a600 0x30>; @@ -66,7 +66,7 @@ interrupts = <2>, <3>; }; - sun_l2_intc: sun_l2_intc@403000 { + sun_l2_intc: interrupt-controller@403000 { compatible = "brcm,l2-intc"; reg = <0x403000 0x30>; interrupt-controller; @@ -89,7 +89,7 @@ "vice_0"; }; - upg_irq0_intc: upg_irq0_intc@406780 { + upg_irq0_intc: interrupt-controller@406780 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; @@ -104,7 +104,7 @@ interrupt-names = "upg_main", "upg_bsc"; }; - upg_aon_irq0_intc: upg_aon_irq0_intc@409480 { + upg_aon_irq0_intc: interrupt-controller@409480 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x409480 0x8>; diff --git a/arch/mips/boot/dts/brcm/bcm7435.dtsi b/arch/mips/boot/dts/brcm/bcm7435.dtsi index a3648964be3a0..19fa259b968b3 100644 --- a/arch/mips/boot/dts/brcm/bcm7435.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7435.dtsi @@ -38,7 +38,7 @@ uart0 = &uart0; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -67,7 +67,7 @@ compatible = "simple-bus"; ranges = <0 0x10000000 0x01000000>; - periph_intc: periph_intc@41b500 { + periph_intc: interrupt-controller@41b500 { compatible = "brcm,bcm7038-l1-intc"; reg = <0x41b500 0x40>, <0x41b600 0x40>, <0x41b700 0x40>, <0x41b800 0x40>; @@ -79,7 +79,7 @@ interrupts = <2>, <3>, <2>, <3>; }; - sun_l2_intc: sun_l2_intc@403000 { + sun_l2_intc: interrupt-controller@403000 { compatible = "brcm,l2-intc"; reg = <0x403000 0x30>; interrupt-controller; @@ -104,7 +104,7 @@ "scpu"; }; - upg_irq0_intc: upg_irq0_intc@406780 { + upg_irq0_intc: interrupt-controller@406780 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; @@ -119,7 +119,7 @@ interrupt-names = "upg_main", "upg_bsc"; }; - upg_aon_irq0_intc: upg_aon_irq0_intc@409480 { + upg_aon_irq0_intc: interrupt-controller@409480 { compatible = "brcm,bcm7120-l2-intc"; reg = <0x409480 0x8>; -- GitLab From d66698e0834657161314050b6c99c3eba36b180a Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Fri, 30 Sep 2016 23:17:34 +0900 Subject: [PATCH 0320/1167] MIPS: BMIPS: Support APPENDED_DTB Use appended DTB when available. Signed-off-by: Jaedon Shin Cc: Kevin Cernekee Cc: Florian Fainelli Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14337/ Signed-off-by: Ralf Baechle --- arch/mips/bmips/setup.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index edf1b31df10b5..3b6f687f177cd 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -152,6 +153,8 @@ void __init plat_time_init(void) mips_hpt_frequency = freq; } +extern const char __appended_dtb; + void __init plat_mem_setup(void) { void *dtb; @@ -161,6 +164,11 @@ void __init plat_mem_setup(void) ioport_resource.start = 0; ioport_resource.end = ~0; +#ifdef CONFIG_MIPS_ELF_APPENDED_DTB + if (!fdt_check_header(&__appended_dtb)) + dtb = (void *)&__appended_dtb; + else +#endif /* intended to somewhat resemble ARM; see Documentation/arm/Booting */ if (fw_arg0 == 0 && fw_arg1 == 0xffffffff) dtb = phys_to_virt(fw_arg2); -- GitLab From e3031b32840c1bee228c58bb284ebc05f97249c7 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Fri, 30 Sep 2016 11:33:45 +0200 Subject: [PATCH 0321/1167] MIPS: tracing: move insn_has_delay_slot to a shared header Currently both kprobes and uprobes code have definitions of the insn_has_delay_slot method. Move it to a separate header as an inline method that each probe-specific method can later use. No functional change intended, although the methods slightly varied in the constraints they set for the methods - the uprobes one was chosen as it is slightly more specific when filtering opcode fields. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14335/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/kprobes.c | 61 ++---------------------- arch/mips/kernel/probes-common.h | 81 ++++++++++++++++++++++++++++++++ arch/mips/kernel/uprobes.c | 65 ++----------------------- 3 files changed, 87 insertions(+), 120 deletions(-) create mode 100644 arch/mips/kernel/probes-common.h diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c index 212f46f2014e0..747e3bf7bd9f7 100644 --- a/arch/mips/kernel/kprobes.c +++ b/arch/mips/kernel/kprobes.c @@ -32,7 +32,8 @@ #include #include #include -#include + +#include "probes-common.h" static const union mips_instruction breakpoint_insn = { .b_format = { @@ -55,63 +56,7 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); static int __kprobes insn_has_delayslot(union mips_instruction insn) { - switch (insn.i_format.opcode) { - - /* - * This group contains: - * jr and jalr are in r_format format. - */ - case spec_op: - switch (insn.r_format.func) { - case jr_op: - case jalr_op: - break; - default: - goto insn_ok; - } - - /* - * This group contains: - * bltz_op, bgez_op, bltzl_op, bgezl_op, - * bltzal_op, bgezal_op, bltzall_op, bgezall_op. - */ - case bcond_op: - - /* - * These are unconditional and in j_format. - */ - case jal_op: - case j_op: - - /* - * These are conditional and in i_format. - */ - case beq_op: - case beql_op: - case bne_op: - case bnel_op: - case blez_op: - case blezl_op: - case bgtz_op: - case bgtzl_op: - - /* - * These are the FPA/cp1 branch instructions. - */ - case cop1_op: - -#ifdef CONFIG_CPU_CAVIUM_OCTEON - case lwc2_op: /* This is bbit0 on Octeon */ - case ldc2_op: /* This is bbit032 on Octeon */ - case swc2_op: /* This is bbit1 on Octeon */ - case sdc2_op: /* This is bbit132 on Octeon */ -#endif - return 1; - default: - break; - } -insn_ok: - return 0; + return __insn_has_delay_slot(insn); } /* diff --git a/arch/mips/kernel/probes-common.h b/arch/mips/kernel/probes-common.h new file mode 100644 index 0000000000000..c979c3790e4c5 --- /dev/null +++ b/arch/mips/kernel/probes-common.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Marcin Nowakowski + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __PROBES_COMMON_H +#define __PROBES_COMMON_H + +#include + +static inline int __insn_has_delay_slot(const union mips_instruction insn) +{ + switch (insn.i_format.opcode) { + /* + * jr and jalr are in r_format format. + */ + case spec_op: + switch (insn.r_format.func) { + case jalr_op: + case jr_op: + return 1; + } + break; + + /* + * This group contains: + * bltz_op, bgez_op, bltzl_op, bgezl_op, + * bltzal_op, bgezal_op, bltzall_op, bgezall_op. + */ + case bcond_op: + switch (insn.i_format.rt) { + case bltz_op: + case bltzl_op: + case bgez_op: + case bgezl_op: + case bltzal_op: + case bltzall_op: + case bgezal_op: + case bgezall_op: + case bposge32_op: + return 1; + } + break; + + /* + * These are unconditional and in j_format. + */ + case jal_op: + case j_op: + case beq_op: + case beql_op: + case bne_op: + case bnel_op: + case blez_op: /* not really i_format */ + case blezl_op: + case bgtz_op: + case bgtzl_op: + return 1; + + /* + * And now the FPA/cp1 branch instructions. + */ + case cop1_op: +#ifdef CONFIG_CPU_CAVIUM_OCTEON + case lwc2_op: /* This is bbit0 on Octeon */ + case ldc2_op: /* This is bbit032 on Octeon */ + case swc2_op: /* This is bbit1 on Octeon */ + case sdc2_op: /* This is bbit132 on Octeon */ +#endif + return 1; + } + + return 0; +} + +#endif /* __PROBES_COMMON_H */ diff --git a/arch/mips/kernel/uprobes.c b/arch/mips/kernel/uprobes.c index 15ad17cb2b6e4..1161c93a74cba 100644 --- a/arch/mips/kernel/uprobes.c +++ b/arch/mips/kernel/uprobes.c @@ -8,71 +8,12 @@ #include #include #include -#include + +#include "probes-common.h" static inline int insn_has_delay_slot(const union mips_instruction insn) { - switch (insn.i_format.opcode) { - /* - * jr and jalr are in r_format format. - */ - case spec_op: - switch (insn.r_format.func) { - case jalr_op: - case jr_op: - return 1; - } - break; - - /* - * This group contains: - * bltz_op, bgez_op, bltzl_op, bgezl_op, - * bltzal_op, bgezal_op, bltzall_op, bgezall_op. - */ - case bcond_op: - switch (insn.i_format.rt) { - case bltz_op: - case bltzl_op: - case bgez_op: - case bgezl_op: - case bltzal_op: - case bltzall_op: - case bgezal_op: - case bgezall_op: - case bposge32_op: - return 1; - } - break; - - /* - * These are unconditional and in j_format. - */ - case jal_op: - case j_op: - case beq_op: - case beql_op: - case bne_op: - case bnel_op: - case blez_op: /* not really i_format */ - case blezl_op: - case bgtz_op: - case bgtzl_op: - return 1; - - /* - * And now the FPA/cp1 branch instructions. - */ - case cop1_op: -#ifdef CONFIG_CPU_CAVIUM_OCTEON - case lwc2_op: /* This is bbit0 on Octeon */ - case ldc2_op: /* This is bbit032 on Octeon */ - case swc2_op: /* This is bbit1 on Octeon */ - case sdc2_op: /* This is bbit132 on Octeon */ -#endif - return 1; - } - - return 0; + return __insn_has_delay_slot(insn); } /** -- GitLab From d05c513069f15be5de766026a4192998688ffff1 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Fri, 30 Sep 2016 11:33:46 +0200 Subject: [PATCH 0322/1167] MIPS: tracing: disable uprobe/kprobe on compact branch instructions Current instruction decoder for uprobe/kprobe handler only handles branches with delay slots. For compact branches the behaviour is rather unpredictable - and depending on the encoding of a compact branch instruction may result in one (or more) of: - executing an instruction that follows a branch which wasn't in a delay slot and shouldn't have been executed - incorrectly emulating a branch leading to a jump to a wrong location - unexpected branching out of the single-stepped code and never reaching the breakpoint that should terminate the probe handler Results of these actions are generally unpredictable, but can end up with a probed application or kernel crash, so disable placing probes on compact branches until they are handled properly. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14336/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/branch.c | 34 ++++++++++++++++++++++++++++++++ arch/mips/kernel/kprobes.c | 6 ++++++ arch/mips/kernel/probes-common.h | 2 ++ arch/mips/kernel/uprobes.c | 6 ++++++ 4 files changed, 48 insertions(+) diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index f5c68483c98ea..12c718181e5e3 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -866,3 +866,37 @@ int __compute_return_epc(struct pt_regs *regs) force_sig(SIGBUS, current); return -EFAULT; } + +#if (defined CONFIG_KPROBES) || (defined CONFIG_UPROBES) + +int __insn_is_compact_branch(union mips_instruction insn) +{ + if (!cpu_has_mips_r6) + return 0; + + switch (insn.i_format.opcode) { + case blezl_op: + case bgtzl_op: + case blez_op: + case bgtz_op: + /* + * blez[l] and bgtz[l] opcodes with non-zero rt + * are MIPS R6 compact branches + */ + if (insn.i_format.rt) + return 1; + break; + case bc6_op: + case balc6_op: + case pop10_op: + case pop30_op: + case pop66_op: + case pop76_op: + return 1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(__insn_is_compact_branch); + +#endif /* CONFIG_KPROBES || CONFIG_UPROBES */ diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c index 747e3bf7bd9f7..f5c8bce70db29 100644 --- a/arch/mips/kernel/kprobes.c +++ b/arch/mips/kernel/kprobes.c @@ -106,6 +106,12 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) goto out; } + if (__insn_is_compact_branch(insn)) { + pr_notice("Kprobes for compact branches are not supported\n"); + ret = -EINVAL; + goto out; + } + /* insn: must be on special executable page on mips. */ p->ainsn.insn = get_insn_slot(); if (!p->ainsn.insn) { diff --git a/arch/mips/kernel/probes-common.h b/arch/mips/kernel/probes-common.h index c979c3790e4c5..dd08e41134b66 100644 --- a/arch/mips/kernel/probes-common.h +++ b/arch/mips/kernel/probes-common.h @@ -13,6 +13,8 @@ #include +int __insn_is_compact_branch(union mips_instruction insn); + static inline int __insn_has_delay_slot(const union mips_instruction insn) { switch (insn.i_format.opcode) { diff --git a/arch/mips/kernel/uprobes.c b/arch/mips/kernel/uprobes.c index 1161c93a74cba..dbb9174031314 100644 --- a/arch/mips/kernel/uprobes.c +++ b/arch/mips/kernel/uprobes.c @@ -36,6 +36,12 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *aup, return -EINVAL; inst.word = aup->insn[0]; + + if (__insn_is_compact_branch(inst)) { + pr_notice("Uprobes for compact branches are not supported\n"); + return -EINVAL; + } + aup->ixol[0] = aup->insn[insn_has_delay_slot(inst)]; aup->ixol[1] = UPROBE_BRK_UPROBE_XOL; /* NOP */ -- GitLab From 23dac14d058fcd7cb2b4e6389139ca065855afe7 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:07 +0100 Subject: [PATCH 0323/1167] MIPS: PCI: Use struct list_head lists Rather than open-coding a linked list implementation, make use of the one in linux/list.h. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14340/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pci.h | 3 ++- arch/mips/pci/pci.c | 9 ++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index 9b63cd41213de..547e113ac0fea 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -17,6 +17,7 @@ */ #include +#include #include /* @@ -25,7 +26,7 @@ * single controller supporting multiple channels. */ struct pci_controller { - struct pci_controller *next; + struct list_head list; struct pci_bus *bus; struct device_node *of_node; diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index b4c02f29663e1..644ae9696edd9 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -28,8 +28,7 @@ /* * The PCI controller list. */ - -static struct pci_controller *hose_head, **hose_tail = &hose_head; +static LIST_HEAD(controllers); unsigned long PCIBIOS_MIN_IO; unsigned long PCIBIOS_MIN_MEM; @@ -193,8 +192,8 @@ void register_pci_controller(struct pci_controller *hose) goto out; } - *hose_tail = hose; - hose_tail = &hose->next; + INIT_LIST_HEAD(&hose->list); + list_add(&hose->list, &controllers); /* * Do not panic here but later - this might happen before console init. @@ -248,7 +247,7 @@ static int __init pcibios_init(void) pcibios_set_cache_line_size(); /* Scan all of the recorded PCI controllers. */ - for (hose = hose_head; hose; hose = hose->next) + list_for_each_entry(hose, &controllers, list) pcibios_scanbus(hose); pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq); -- GitLab From 88555b481958083b1b928a4ba5c6e3bc606ce34b Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:08 +0100 Subject: [PATCH 0324/1167] MIPS: PCI: Support for CONFIG_PCI_DOMAINS_GENERIC Introduce support for CONFIG_PCI_DOMAINS_GENERIC, allowing for platforms to make use of generic PCI domains instead of the MIPS-specific implementation. The set_pci_need_domain_info function is introduced to abstract away the removed need_domain_info field in struct pci_controller, and pcibios_scanbus is adjusted to use the pci_domain_nr accessor instead of directly accessing the index field. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14341/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 3 +++ arch/mips/include/asm/pci.h | 21 ++++++++++++++++++++- arch/mips/pci/pci.c | 4 ++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 400cd3695ecc8..7a75215aabac0 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2995,6 +2995,9 @@ config HT_PCI config PCI_DOMAINS bool +config PCI_DOMAINS_GENERIC + bool + source "drivers/pci/Kconfig" # diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index 547e113ac0fea..0564692c7d3bc 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -39,10 +39,12 @@ struct pci_controller { struct resource *busn_resource; unsigned long busn_offset; +#ifndef CONFIG_PCI_DOMAINS_GENERIC unsigned int index; /* For compatibility with current (as of July 2003) pciutils and XFree86. Eventually will be removed. */ unsigned int need_domain_info; +#endif /* Optional access methods for reading/writing the bus number of the PCI controller */ @@ -101,7 +103,18 @@ struct pci_dev; */ #define PCI_DMA_BUS_IS_PHYS (1) -#ifdef CONFIG_PCI_DOMAINS +#ifdef CONFIG_PCI_DOMAINS_GENERIC +static inline int pci_proc_domain(struct pci_bus *bus) +{ + return pci_domain_nr(bus); +} + +static inline void set_pci_need_domain_info(struct pci_controller *hose, + int need_domain_info) +{ + /* nothing to do */ +} +#elif defined(CONFIG_PCI_DOMAINS) #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index static inline int pci_proc_domain(struct pci_bus *bus) @@ -109,6 +122,12 @@ static inline int pci_proc_domain(struct pci_bus *bus) struct pci_controller *hose = bus->sysdata; return hose->need_domain_info; } + +static inline void set_pci_need_domain_info(struct pci_controller *hose, + int need_domain_info) +{ + hose->need_domain_info = need_domain_info; +} #endif /* CONFIG_PCI_DOMAINS */ #endif /* __KERNEL__ */ diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index 644ae9696edd9..5207c043c69c4 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -95,8 +95,8 @@ static void pcibios_scanbus(struct pci_controller *hose) &resources); hose->bus = bus; - need_domain_info = need_domain_info || hose->index; - hose->need_domain_info = need_domain_info; + need_domain_info = need_domain_info || pci_domain_nr(bus); + set_pci_need_domain_info(hose, need_domain_info); if (!bus) { pci_free_resource_list(&resources); -- GitLab From f474ba9d9f275fc3bfe459b48bfc17ddd8e1f4cb Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:09 +0100 Subject: [PATCH 0325/1167] MIPS: PCI: Make pcibios_set_cache_line_size an initcall In preparation for allowing configurations in which pcibios_init is not included, make pcibios_set_cache_line_size an initcall. arch_initcall is used such that it runs before the pcibios_init subsys_initcall for platforms that continue to use it. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14342/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index 5207c043c69c4..30320a4c89091 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -220,7 +220,7 @@ void register_pci_controller(struct pci_controller *hose) "Skipping PCI bus scan due to resource conflict\n"); } -static void __init pcibios_set_cache_line_size(void) +static int __init pcibios_set_cache_line_size(void) { struct cpuinfo_mips *c = ¤t_cpu_data; unsigned int lsize; @@ -238,14 +238,14 @@ static void __init pcibios_set_cache_line_size(void) pci_dfl_cache_line_size = lsize >> 2; pr_debug("PCI: pci_cache_line_size set to %d bytes\n", lsize); + return 0; } +arch_initcall(pcibios_set_cache_line_size); static int __init pcibios_init(void) { struct pci_controller *hose; - pcibios_set_cache_line_size(); - /* Scan all of the recorded PCI controllers. */ list_for_each_entry(hose, &controllers, list) pcibios_scanbus(hose); -- GitLab From ab96b03144c5392b8c0c427cc37df34daa84c5d0 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:10 +0100 Subject: [PATCH 0326/1167] MIPS: PCI: Inline pcibios_assign_all_busses The MIPS implementation of pcibios_assign_all_busses trivially returns 1. Implement it as a static function in asm/pci.h such that the compiler can inline it & optimise out never-taken paths. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14343/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pci.h | 6 ++++-- arch/mips/pci/pci.c | 5 ----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index 0564692c7d3bc..acc651ec50143 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -66,8 +66,10 @@ extern int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); /* Can be used to override the logic in pci_scan_bus for skipping already-configured bus numbers - to be used for buggy BIOSes or architectures with incomplete PCI setup by the loader */ - -extern unsigned int pcibios_assign_all_busses(void); +static inline unsigned int pcibios_assign_all_busses(void) +{ + return 1; +} extern unsigned long PCIBIOS_MIN_IO; extern unsigned long PCIBIOS_MIN_MEM; diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index 30320a4c89091..8cc6ea4e94819 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -297,11 +297,6 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask) return 0; } -unsigned int pcibios_assign_all_busses(void) -{ - return 1; -} - int pcibios_enable_device(struct pci_dev *dev, int mask) { int err; -- GitLab From f8091a88978b68df8ee6095eed0de2177eac3c69 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:11 +0100 Subject: [PATCH 0327/1167] MIPS: PCI: Split pci.c into pci.c & pci-legacy.c Split out the parts of pci.c that are used by existing systems with MIPS-style PCI drivers but that will not be used by systems with more generic PCI drivers such as pcie-xilinx. This is done in preparation for allowing configurations where the code moved to pci-legacy.c is not built. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/14344/ Signed-off-by: Ralf Baechle --- arch/mips/pci/Makefile | 1 + arch/mips/pci/pci-legacy.c | 302 +++++++++++++++++++++++++++++++++++++ arch/mips/pci/pci.c | 287 +---------------------------------- 3 files changed, 306 insertions(+), 284 deletions(-) create mode 100644 arch/mips/pci/pci-legacy.c diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 139ad1d7ab5e3..566663758570f 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -3,6 +3,7 @@ # obj-y += pci.o +obj-y += pci-legacy.o # # PCI bus host bridge specific code diff --git a/arch/mips/pci/pci-legacy.c b/arch/mips/pci/pci-legacy.c new file mode 100644 index 0000000000000..014649be158d9 --- /dev/null +++ b/arch/mips/pci/pci-legacy.c @@ -0,0 +1,302 @@ +/* + * 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; either version 2 of the License, or (at your + * option) any later version. + * + * Copyright (C) 2003, 04, 11 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2011 Wind River Systems, + * written by Ralf Baechle (ralf@linux-mips.org) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * If PCI_PROBE_ONLY in pci_flags is set, we don't change any PCI resource + * assignments. + */ + +/* + * The PCI controller list. + */ +static LIST_HEAD(controllers); + +static int pci_initialized; + +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ +resource_size_t +pcibios_align_resource(void *data, const struct resource *res, + resource_size_t size, resource_size_t align) +{ + struct pci_dev *dev = data; + struct pci_controller *hose = dev->sysdata; + resource_size_t start = res->start; + + if (res->flags & IORESOURCE_IO) { + /* Make sure we start at our min on all hoses */ + if (start < PCIBIOS_MIN_IO + hose->io_resource->start) + start = PCIBIOS_MIN_IO + hose->io_resource->start; + + /* + * Put everything into 0x00-0xff region modulo 0x400 + */ + if (start & 0x300) + start = (start + 0x3ff) & ~0x3ff; + } else if (res->flags & IORESOURCE_MEM) { + /* Make sure we start at our min on all hoses */ + if (start < PCIBIOS_MIN_MEM + hose->mem_resource->start) + start = PCIBIOS_MIN_MEM + hose->mem_resource->start; + } + + return start; +} + +static void pcibios_scanbus(struct pci_controller *hose) +{ + static int next_busno; + static int need_domain_info; + LIST_HEAD(resources); + struct pci_bus *bus; + + if (hose->get_busno && pci_has_flag(PCI_PROBE_ONLY)) + next_busno = (*hose->get_busno)(); + + pci_add_resource_offset(&resources, + hose->mem_resource, hose->mem_offset); + pci_add_resource_offset(&resources, + hose->io_resource, hose->io_offset); + pci_add_resource_offset(&resources, + hose->busn_resource, hose->busn_offset); + bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose, + &resources); + hose->bus = bus; + + need_domain_info = need_domain_info || pci_domain_nr(bus); + set_pci_need_domain_info(hose, need_domain_info); + + if (!bus) { + pci_free_resource_list(&resources); + return; + } + + next_busno = bus->busn_res.end + 1; + /* Don't allow 8-bit bus number overflow inside the hose - + reserve some space for bridges. */ + if (next_busno > 224) { + next_busno = 0; + need_domain_info = 1; + } + + /* + * We insert PCI resources into the iomem_resource and + * ioport_resource trees in either pci_bus_claim_resources() + * or pci_bus_assign_resources(). + */ + if (pci_has_flag(PCI_PROBE_ONLY)) { + pci_bus_claim_resources(bus); + } else { + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + } + pci_bus_add_devices(bus); +} + +#ifdef CONFIG_OF +void pci_load_of_ranges(struct pci_controller *hose, struct device_node *node) +{ + struct of_pci_range range; + struct of_pci_range_parser parser; + + pr_info("PCI host bridge %s ranges:\n", node->full_name); + hose->of_node = node; + + if (of_pci_range_parser_init(&parser, node)) + return; + + for_each_of_pci_range(&parser, &range) { + struct resource *res = NULL; + + switch (range.flags & IORESOURCE_TYPE_BITS) { + case IORESOURCE_IO: + pr_info(" IO 0x%016llx..0x%016llx\n", + range.cpu_addr, + range.cpu_addr + range.size - 1); + hose->io_map_base = + (unsigned long)ioremap(range.cpu_addr, + range.size); + res = hose->io_resource; + break; + case IORESOURCE_MEM: + pr_info(" MEM 0x%016llx..0x%016llx\n", + range.cpu_addr, + range.cpu_addr + range.size - 1); + res = hose->mem_resource; + break; + } + if (res != NULL) + of_pci_range_to_resource(&range, node, res); + } +} + +struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) +{ + struct pci_controller *hose = bus->sysdata; + + return of_node_get(hose->of_node); +} +#endif + +static DEFINE_MUTEX(pci_scan_mutex); + +void register_pci_controller(struct pci_controller *hose) +{ + struct resource *parent; + + parent = hose->mem_resource->parent; + if (!parent) + parent = &iomem_resource; + + if (request_resource(parent, hose->mem_resource) < 0) + goto out; + + parent = hose->io_resource->parent; + if (!parent) + parent = &ioport_resource; + + if (request_resource(parent, hose->io_resource) < 0) { + release_resource(hose->mem_resource); + goto out; + } + + INIT_LIST_HEAD(&hose->list); + list_add(&hose->list, &controllers); + + /* + * Do not panic here but later - this might happen before console init. + */ + if (!hose->io_map_base) { + printk(KERN_WARNING + "registering PCI controller with io_map_base unset\n"); + } + + /* + * Scan the bus if it is register after the PCI subsystem + * initialization. + */ + if (pci_initialized) { + mutex_lock(&pci_scan_mutex); + pcibios_scanbus(hose); + mutex_unlock(&pci_scan_mutex); + } + + return; + +out: + printk(KERN_WARNING + "Skipping PCI bus scan due to resource conflict\n"); +} + +static int __init pcibios_init(void) +{ + struct pci_controller *hose; + + /* Scan all of the recorded PCI controllers. */ + list_for_each_entry(hose, &controllers, list) + pcibios_scanbus(hose); + + pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq); + + pci_initialized = 1; + + return 0; +} + +subsys_initcall(pcibios_init); + +static int pcibios_enable_resources(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx=0; idx < PCI_NUM_RESOURCES; idx++) { + /* Only set up the requested stuff */ + if (!(mask & (1<resource[idx]; + if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) + continue; + if ((idx == PCI_ROM_RESOURCE) && + (!(r->flags & IORESOURCE_ROM_ENABLE))) + continue; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available " + "because of resource collisions\n", + pci_name(dev)); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", + pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + int err; + + if ((err = pcibios_enable_resources(dev, mask)) < 0) + return err; + + return pcibios_plat_dev_init(dev); +} + +void pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev = bus->self; + + if (pci_has_flag(PCI_PROBE_ONLY) && dev && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + pci_read_bridge_bases(bus); + } +} + +char * (*pcibios_plat_setup)(char *str) __initdata; + +char *__init pcibios_setup(char *str) +{ + if (pcibios_plat_setup) + return pcibios_plat_setup(str); + return str; +} diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index 8cc6ea4e94819..f6325fa657fb6 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -20,205 +20,11 @@ #include -/* - * If PCI_PROBE_ONLY in pci_flags is set, we don't change any PCI resource - * assignments. - */ - -/* - * The PCI controller list. - */ -static LIST_HEAD(controllers); - unsigned long PCIBIOS_MIN_IO; -unsigned long PCIBIOS_MIN_MEM; - -static int pci_initialized; - -/* - * We need to avoid collisions with `mirrored' VGA ports - * and other strange ISA hardware, so we always want the - * addresses to be allocated in the 0x000-0x0ff region - * modulo 0x400. - * - * Why? Because some silly external IO cards only decode - * the low 10 bits of the IO address. The 0x00-0xff region - * is reserved for motherboard devices that decode all 16 - * bits, so it's ok to allocate at, say, 0x2800-0x28ff, - * but we want to try to avoid allocating at 0x2900-0x2bff - * which might have be mirrored at 0x0100-0x03ff.. - */ -resource_size_t -pcibios_align_resource(void *data, const struct resource *res, - resource_size_t size, resource_size_t align) -{ - struct pci_dev *dev = data; - struct pci_controller *hose = dev->sysdata; - resource_size_t start = res->start; - - if (res->flags & IORESOURCE_IO) { - /* Make sure we start at our min on all hoses */ - if (start < PCIBIOS_MIN_IO + hose->io_resource->start) - start = PCIBIOS_MIN_IO + hose->io_resource->start; - - /* - * Put everything into 0x00-0xff region modulo 0x400 - */ - if (start & 0x300) - start = (start + 0x3ff) & ~0x3ff; - } else if (res->flags & IORESOURCE_MEM) { - /* Make sure we start at our min on all hoses */ - if (start < PCIBIOS_MIN_MEM + hose->mem_resource->start) - start = PCIBIOS_MIN_MEM + hose->mem_resource->start; - } - - return start; -} - -static void pcibios_scanbus(struct pci_controller *hose) -{ - static int next_busno; - static int need_domain_info; - LIST_HEAD(resources); - struct pci_bus *bus; - - if (hose->get_busno && pci_has_flag(PCI_PROBE_ONLY)) - next_busno = (*hose->get_busno)(); - - pci_add_resource_offset(&resources, - hose->mem_resource, hose->mem_offset); - pci_add_resource_offset(&resources, - hose->io_resource, hose->io_offset); - pci_add_resource_offset(&resources, - hose->busn_resource, hose->busn_offset); - bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose, - &resources); - hose->bus = bus; - - need_domain_info = need_domain_info || pci_domain_nr(bus); - set_pci_need_domain_info(hose, need_domain_info); - - if (!bus) { - pci_free_resource_list(&resources); - return; - } - - next_busno = bus->busn_res.end + 1; - /* Don't allow 8-bit bus number overflow inside the hose - - reserve some space for bridges. */ - if (next_busno > 224) { - next_busno = 0; - need_domain_info = 1; - } - - /* - * We insert PCI resources into the iomem_resource and - * ioport_resource trees in either pci_bus_claim_resources() - * or pci_bus_assign_resources(). - */ - if (pci_has_flag(PCI_PROBE_ONLY)) { - pci_bus_claim_resources(bus); - } else { - pci_bus_size_bridges(bus); - pci_bus_assign_resources(bus); - } - pci_bus_add_devices(bus); -} - -#ifdef CONFIG_OF -void pci_load_of_ranges(struct pci_controller *hose, struct device_node *node) -{ - struct of_pci_range range; - struct of_pci_range_parser parser; - - pr_info("PCI host bridge %s ranges:\n", node->full_name); - hose->of_node = node; - - if (of_pci_range_parser_init(&parser, node)) - return; - - for_each_of_pci_range(&parser, &range) { - struct resource *res = NULL; - - switch (range.flags & IORESOURCE_TYPE_BITS) { - case IORESOURCE_IO: - pr_info(" IO 0x%016llx..0x%016llx\n", - range.cpu_addr, - range.cpu_addr + range.size - 1); - hose->io_map_base = - (unsigned long)ioremap(range.cpu_addr, - range.size); - res = hose->io_resource; - break; - case IORESOURCE_MEM: - pr_info(" MEM 0x%016llx..0x%016llx\n", - range.cpu_addr, - range.cpu_addr + range.size - 1); - res = hose->mem_resource; - break; - } - if (res != NULL) - of_pci_range_to_resource(&range, node, res); - } -} - -struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) -{ - struct pci_controller *hose = bus->sysdata; - - return of_node_get(hose->of_node); -} -#endif - -static DEFINE_MUTEX(pci_scan_mutex); - -void register_pci_controller(struct pci_controller *hose) -{ - struct resource *parent; - - parent = hose->mem_resource->parent; - if (!parent) - parent = &iomem_resource; - - if (request_resource(parent, hose->mem_resource) < 0) - goto out; - - parent = hose->io_resource->parent; - if (!parent) - parent = &ioport_resource; - - if (request_resource(parent, hose->io_resource) < 0) { - release_resource(hose->mem_resource); - goto out; - } - - INIT_LIST_HEAD(&hose->list); - list_add(&hose->list, &controllers); - - /* - * Do not panic here but later - this might happen before console init. - */ - if (!hose->io_map_base) { - printk(KERN_WARNING - "registering PCI controller with io_map_base unset\n"); - } - - /* - * Scan the bus if it is register after the PCI subsystem - * initialization. - */ - if (pci_initialized) { - mutex_lock(&pci_scan_mutex); - pcibios_scanbus(hose); - mutex_unlock(&pci_scan_mutex); - } - - return; +EXPORT_SYMBOL(PCIBIOS_MIN_IO); -out: - printk(KERN_WARNING - "Skipping PCI bus scan due to resource conflict\n"); -} +unsigned long PCIBIOS_MIN_MEM; +EXPORT_SYMBOL(PCIBIOS_MIN_MEM); static int __init pcibios_set_cache_line_size(void) { @@ -242,84 +48,6 @@ static int __init pcibios_set_cache_line_size(void) } arch_initcall(pcibios_set_cache_line_size); -static int __init pcibios_init(void) -{ - struct pci_controller *hose; - - /* Scan all of the recorded PCI controllers. */ - list_for_each_entry(hose, &controllers, list) - pcibios_scanbus(hose); - - pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq); - - pci_initialized = 1; - - return 0; -} - -subsys_initcall(pcibios_init); - -static int pcibios_enable_resources(struct pci_dev *dev, int mask) -{ - u16 cmd, old_cmd; - int idx; - struct resource *r; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - for (idx=0; idx < PCI_NUM_RESOURCES; idx++) { - /* Only set up the requested stuff */ - if (!(mask & (1<resource[idx]; - if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) - continue; - if ((idx == PCI_ROM_RESOURCE) && - (!(r->flags & IORESOURCE_ROM_ENABLE))) - continue; - if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available " - "because of resource collisions\n", - pci_name(dev)); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - if (cmd != old_cmd) { - printk("PCI: Enabling device %s (%04x -> %04x)\n", - pci_name(dev), old_cmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - return 0; -} - -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - int err; - - if ((err = pcibios_enable_resources(dev, mask)) < 0) - return err; - - return pcibios_plat_dev_init(dev); -} - -void pcibios_fixup_bus(struct pci_bus *bus) -{ - struct pci_dev *dev = bus->self; - - if (pci_has_flag(PCI_PROBE_ONLY) && dev && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - pci_read_bridge_bases(bus); - } -} - -EXPORT_SYMBOL(PCIBIOS_MIN_IO); -EXPORT_SYMBOL(PCIBIOS_MIN_MEM); - void pci_resource_to_user(const struct pci_dev *dev, int bar, const struct resource *rsrc, resource_size_t *start, resource_size_t *end) @@ -353,12 +81,3 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot); } - -char * (*pcibios_plat_setup)(char *str) __initdata; - -char *__init pcibios_setup(char *str) -{ - if (pcibios_plat_setup) - return pcibios_plat_setup(str); - return str; -} -- GitLab From c5611df968047fb0b38156497b4242730ef66108 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:12 +0100 Subject: [PATCH 0328/1167] MIPS: PCI: Introduce CONFIG_PCI_DRIVERS_LEGACY Introduce 2 Kconfig symbols, CONFIG_PCI_DRIVERS_GENERIC & CONFIG_PCI_DRIVERS_LEGACY, which indicate whether the system should be built to for PCI drivers using the MIPS-specific struct pci_controller API (hereafter "legacy" drivers) or more generic drivers using only functionality provided by the PCI core (hereafter "generic" drivers). The Kconfig entries are created such that platforms have to select CONFIG_PCI_DRIVERS_GENERIC if they wish to use it - that is, the default is CONFIG_PCI_DRIVERS_LEGACY so that existing platforms need no modification. The functions declared in pci.h are rearranged with those provided only by pci-legacy.c being guarded by an #ifdef CONFIG_PCI_DRIVERS_LEGACY to ensure they are only used in configurations where they are implemented. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14345/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 8 +++++- arch/mips/include/asm/pci.h | 54 +++++++++++++++++++++---------------- arch/mips/lib/iomap-pci.c | 4 +++ arch/mips/pci/Makefile | 2 +- 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 7a75215aabac0..d31f839c6e773 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2974,7 +2974,6 @@ config PCI bool "Support for PCI controller" depends on HW_HAS_PCI select PCI_DOMAINS - select NO_GENERIC_PCI_IOPORT_MAP help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside @@ -2998,6 +2997,13 @@ config PCI_DOMAINS config PCI_DOMAINS_GENERIC bool +config PCI_DRIVERS_GENERIC + bool + +config PCI_DRIVERS_LEGACY + def_bool !PCI_DRIVERS_GENERIC + select NO_GENERIC_PCI_IOPORT_MAP + source "drivers/pci/Kconfig" # diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index acc651ec50143..30d1129d86248 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -20,6 +20,8 @@ #include #include +#ifdef CONFIG_PCI_DRIVERS_LEGACY + /* * Each pci channel is a top-level PCI bus seem by CPU. A machine with * multiple PCI channels may have multiple PCI host controllers or a @@ -62,6 +64,35 @@ extern void register_pci_controller(struct pci_controller *hose); */ extern int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); +/* Do platform specific device initialization at pci_enable_device() time */ +extern int pcibios_plat_dev_init(struct pci_dev *dev); + +extern char * (*pcibios_plat_setup)(char *str); + +#ifdef CONFIG_OF +/* this function parses memory ranges from a device node */ +extern void pci_load_of_ranges(struct pci_controller *hose, + struct device_node *node); +#else +static inline void pci_load_of_ranges(struct pci_controller *hose, + struct device_node *node) {} +#endif + +#ifdef CONFIG_PCI_DOMAINS_GENERIC +static inline void set_pci_need_domain_info(struct pci_controller *hose, + int need_domain_info) +{ + /* nothing to do */ +} +#elif defined(CONFIG_PCI_DOMAINS) +static inline void set_pci_need_domain_info(struct pci_controller *hose, + int need_domain_info) +{ + hose->need_domain_info = need_domain_info; +} +#endif /* CONFIG_PCI_DOMAINS */ + +#endif /* Can be used to override the logic in pci_scan_bus for skipping already-configured bus numbers - to be used for buggy BIOSes @@ -110,12 +141,6 @@ static inline int pci_proc_domain(struct pci_bus *bus) { return pci_domain_nr(bus); } - -static inline void set_pci_need_domain_info(struct pci_controller *hose, - int need_domain_info) -{ - /* nothing to do */ -} #elif defined(CONFIG_PCI_DOMAINS) #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index @@ -124,12 +149,6 @@ static inline int pci_proc_domain(struct pci_bus *bus) struct pci_controller *hose = bus->sysdata; return hose->need_domain_info; } - -static inline void set_pci_need_domain_info(struct pci_controller *hose, - int need_domain_info) -{ - hose->need_domain_info = need_domain_info; -} #endif /* CONFIG_PCI_DOMAINS */ #endif /* __KERNEL__ */ @@ -143,15 +162,4 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) return channel ? 15 : 14; } -extern char * (*pcibios_plat_setup)(char *str); - -#ifdef CONFIG_OF -/* this function parses memory ranges from a device node */ -extern void pci_load_of_ranges(struct pci_controller *hose, - struct device_node *node); -#else -static inline void pci_load_of_ranges(struct pci_controller *hose, - struct device_node *node) {} -#endif - #endif /* _ASM_PCI_H */ diff --git a/arch/mips/lib/iomap-pci.c b/arch/mips/lib/iomap-pci.c index a629077fd7b9a..8ed3f25a9047d 100644 --- a/arch/mips/lib/iomap-pci.c +++ b/arch/mips/lib/iomap-pci.c @@ -10,6 +10,8 @@ #include #include +#ifdef CONFIG_PCI_DRIVERS_LEGACY + void __iomem *__pci_ioport_map(struct pci_dev *dev, unsigned long port, unsigned int nr) { @@ -40,6 +42,8 @@ void __iomem *__pci_ioport_map(struct pci_dev *dev, return (void __iomem *) (ctrl->io_map_base + port); } +#endif /* CONFIG_PCI_DRIVERS_LEGACY */ + void pci_iounmap(struct pci_dev *dev, void __iomem * addr) { iounmap(addr); diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 566663758570f..847821040cd9c 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -3,7 +3,7 @@ # obj-y += pci.o -obj-y += pci-legacy.o +obj-$(CONFIG_PCI_DRIVERS_LEGACY)+= pci-legacy.o # # PCI bus host bridge specific code -- GitLab From 87dd9a4de421f052fd9be58c7da08a453f340d5e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:13 +0100 Subject: [PATCH 0329/1167] MIPS: PCI: Support generic drivers Introduce support for PCI drivers using only functionality provided generically by the PCI subsystem, by adding the minimum arch-provided functions required. The driver this has been developed for & tested with the xilinx-pcie on a MIPS Boston development board. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14346/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + arch/mips/pci/Makefile | 1 + arch/mips/pci/pci-generic.c | 52 +++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 arch/mips/pci/pci-generic.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index d31f839c6e773..86d5b39305317 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2998,6 +2998,7 @@ config PCI_DOMAINS_GENERIC bool config PCI_DRIVERS_GENERIC + select PCI_DOMAINS_GENERIC if PCI_DOMAINS bool config PCI_DRIVERS_LEGACY diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 847821040cd9c..4b821481dd443 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -4,6 +4,7 @@ obj-y += pci.o obj-$(CONFIG_PCI_DRIVERS_LEGACY)+= pci-legacy.o +obj-$(CONFIG_PCI_DRIVERS_GENERIC)+= pci-generic.o # # PCI bus host bridge specific code diff --git a/arch/mips/pci/pci-generic.c b/arch/mips/pci/pci-generic.c new file mode 100644 index 0000000000000..dce304dc3d62d --- /dev/null +++ b/arch/mips/pci/pci-generic.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * pcibios_align_resource taken from arch/arm/kernel/bios32.c. + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include + +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ +resource_size_t pcibios_align_resource(void *data, const struct resource *res, + resource_size_t size, resource_size_t align) +{ + struct pci_dev *dev = data; + resource_size_t start = res->start; + struct pci_host_bridge *host_bridge; + + if (res->flags & IORESOURCE_IO && start & 0x300) + start = (start + 0x3ff) & ~0x3ff; + + start = (start + align - 1) & ~(align - 1); + + host_bridge = pci_find_host_bridge(dev->bus); + + if (host_bridge->align_resource) + return host_bridge->align_resource(dev, res, + start, size, align); + + return start; +} + +void pcibios_fixup_bus(struct pci_bus *bus) +{ + pci_read_bridge_bases(bus); +} -- GitLab From f23020230e682a43cc4706cabb041bba469df2d6 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:14 +0100 Subject: [PATCH 0330/1167] MIPS: Sanitise coherentio semantics The coherentio variable has previously been used as a boolean value, indicating whether the user specified that coherent I/O should be enabled or disabled. It failed to take into account the case where the user does not specify any preference, in which case it makes sense that we should default to coherent I/O if the hardware supports it (hw_coherentio is non-zero). Introduce an enum to clarify the 3 different values of coherentio & use it throughout the code, modifying plat_device_is_coherent() & r4k_cache_init() to take into account the default case. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/14347/ Signed-off-by: Ralf Baechle --- arch/mips/alchemy/common/setup.c | 6 +++--- arch/mips/include/asm/dma-coherence.h | 12 +++++++++--- arch/mips/include/asm/mach-generic/dma-coherence.h | 10 +++++++++- arch/mips/mm/c-r4k.c | 3 ++- arch/mips/mm/dma-default.c | 7 ++++--- arch/mips/mti-malta/malta-setup.c | 4 ++-- arch/mips/pci/pci-alchemy.c | 3 ++- 7 files changed, 31 insertions(+), 14 deletions(-) diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index 2902138b3e0f5..7faaa6d593a74 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c @@ -48,17 +48,17 @@ void __init plat_mem_setup(void) clear_c0_config(1 << 19); /* Clear Config[OD] */ hw_coherentio = 0; - coherentio = 1; + coherentio = IO_COHERENCE_ENABLED; switch (alchemy_get_cputype()) { case ALCHEMY_CPU_AU1000: case ALCHEMY_CPU_AU1500: case ALCHEMY_CPU_AU1100: - coherentio = 0; + coherentio = IO_COHERENCE_DISABLED; break; case ALCHEMY_CPU_AU1200: /* Au1200 AB USB does not support coherent memory */ if (0 == (read_c0_prid() & PRID_REV_MASK)) - coherentio = 0; + coherentio = IO_COHERENCE_DISABLED; break; } diff --git a/arch/mips/include/asm/dma-coherence.h b/arch/mips/include/asm/dma-coherence.h index bc5e85d579e60..4fbce79fb57fa 100644 --- a/arch/mips/include/asm/dma-coherence.h +++ b/arch/mips/include/asm/dma-coherence.h @@ -9,14 +9,20 @@ #ifndef __ASM_DMA_COHERENCE_H #define __ASM_DMA_COHERENCE_H +enum coherent_io_user_state { + IO_COHERENCE_DEFAULT, + IO_COHERENCE_ENABLED, + IO_COHERENCE_DISABLED, +}; + #ifdef CONFIG_DMA_MAYBE_COHERENT -extern int coherentio; +extern enum coherent_io_user_state coherentio; extern int hw_coherentio; #else #ifdef CONFIG_DMA_COHERENT -#define coherentio 1 +#define coherentio IO_COHERENCE_ENABLED #else -#define coherentio 0 +#define coherentio IO_COHERENCE_DISABLED #endif #define hw_coherentio 0 #endif /* CONFIG_DMA_MAYBE_COHERENT */ diff --git a/arch/mips/include/asm/mach-generic/dma-coherence.h b/arch/mips/include/asm/mach-generic/dma-coherence.h index 0f8a354fd4686..8484f82fc7941 100644 --- a/arch/mips/include/asm/mach-generic/dma-coherence.h +++ b/arch/mips/include/asm/mach-generic/dma-coherence.h @@ -49,7 +49,15 @@ static inline int plat_dma_supported(struct device *dev, u64 mask) static inline int plat_device_is_coherent(struct device *dev) { - return coherentio; + switch (coherentio) { + default: + case IO_COHERENCE_DEFAULT: + return hw_coherentio; + case IO_COHERENCE_ENABLED: + return 1; + case IO_COHERENCE_DISABLED: + return 0; + } } #ifndef plat_post_dma_flush diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 1fc11184e999e..78ac033a0f074 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1935,7 +1935,8 @@ void r4k_cache_init(void) __local_flush_icache_user_range = local_r4k_flush_icache_user_range; #if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT) - if (coherentio) { + if ((coherentio == IO_COHERENCE_ENABLED) || + ((coherentio == IO_COHERENCE_DEFAULT) && hw_coherentio)) { _dma_cache_wback_inv = (void *)cache_noop; _dma_cache_wback = (void *)cache_noop; _dma_cache_inv = (void *)cache_noop; diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 755259c54976b..8b86c61682392 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -25,13 +25,14 @@ #include #ifdef CONFIG_DMA_MAYBE_COHERENT -int coherentio = 0; /* User defined DMA coherency from command line. */ +/* User defined DMA coherency from command line. */ +enum coherent_io_user_state coherentio = IO_COHERENCE_DEFAULT; EXPORT_SYMBOL_GPL(coherentio); int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */ static int __init setcoherentio(char *str) { - coherentio = 1; + coherentio = IO_COHERENCE_ENABLED; pr_info("Hardware DMA cache coherency (command line)\n"); return 0; } @@ -39,7 +40,7 @@ early_param("coherentio", setcoherentio); static int __init setnocoherentio(char *str) { - coherentio = 0; + coherentio = IO_COHERENCE_DISABLED; pr_info("Software DMA cache coherency (command line)\n"); return 0; } diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c index 7e7364b0501ed..f1b6074828b12 100644 --- a/arch/mips/mti-malta/malta-setup.c +++ b/arch/mips/mti-malta/malta-setup.c @@ -154,12 +154,12 @@ static void __init plat_setup_iocoherency(void) * coherency instead. */ if (plat_enable_iocoherency()) { - if (coherentio == 0) + if (coherentio == IO_COHERENCE_DISABLED) pr_info("Hardware DMA cache coherency disabled\n"); else pr_info("Hardware DMA cache coherency enabled\n"); } else { - if (coherentio == 1) + if (coherentio == IO_COHERENCE_ENABLED) pr_info("Hardware DMA cache coherency unsupported, but enabled from command line!\n"); else pr_info("Software DMA cache coherency enabled\n"); diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c index c8994c156e2dd..e99ca7702d8ad 100644 --- a/arch/mips/pci/pci-alchemy.c +++ b/arch/mips/pci/pci-alchemy.c @@ -429,7 +429,8 @@ static int alchemy_pci_probe(struct platform_device *pdev) /* Au1500 revisions older than AD have borked coherent PCI */ if ((alchemy_get_cputype() == ALCHEMY_CPU_AU1500) && - (read_c0_prid() < 0x01030202) && !coherentio) { + (read_c0_prid() < 0x01030202) && + (coherentio == IO_COHERENCE_DISABLED)) { val = __raw_readl(ctx->regs + PCI_REG_CONFIG); val |= PCI_CONFIG_NC; __raw_writel(val, ctx->regs + PCI_REG_CONFIG); -- GitLab From cfa93fb9c2eae805f2c16d72bad04ca49b6e16d2 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:15 +0100 Subject: [PATCH 0331/1167] MIPS: dma-default: Don't check hw_coherentio if device is non-coherent There are no cases where plat_device_is_coherent() will return zero whilst hw_coherentio is non-zero, and acting any differently in such a case doesn't make much sense - if a device is non-coherent with the CPU caches then access to memory "coherent" with DMA must be uncached. Clean up the nonsensical case. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14348/ Signed-off-by: Ralf Baechle --- arch/mips/mm/dma-default.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 8b86c61682392..7ae4c55c935a7 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -161,8 +161,7 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size, *dma_handle = plat_map_dma_mem(dev, ret, size); if (!plat_device_is_coherent(dev)) { dma_cache_wback_inv((unsigned long) ret, size); - if (!hw_coherentio) - ret = UNCAC_ADDR(ret); + ret = UNCAC_ADDR(ret); } return ret; @@ -190,7 +189,7 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL); - if (!plat_device_is_coherent(dev) && !hw_coherentio) + if (!plat_device_is_coherent(dev)) addr = CAC_ADDR(addr); page = virt_to_page((void *) addr); @@ -210,7 +209,7 @@ static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma, unsigned long pfn; int ret = -ENXIO; - if (!plat_device_is_coherent(dev) && !hw_coherentio) + if (!plat_device_is_coherent(dev)) addr = CAC_ADDR(addr); pfn = page_to_pfn(virt_to_page((void *)addr)); -- GitLab From 20d330645cfb8cfecfb82b369e4d3084e429e68a Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:16 +0100 Subject: [PATCH 0332/1167] MIPS: Support per-device DMA coherence On some MIPS systems, a subset of devices may have DMA coherent with CPU caches. For example in systems including a MIPS I/O Coherence Unit (IOCU), some devices may be connected to that IOCU whilst others are not. Prior to this patch, we have a plat_device_is_coherent() function but no implementation which does anything besides return a global true or false, optionally chosen at runtime. For devices such as those described above this is insufficient. Fix this by tracking DMA coherence on a per-device basis with a dma_coherent field in struct dev_archdata. Setting this from arch_setup_dma_ops() takes care of devices which set the dma-coherent property via device tree, and any PCI devices beneath a bridge described in DT, automatically. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14349/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 ++++ arch/mips/include/asm/device.h | 5 +++++ arch/mips/include/asm/dma-coherence.h | 4 +++- arch/mips/include/asm/dma-mapping.h | 10 ++++++++++ arch/mips/include/asm/mach-generic/dma-coherence.h | 4 ++++ arch/mips/mm/c-r4k.c | 4 ++++ arch/mips/mm/dma-default.c | 2 +- 7 files changed, 31 insertions(+), 2 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 86d5b39305317..2356439705174 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1099,6 +1099,10 @@ config DMA_MAYBE_COHERENT select DMA_NONCOHERENT bool +config DMA_PERDEV_COHERENT + bool + select DMA_MAYBE_COHERENT + config DMA_COHERENT bool diff --git a/arch/mips/include/asm/device.h b/arch/mips/include/asm/device.h index c94fafba9e62f..21c2082a0dfbb 100644 --- a/arch/mips/include/asm/device.h +++ b/arch/mips/include/asm/device.h @@ -11,6 +11,11 @@ struct dma_map_ops; struct dev_archdata { /* DMA operations on that device */ struct dma_map_ops *dma_ops; + +#ifdef CONFIG_DMA_PERDEV_COHERENT + /* Non-zero if DMA is coherent with CPU caches */ + bool dma_coherent; +#endif }; struct pdev_archdata { diff --git a/arch/mips/include/asm/dma-coherence.h b/arch/mips/include/asm/dma-coherence.h index 4fbce79fb57fa..72d0eab02afcb 100644 --- a/arch/mips/include/asm/dma-coherence.h +++ b/arch/mips/include/asm/dma-coherence.h @@ -15,7 +15,9 @@ enum coherent_io_user_state { IO_COHERENCE_DISABLED, }; -#ifdef CONFIG_DMA_MAYBE_COHERENT +#if defined(CONFIG_DMA_PERDEV_COHERENT) +/* Don't provide (hw_)coherentio to avoid misuse */ +#elif defined(CONFIG_DMA_MAYBE_COHERENT) extern enum coherent_io_user_state coherentio; extern int hw_coherentio; #else diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index 12fa79e2f1b4f..7aa71b9b0258f 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -32,4 +32,14 @@ static inline void dma_mark_clean(void *addr, size_t size) {} extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction); +#define arch_setup_dma_ops arch_setup_dma_ops +static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, + u64 size, const struct iommu_ops *iommu, + bool coherent) +{ +#ifdef CONFIG_DMA_PERDEV_COHERENT + dev->archdata.dma_coherent = coherent; +#endif +} + #endif /* _ASM_DMA_MAPPING_H */ diff --git a/arch/mips/include/asm/mach-generic/dma-coherence.h b/arch/mips/include/asm/mach-generic/dma-coherence.h index 8484f82fc7941..61addb1677e95 100644 --- a/arch/mips/include/asm/mach-generic/dma-coherence.h +++ b/arch/mips/include/asm/mach-generic/dma-coherence.h @@ -49,6 +49,9 @@ static inline int plat_dma_supported(struct device *dev, u64 mask) static inline int plat_device_is_coherent(struct device *dev) { +#ifdef CONFIG_DMA_PERDEV_COHERENT + return dev->archdata.dma_coherent; +#else switch (coherentio) { default: case IO_COHERENCE_DEFAULT: @@ -58,6 +61,7 @@ static inline int plat_device_is_coherent(struct device *dev) case IO_COHERENCE_DISABLED: return 0; } +#endif } #ifndef plat_post_dma_flush diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 78ac033a0f074..88cfaf81c9587 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1935,8 +1935,12 @@ void r4k_cache_init(void) __local_flush_icache_user_range = local_r4k_flush_icache_user_range; #if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT) +# if defined(CONFIG_DMA_PERDEV_COHERENT) + if (0) { +# else if ((coherentio == IO_COHERENCE_ENABLED) || ((coherentio == IO_COHERENCE_DEFAULT) && hw_coherentio)) { +# endif _dma_cache_wback_inv = (void *)cache_noop; _dma_cache_wback = (void *)cache_noop; _dma_cache_inv = (void *)cache_noop; diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 7ae4c55c935a7..46d5696c4f276 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -24,7 +24,7 @@ #include -#ifdef CONFIG_DMA_MAYBE_COHERENT +#if defined(CONFIG_DMA_MAYBE_COHERENT) && !defined(CONFIG_DMA_PERDEV_COHERENT) /* User defined DMA coherency from command line. */ enum coherent_io_user_state coherentio = IO_COHERENCE_DEFAULT; EXPORT_SYMBOL_GPL(coherentio); -- GitLab From dabdc1853d59b355eaa679b8856016a7366da9af Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:17 +0100 Subject: [PATCH 0333/1167] MIPS: Print CM error reports upon bus errors If a bus error occurs on a system with a MIPS Coherence Manager (CM) then the CM may hold useful diagnostic information. Printing this out has so far been left up to boards, with the requirement that they register a board_be_handler function & call mips_cm_error_decode() from there. In order to avoid boards other than Malta needing to duplicate this code, call mips_cm_error_decode() automatically if the board registers no board_be_handler, and remove the Malta implementation of that. This patch results in no functional change, but removes a further piece of platform-specific code. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14350/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 3 +++ arch/mips/mti-malta/malta-int.c | 15 --------------- arch/mips/mti-malta/malta-setup.c | 6 ------ 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 0c0270c29cd1f..1f5fdee1dfc31 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -445,6 +446,8 @@ asmlinkage void do_be(struct pt_regs *regs) if (board_be_handler) action = board_be_handler(regs, fixup != NULL); + else + mips_cm_error_report(); switch (action) { case MIPS_BE_DISCARD: diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index 9f83224292d9b..cb675ec6f283e 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -290,18 +290,3 @@ void __init arch_init_irq(void) setup_irq(corehi_irq, &corehi_irqaction); } - -void malta_be_init(void) -{ - /* Could change CM error mask register. */ -} - -int malta_be_handler(struct pt_regs *regs, int is_fixup) -{ - /* This duplicates the handling in do_be which seems wrong */ - int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; - - mips_cm_error_report(); - - return retval; -} diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c index f1b6074828b12..a01d5debfcaf5 100644 --- a/arch/mips/mti-malta/malta-setup.c +++ b/arch/mips/mti-malta/malta-setup.c @@ -42,9 +42,6 @@ #define ROCIT_CONFIG_GEN0 0x1f403000 #define ROCIT_CONFIG_GEN0_PCI_IOCU BIT(7) -extern void malta_be_init(void); -extern int malta_be_handler(struct pt_regs *regs, int is_fixup); - static struct resource standard_io_resources[] = { { .name = "dma1", @@ -301,7 +298,4 @@ void __init plat_mem_setup(void) #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) screen_info_setup(); #endif - - board_be_init = malta_be_init; - board_be_handler = malta_be_handler; } -- GitLab From 3ffc17d8768be705e292ac4c2e3ab1f18dc06047 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:18 +0100 Subject: [PATCH 0334/1167] MIPS: Adjust MIPS64 CAC_BASE to reflect Config.K0 On MIPS64 we define the default CAC_BASE as one of the xkphys regions of the virtual address space. Since the CCA is encoded in bits 61:59 of xkphys addresses, fixing CAC_BASE to any particular one prevents us from dynamically changing the CCA as we do for MIPS32 where CAC_BASE is placed within kseg0. In order to make the kernel more generic, drop the current kludge that gives CAC_BASE CCA=3 if CONFIG_DMA_NONCOHERENT is selected (disregarding CONFIG_DMA_MAYBE_COHERENT) & CCA=5 (which is not standardised by the architecture) otherwise. Instead read Config.K0 and generate the appropriate offset into xkphys, presuming that either the bootloader or early kernel code will have configured Config.K0 appropriately. This seems like the best option for a generic implementation. The ip27 spaces.h is adjusted to set its former value of CAC_BASE, since it's the only user of CAC_BASE from assembly (in its smp_slave_setup macro). This allows the generic case to focus solely on C code without breaking ip27. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14351/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/addrspace.h | 3 +-- arch/mips/include/asm/mach-generic/spaces.h | 8 +++----- arch/mips/include/asm/mach-ip27/spaces.h | 1 + 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/mips/include/asm/addrspace.h b/arch/mips/include/asm/addrspace.h index c5b04e752e976..4856adc8906ef 100644 --- a/arch/mips/include/asm/addrspace.h +++ b/arch/mips/include/asm/addrspace.h @@ -126,8 +126,7 @@ #define PHYS_TO_XKSEG_UNCACHED(p) PHYS_TO_XKPHYS(K_CALG_UNCACHED, (p)) #define PHYS_TO_XKSEG_CACHED(p) PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE, (p)) #define XKPHYS_TO_PHYS(p) ((p) & TO_PHYS_MASK) -#define PHYS_TO_XKPHYS(cm, a) (_CONST64_(0x8000000000000000) | \ - (_CONST64_(cm) << 59) | (a)) +#define PHYS_TO_XKPHYS(cm, a) (XKPHYS | (_ACAST64_(cm) << 59) | (a)) /* * The ultimate limited of the 64-bit MIPS architecture: 2 bits for selecting diff --git a/arch/mips/include/asm/mach-generic/spaces.h b/arch/mips/include/asm/mach-generic/spaces.h index afc96ecb90042..952b0fdfda0e6 100644 --- a/arch/mips/include/asm/mach-generic/spaces.h +++ b/arch/mips/include/asm/mach-generic/spaces.h @@ -12,6 +12,8 @@ #include +#include + /* * This gives the physical RAM offset. */ @@ -52,11 +54,7 @@ #ifdef CONFIG_64BIT #ifndef CAC_BASE -#ifdef CONFIG_DMA_NONCOHERENT -#define CAC_BASE _AC(0x9800000000000000, UL) -#else -#define CAC_BASE _AC(0xa800000000000000, UL) -#endif +#define CAC_BASE PHYS_TO_XKPHYS(read_c0_config() & CONF_CM_CMASK, 0) #endif #ifndef IO_BASE diff --git a/arch/mips/include/asm/mach-ip27/spaces.h b/arch/mips/include/asm/mach-ip27/spaces.h index b18802a0b17e9..4775a1136a5b4 100644 --- a/arch/mips/include/asm/mach-ip27/spaces.h +++ b/arch/mips/include/asm/mach-ip27/spaces.h @@ -19,6 +19,7 @@ #define IO_BASE 0x9200000000000000 #define MSPEC_BASE 0x9400000000000000 #define UNCAC_BASE 0x9600000000000000 +#define CAC_BASE 0xa800000000000000 #define TO_MSPEC(x) (MSPEC_BASE | ((x) & TO_PHYS_MASK)) #define TO_HSPEC(x) (HSPEC_BASE | ((x) & TO_PHYS_MASK)) -- GitLab From cf2a5e0bb4c66e8c43caf9f1be93a1bd7fd07b17 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:19 +0100 Subject: [PATCH 0335/1167] MIPS: Support generating Flattened Image Trees (.itb) Add support for generating kernel images in the Flattened Image Tree (.itb) format as supported by U-Boot. This format is essentially a Flattened Device Tree binary containing images (kernels, DTBs, ramdisks) and configurations which link those images together. The big advantages of FIT images over the uImage format are: - We can include FDTs in the kernel image in a way that the bootloader can extract it & manipulate it before providing it to the kernel. Thus we can ship FDTs as part of the kernel giving us the advantages of being able to develop & maintain the DT within the kernel tree, but also have the benefits of the bootloader being able to manipulate the FDT. Example uses for this would be to inject the kernel command line into the chosen node, or to fill in the correct memory size. - We can include multiple configurations in a single kernel image. This means that a single FIT image can, given appropriate bootloaders, be booted on different boards with the bootloader selecting an appropriate configuration & providing the correct FDT to the kernel. - We can support a multitude of hashes over the data. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14352/ Signed-off-by: Ralf Baechle --- arch/mips/Makefile | 8 +++++- arch/mips/boot/Makefile | 57 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 598ab2930fce6..691a6e1258793 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -262,7 +262,8 @@ KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y) KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0) bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) \ - VMLINUX_ENTRY_ADDRESS=$(entry-y) + VMLINUX_ENTRY_ADDRESS=$(entry-y) \ + PLATFORM=$(platform-y) LDFLAGS += -m $(ld-emul) @@ -302,6 +303,11 @@ boot-y += uImage.gz boot-y += uImage.lzma boot-y += uImage.lzo endif +boot-y += vmlinux.itb +boot-y += vmlinux.gz.itb +boot-y += vmlinux.bz2.itb +boot-y += vmlinux.lzma.itb +boot-y += vmlinux.lzo.itb # compressed boot image targets (arch/mips/boot/compressed/) bootz-y := vmlinuz diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile index acb1988f354ed..ed656636accec 100644 --- a/arch/mips/boot/Makefile +++ b/arch/mips/boot/Makefile @@ -100,3 +100,60 @@ $(obj)/uImage.lzo: $(obj)/vmlinux.bin.lzo FORCE $(obj)/uImage: $(obj)/uImage.$(suffix-y) @ln -sf $(notdir $<) $@ @echo ' Image $@ is ready' + +# +# Flattened Image Tree (.itb) images +# + +targets += vmlinux.itb +targets += vmlinux.gz.itb +targets += vmlinux.bz2.itb +targets += vmlinux.lzma.itb +targets += vmlinux.lzo.itb + +quiet_cmd_cpp_its_S = ITS $@ + cmd_cpp_its_S = $(CPP) $(cpp_flags) -P -C -o $@ $< \ + -DKERNEL_NAME="\"Linux $(KERNELRELEASE)\"" \ + -DVMLINUX_BINARY="\"$(3)\"" \ + -DVMLINUX_COMPRESSION="\"$(2)\"" \ + -DVMLINUX_LOAD_ADDRESS=$(VMLINUX_LOAD_ADDRESS) \ + -DVMLINUX_ENTRY_ADDRESS=$(VMLINUX_ENTRY_ADDRESS) + +$(obj)/vmlinux.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE + $(call if_changed_dep,cpp_its_S,none,vmlinux.bin) + +$(obj)/vmlinux.gz.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE + $(call if_changed_dep,cpp_its_S,gzip,vmlinux.bin.gz) + +$(obj)/vmlinux.bz2.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE + $(call if_changed_dep,cpp_its_S,bzip2,vmlinux.bin.bz2) + +$(obj)/vmlinux.lzma.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE + $(call if_changed_dep,cpp_its_S,lzma,vmlinux.bin.lzma) + +$(obj)/vmlinux.lzo.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE + $(call if_changed_dep,cpp_its_S,lzo,vmlinux.bin.lzo) + +quiet_cmd_itb-image = ITB $@ + cmd_itb-image = \ + env PATH="$(objtree)/scripts/dtc:$(PATH)" \ + $(CONFIG_SHELL) $(MKIMAGE) \ + -D "-I dts -O dtb -p 500 \ + --include $(objtree)/arch/mips \ + --warning no-unit_address_vs_reg" \ + -f $(2) $@ + +$(obj)/vmlinux.itb: $(obj)/vmlinux.its $(obj)/vmlinux.bin FORCE + $(call if_changed,itb-image,$<) + +$(obj)/vmlinux.gz.itb: $(obj)/vmlinux.gz.its $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,itb-image,$<) + +$(obj)/vmlinux.bz2.itb: $(obj)/vmlinux.bz2.its $(obj)/vmlinux.bin.bz2 FORCE + $(call if_changed,itb-image,$<) + +$(obj)/vmlinux.lzma.itb: $(obj)/vmlinux.lzma.its $(obj)/vmlinux.bin.lzma FORCE + $(call if_changed,itb-image,$<) + +$(obj)/vmlinux.lzo.itb: $(obj)/vmlinux.lzo.its $(obj)/vmlinux.bin.lzo FORCE + $(call if_changed,itb-image,$<) -- GitLab From eed0eabd12ef061821cbfa20d903476e07645320 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:20 +0100 Subject: [PATCH 0336/1167] MIPS: generic: Introduce generic DT-based board support Introduce a "generic" platform, which aims to be board-agnostic by making use of device trees passed by the boot protocol defined in the MIPS UHI (Universal Hosting Interface) specification. Provision is made for supporting boards which use a legacy boot protocol that can't be changed, but adding support for such boards or any others is left to followon patches. Right now the built kernels expect to be loaded to 0x80100000, ie. in kseg0. This is fine for the vast majority of MIPS platforms, but nevertheless it would be good to remove this limitation in the future by mapping the kernel via the TLB such that it can be loaded anywhere & map itself appropriately. Configuration is handled by dynamically generating configs using scripts/kconfig/merge_config.sh, somewhat similar to the way powerpc makes use of it. This allows for variations upon the configuration, eg. differing architecture revisions or subsets of driver support for differing boards, to be handled without having a large number of defconfig files. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14353/ Signed-off-by: Ralf Baechle --- arch/mips/Kbuild.platforms | 1 + arch/mips/Kconfig | 52 ++++++ arch/mips/Makefile | 56 +++++++ arch/mips/boot/Makefile | 11 +- arch/mips/configs/generic/32r1.config | 2 + arch/mips/configs/generic/32r2.config | 3 + arch/mips/configs/generic/32r6.config | 2 + arch/mips/configs/generic/64r1.config | 4 + arch/mips/configs/generic/64r2.config | 5 + arch/mips/configs/generic/64r6.config | 4 + arch/mips/configs/generic/eb.config | 1 + arch/mips/configs/generic/el.config | 1 + arch/mips/configs/generic/micro32r2.config | 4 + arch/mips/configs/generic_defconfig | 96 +++++++++++ arch/mips/generic/Kconfig | 12 ++ arch/mips/generic/Makefile | 13 ++ arch/mips/generic/Platform | 14 ++ arch/mips/generic/init.c | 176 +++++++++++++++++++++ arch/mips/generic/irq.c | 64 ++++++++ arch/mips/generic/proc.c | 29 ++++ arch/mips/generic/vmlinux.its.S | 31 ++++ arch/mips/include/asm/machine.h | 63 ++++++++ 22 files changed, 643 insertions(+), 1 deletion(-) create mode 100644 arch/mips/configs/generic/32r1.config create mode 100644 arch/mips/configs/generic/32r2.config create mode 100644 arch/mips/configs/generic/32r6.config create mode 100644 arch/mips/configs/generic/64r1.config create mode 100644 arch/mips/configs/generic/64r2.config create mode 100644 arch/mips/configs/generic/64r6.config create mode 100644 arch/mips/configs/generic/eb.config create mode 100644 arch/mips/configs/generic/el.config create mode 100644 arch/mips/configs/generic/micro32r2.config create mode 100644 arch/mips/configs/generic_defconfig create mode 100644 arch/mips/generic/Kconfig create mode 100644 arch/mips/generic/Makefile create mode 100644 arch/mips/generic/Platform create mode 100644 arch/mips/generic/init.c create mode 100644 arch/mips/generic/irq.c create mode 100644 arch/mips/generic/proc.c create mode 100644 arch/mips/generic/vmlinux.its.S create mode 100644 arch/mips/include/asm/machine.h diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index c5cd63a4b6d53..9c1e8f9f854aa 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -11,6 +11,7 @@ platforms += cavium-octeon platforms += cobalt platforms += dec platforms += emma +platforms += generic platforms += jazz platforms += jz4740 platforms += lantiq diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 2356439705174..82b45dc9fa4de 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -73,6 +73,57 @@ choice prompt "System type" default SGI_IP22 +config MIPS_GENERIC + bool "Generic board-agnostic MIPS kernel" + select BOOT_RAW + select BUILTIN_DTB + select CEVT_R4K + select CLKSRC_MIPS_GIC + select COMMON_CLK + select CPU_MIPSR2_IRQ_VI + select CPU_MIPSR2_IRQ_EI + select CSRC_R4K + select DMA_PERDEV_COHERENT + select HW_HAS_PCI + select IRQ_MIPS_CPU + select LIBFDT + select MIPS_CPU_SCACHE + select MIPS_GIC + select MIPS_L1_CACHE_SHIFT_7 + select NO_EXCEPT_FILL + select PCI_DRIVERS_GENERIC + select PINCTRL + select SMP_UP if SMP + select SYS_HAS_CPU_MIPS32_R1 + select SYS_HAS_CPU_MIPS32_R2 + select SYS_HAS_CPU_MIPS32_R6 + select SYS_HAS_CPU_MIPS64_R1 + select SYS_HAS_CPU_MIPS64_R2 + select SYS_HAS_CPU_MIPS64_R6 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_HIGHMEM + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_MICROMIPS + select SYS_SUPPORTS_MIPS_CPS + select SYS_SUPPORTS_MIPS16 + select SYS_SUPPORTS_MULTITHREADING + select SYS_SUPPORTS_RELOCATABLE + select SYS_SUPPORTS_SMARTMIPS + select USB_EHCI_BIG_ENDIAN_DESC if BIG_ENDIAN + select USB_EHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN + select USB_OHCI_BIG_ENDIAN_DESC if BIG_ENDIAN + select USB_OHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN + select USB_UHCI_BIG_ENDIAN_DESC if BIG_ENDIAN + select USB_UHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN + select USE_OF + help + Select this to build a kernel which aims to support multiple boards, + generally using a flattened device tree passed from the bootloader + using the boot protocol defined in the UHI (Unified Hosting + Interface) specification. + config MIPS_ALCHEMY bool "Alchemy processor based machines" select ARCH_PHYS_ADDR_T_64BIT @@ -989,6 +1040,7 @@ source "arch/mips/ath79/Kconfig" source "arch/mips/bcm47xx/Kconfig" source "arch/mips/bcm63xx/Kconfig" source "arch/mips/bmips/Kconfig" +source "arch/mips/generic/Kconfig" source "arch/mips/jazz/Kconfig" source "arch/mips/jz4740/Kconfig" source "arch/mips/lantiq/Kconfig" diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 691a6e1258793..f3e768a69a52b 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -264,6 +264,12 @@ KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0) bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) \ VMLINUX_ENTRY_ADDRESS=$(entry-y) \ PLATFORM=$(platform-y) +ifdef CONFIG_32BIT +bootvars-y += ADDR_BITS=32 +endif +ifdef CONFIG_64BIT +bootvars-y += ADDR_BITS=64 +endif LDFLAGS += -m $(ld-emul) @@ -431,4 +437,54 @@ define archhelp echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)' echo echo ' These will be default as appropriate for a configured platform.' + echo + echo ' If you are targeting a system supported by generic kernels you may' + echo ' configure the kernel for a given architecture target like so:' + echo + echo ' {micro32,32,64}{r1,r2,r6}{el,}_defconfig ' + echo + echo ' Otherwise, the following default configurations are available:' endef + +generic_config_dir = $(srctree)/arch/$(ARCH)/configs/generic +generic_defconfigs := + +# +# If the user generates a generic kernel configuration without specifying a +# list of boards to include the config fragments for, default to including all +# available board config fragments. +# +ifeq ($(BOARDS),) +BOARDS = $(patsubst board-%.config,%,$(notdir $(wildcard $(generic_config_dir)/board-*.config))) +endif + +# +# Generic kernel configurations which merge generic_defconfig with the +# appropriate config fragments from arch/mips/configs/generic/, resulting in +# the ability to easily configure the kernel for a given architecture, +# endianness & set of boards without duplicating the needed configuration in +# hundreds of defconfig files. +# +define gen_generic_defconfigs +$(foreach bits,$(1),$(foreach rev,$(2),$(foreach endian,$(3), +target := $(bits)$(rev)$(filter el,$(endian))_defconfig +generic_defconfigs += $$(target) +$$(target): $(generic_config_dir)/$(bits)$(rev).config +$$(target): $(generic_config_dir)/$(endian).config +))) +endef + +$(eval $(call gen_generic_defconfigs,32 64,r1 r2 r6,eb el)) +$(eval $(call gen_generic_defconfigs,micro32,r2,eb el)) + +.PHONY: $(generic_defconfigs) +$(generic_defconfigs): + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \ + -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/generic_defconfig $^ \ + $(foreach board,$(BOARDS),$(generic_config_dir)/board-$(board).config) + $(Q)$(MAKE) olddefconfig + +# +# Prevent generic merge_config rules attempting to merge single fragments +# +$(generic_config_dir)/%.config: ; diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile index ed656636accec..2728a9a9c7c5b 100644 --- a/arch/mips/boot/Makefile +++ b/arch/mips/boot/Makefile @@ -111,13 +111,22 @@ targets += vmlinux.bz2.itb targets += vmlinux.lzma.itb targets += vmlinux.lzo.itb +ifeq ($(ADDR_BITS),32) + itb_addr_cells = 1 +endif +ifeq ($(ADDR_BITS),64) + itb_addr_cells = 2 +endif + quiet_cmd_cpp_its_S = ITS $@ cmd_cpp_its_S = $(CPP) $(cpp_flags) -P -C -o $@ $< \ -DKERNEL_NAME="\"Linux $(KERNELRELEASE)\"" \ -DVMLINUX_BINARY="\"$(3)\"" \ -DVMLINUX_COMPRESSION="\"$(2)\"" \ -DVMLINUX_LOAD_ADDRESS=$(VMLINUX_LOAD_ADDRESS) \ - -DVMLINUX_ENTRY_ADDRESS=$(VMLINUX_ENTRY_ADDRESS) + -DVMLINUX_ENTRY_ADDRESS=$(VMLINUX_ENTRY_ADDRESS) \ + -DADDR_BITS=$(ADDR_BITS) \ + -DADDR_CELLS=$(itb_addr_cells) $(obj)/vmlinux.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE $(call if_changed_dep,cpp_its_S,none,vmlinux.bin) diff --git a/arch/mips/configs/generic/32r1.config b/arch/mips/configs/generic/32r1.config new file mode 100644 index 0000000000000..a11cd8715519e --- /dev/null +++ b/arch/mips/configs/generic/32r1.config @@ -0,0 +1,2 @@ +CONFIG_CPU_MIPS32_R1=y +CONFIG_HIGHMEM=y diff --git a/arch/mips/configs/generic/32r2.config b/arch/mips/configs/generic/32r2.config new file mode 100644 index 0000000000000..9570672d4f9f6 --- /dev/null +++ b/arch/mips/configs/generic/32r2.config @@ -0,0 +1,3 @@ +CONFIG_CPU_MIPS32_R2=y +CONFIG_MIPS_O32_FP64_SUPPORT=y +CONFIG_HIGHMEM=y diff --git a/arch/mips/configs/generic/32r6.config b/arch/mips/configs/generic/32r6.config new file mode 100644 index 0000000000000..ca606e71f4d02 --- /dev/null +++ b/arch/mips/configs/generic/32r6.config @@ -0,0 +1,2 @@ +CONFIG_CPU_MIPS32_R6=y +CONFIG_HIGHMEM=y diff --git a/arch/mips/configs/generic/64r1.config b/arch/mips/configs/generic/64r1.config new file mode 100644 index 0000000000000..7c1ea7e7bae32 --- /dev/null +++ b/arch/mips/configs/generic/64r1.config @@ -0,0 +1,4 @@ +CONFIG_CPU_MIPS64_R1=y +CONFIG_64BIT=y +CONFIG_MIPS32_O32=y +CONFIG_MIPS32_N32=y diff --git a/arch/mips/configs/generic/64r2.config b/arch/mips/configs/generic/64r2.config new file mode 100644 index 0000000000000..b4d31ae8bfec0 --- /dev/null +++ b/arch/mips/configs/generic/64r2.config @@ -0,0 +1,5 @@ +CONFIG_CPU_MIPS64_R2=y +CONFIG_MIPS_O32_FP64_SUPPORT=y +CONFIG_64BIT=y +CONFIG_MIPS32_O32=y +CONFIG_MIPS32_N32=y diff --git a/arch/mips/configs/generic/64r6.config b/arch/mips/configs/generic/64r6.config new file mode 100644 index 0000000000000..7cac0339c4d52 --- /dev/null +++ b/arch/mips/configs/generic/64r6.config @@ -0,0 +1,4 @@ +CONFIG_CPU_MIPS64_R6=y +CONFIG_64BIT=y +CONFIG_MIPS32_O32=y +CONFIG_MIPS32_N32=y diff --git a/arch/mips/configs/generic/eb.config b/arch/mips/configs/generic/eb.config new file mode 100644 index 0000000000000..c5cdc99a6530f --- /dev/null +++ b/arch/mips/configs/generic/eb.config @@ -0,0 +1 @@ +CONFIG_CPU_BIG_ENDIAN=y diff --git a/arch/mips/configs/generic/el.config b/arch/mips/configs/generic/el.config new file mode 100644 index 0000000000000..ee43fdb3b8f4c --- /dev/null +++ b/arch/mips/configs/generic/el.config @@ -0,0 +1 @@ +CONFIG_CPU_LITTLE_ENDIAN=y diff --git a/arch/mips/configs/generic/micro32r2.config b/arch/mips/configs/generic/micro32r2.config new file mode 100644 index 0000000000000..b701fe7aaa680 --- /dev/null +++ b/arch/mips/configs/generic/micro32r2.config @@ -0,0 +1,4 @@ +CONFIG_CPU_MIPS32_R2=y +CONFIG_CPU_MICROMIPS=y +CONFIG_MIPS_O32_FP64_SUPPORT=y +CONFIG_HIGHMEM=y diff --git a/arch/mips/configs/generic_defconfig b/arch/mips/configs/generic_defconfig new file mode 100644 index 0000000000000..c95d94c7838bc --- /dev/null +++ b/arch/mips/configs/generic_defconfig @@ -0,0 +1,96 @@ +CONFIG_MIPS_GENERIC=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_MIPS_CPS=y +CONFIG_CPU_HAS_MSA=y +CONFIG_HIGHMEM=y +CONFIG_NR_CPUS=2 +CONFIG_MIPS_O32_FP64_SUPPORT=y +CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BPF_SYSCALL=y +CONFIG_USERFAULTFD=y +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_TRIM_UNUSED_KSYMS=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_NETFILTER=y +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_SCSI=y +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +CONFIG_HW_RANDOM=y +# CONFIG_HWMON is not set +CONFIG_MFD_SYSCON=y +CONFIG_HID_A4TECH=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +# CONFIG_USB_SUPPORT is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_FANOTIFY=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_REDUCED=y +CONFIG_DEBUG_FS=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_FTRACE is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon" +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set diff --git a/arch/mips/generic/Kconfig b/arch/mips/generic/Kconfig new file mode 100644 index 0000000000000..baddb0646b23c --- /dev/null +++ b/arch/mips/generic/Kconfig @@ -0,0 +1,12 @@ +if MIPS_GENERIC + +config LEGACY_BOARDS + bool + help + Select this from your board if the board must use a legacy, non-UHI, + boot protocol. This will cause the kernel to scan through the list of + supported machines calling their detect functions in turn if the + kernel is booted without being provided with an FDT via the UHI + boot protocol. + +endif diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile new file mode 100644 index 0000000000000..26e64207f7ad1 --- /dev/null +++ b/arch/mips/generic/Makefile @@ -0,0 +1,13 @@ +# +# Copyright (C) 2016 Imagination Technologies +# Author: Paul Burton +# +# 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; either version 2 of the License, or (at your +# option) any later version. +# + +obj-y += init.o +obj-y += irq.o +obj-y += proc.o diff --git a/arch/mips/generic/Platform b/arch/mips/generic/Platform new file mode 100644 index 0000000000000..9a30d69e22816 --- /dev/null +++ b/arch/mips/generic/Platform @@ -0,0 +1,14 @@ +# +# Copyright (C) 2016 Imagination Technologies +# Author: Paul Burton +# +# 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; either version 2 of the License, or (at your +# option) any later version. +# + +platform-$(CONFIG_MIPS_GENERIC) += generic/ +cflags-$(CONFIG_MIPS_GENERIC) += -I$(srctree)/arch/mips/include/asm/mach-generic +load-$(CONFIG_MIPS_GENERIC) += 0xffffffff80100000 +all-$(CONFIG_MIPS_GENERIC) := vmlinux.gz.itb diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c new file mode 100644 index 0000000000000..0ea73e8454404 --- /dev/null +++ b/arch/mips/generic/init.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static __initdata const void *fdt; +static __initdata const struct mips_machine *mach; +static __initdata const void *mach_match_data; + +void __init prom_init(void) +{ + const struct mips_machine *check_mach; + const struct of_device_id *match; + + if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) { + /* + * We booted using the UHI boot protocol, so we have been + * provided with the appropriate device tree for the board. + * Make use of it & search for any machine struct based upon + * the root compatible string. + */ + fdt = (void *)fw_arg1; + + for_each_mips_machine(check_mach) { + match = mips_machine_is_compatible(check_mach, fdt); + if (match) { + mach = check_mach; + mach_match_data = match->data; + break; + } + } + } else if (IS_ENABLED(CONFIG_LEGACY_BOARDS)) { + /* + * We weren't booted using the UHI boot protocol, but do + * support some number of boards with legacy boot protocols. + * Attempt to find the right one. + */ + for_each_mips_machine(check_mach) { + if (!check_mach->detect) + continue; + + if (!check_mach->detect()) + continue; + + mach = check_mach; + } + + /* + * If we don't recognise the machine then we can't continue, so + * die here. + */ + BUG_ON(!mach); + + /* Retrieve the machine's FDT */ + fdt = mach->fdt; + } + + BUG_ON(!fdt); +} + +void __init *plat_get_fdt(void) +{ + return (void *)fdt; +} + +void __init plat_mem_setup(void) +{ + if (mach && mach->fixup_fdt) + fdt = mach->fixup_fdt(fdt, mach_match_data); + + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); + __dt_setup_arch((void *)fdt); +} + +void __init device_tree_init(void) +{ + int err; + + unflatten_and_copy_device_tree(); + mips_cpc_probe(); + + err = register_cps_smp_ops(); + if (err) + err = register_up_smp_ops(); +} + +void __init plat_time_init(void) +{ + struct device_node *np; + struct clk *clk; + + of_clk_init(NULL); + + if (!cpu_has_counter) { + mips_hpt_frequency = 0; + } else if (mach && mach->measure_hpt_freq) { + mips_hpt_frequency = mach->measure_hpt_freq(); + } else { + np = of_get_cpu_node(0, NULL); + if (!np) { + pr_err("Failed to get CPU node\n"); + return; + } + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk)); + return; + } + + mips_hpt_frequency = clk_get_rate(clk); + clk_put(clk); + + switch (boot_cpu_type()) { + case CPU_20KC: + case CPU_25KF: + /* The counter runs at the CPU clock rate */ + break; + default: + /* The counter runs at half the CPU clock rate */ + mips_hpt_frequency /= 2; + break; + } + } + + clocksource_probe(); +} + +void __init arch_init_irq(void) +{ + struct device_node *intc_node; + + intc_node = of_find_compatible_node(NULL, NULL, + "mti,cpu-interrupt-controller"); + if (!cpu_has_veic && !intc_node) + mips_cpu_irq_init(); + + irqchip_init(); +} + +static int __init publish_devices(void) +{ + if (!of_have_populated_dt()) + panic("Device-tree not present"); + + if (of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL)) + panic("Failed to populate DT"); + + return 0; +} +arch_initcall(publish_devices); + +void __init prom_free_prom_memory(void) +{ +} diff --git a/arch/mips/generic/irq.c b/arch/mips/generic/irq.c new file mode 100644 index 0000000000000..14064bdd91ddc --- /dev/null +++ b/arch/mips/generic/irq.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include + +int get_c0_fdc_int(void) +{ + int mips_cpu_fdc_irq; + + if (cpu_has_veic) + panic("Unimplemented!"); + else if (gic_present) + mips_cpu_fdc_irq = gic_get_c0_fdc_int(); + else if (cp0_fdc_irq >= 0) + mips_cpu_fdc_irq = MIPS_CPU_IRQ_BASE + cp0_fdc_irq; + else + mips_cpu_fdc_irq = -1; + + return mips_cpu_fdc_irq; +} + +int get_c0_perfcount_int(void) +{ + int mips_cpu_perf_irq; + + if (cpu_has_veic) + panic("Unimplemented!"); + else if (gic_present) + mips_cpu_perf_irq = gic_get_c0_perfcount_int(); + else if (cp0_perfcount_irq >= 0) + mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; + else + mips_cpu_perf_irq = -1; + + return mips_cpu_perf_irq; +} + +unsigned int get_c0_compare_int(void) +{ + int mips_cpu_timer_irq; + + if (cpu_has_veic) + panic("Unimplemented!"); + else if (gic_present) + mips_cpu_timer_irq = gic_get_c0_compare_int(); + else + mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; + + return mips_cpu_timer_irq; +} diff --git a/arch/mips/generic/proc.c b/arch/mips/generic/proc.c new file mode 100644 index 0000000000000..42b33250a4a2e --- /dev/null +++ b/arch/mips/generic/proc.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include + +#include + +const char *get_system_type(void) +{ + const char *str; + int err; + + err = of_property_read_string(of_root, "model", &str); + if (!err) + return str; + + err = of_property_read_string_index(of_root, "compatible", 0, &str); + if (!err) + return str; + + return "Unknown"; +} diff --git a/arch/mips/generic/vmlinux.its.S b/arch/mips/generic/vmlinux.its.S new file mode 100644 index 0000000000000..f67fbf1c85417 --- /dev/null +++ b/arch/mips/generic/vmlinux.its.S @@ -0,0 +1,31 @@ +/dts-v1/; + +/ { + description = KERNEL_NAME; + #address-cells = ; + + images { + kernel@0 { + description = KERNEL_NAME; + data = /incbin/(VMLINUX_BINARY); + type = "kernel"; + arch = "mips"; + os = "linux"; + compression = VMLINUX_COMPRESSION; + load = /bits/ ADDR_BITS ; + entry = /bits/ ADDR_BITS ; + hash@0 { + algo = "sha1"; + }; + }; + }; + + configurations { + default = "conf@default"; + + conf@default { + description = "Generic Linux kernel"; + kernel = "kernel@0"; + }; + }; +}; diff --git a/arch/mips/include/asm/machine.h b/arch/mips/include/asm/machine.h new file mode 100644 index 0000000000000..6b444cd9526fe --- /dev/null +++ b/arch/mips/include/asm/machine.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __MIPS_ASM_MACHINE_H__ +#define __MIPS_ASM_MACHINE_H__ + +#include +#include + +struct mips_machine { + const struct of_device_id *matches; + const void *fdt; + bool (*detect)(void); + const void *(*fixup_fdt)(const void *fdt, const void *match_data); + unsigned int (*measure_hpt_freq)(void); +}; + +extern long __mips_machines_start; +extern long __mips_machines_end; + +#define MIPS_MACHINE(name) \ + static const struct mips_machine __mips_mach_##name \ + __used __section(.mips.machines.init) + +#define for_each_mips_machine(mach) \ + for ((mach) = (struct mips_machine *)&__mips_machines_start; \ + (mach) < (struct mips_machine *)&__mips_machines_end; \ + (mach)++) + +/** + * mips_machine_is_compatible() - check if a machine is compatible with an FDT + * @mach: the machine struct to check + * @fdt: the FDT to check for compatibility with + * + * Check whether the given machine @mach is compatible with the given flattened + * device tree @fdt, based upon the compatibility property of the root node. + * + * Return: the device id matched if any, else NULL + */ +static inline const struct of_device_id * +mips_machine_is_compatible(const struct mips_machine *mach, const void *fdt) +{ + const struct of_device_id *match; + + if (!mach->matches) + return NULL; + + for (match = mach->matches; match->compatible; match++) { + if (fdt_node_check_compatible(fdt, 0, match->compatible) == 0) + return match; + } + + return NULL; +} + +#endif /* __MIPS_ASM_MACHINE_H__ */ -- GitLab From 3f5f0a4475e13345326061f00c68f428232ba2bc Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:21 +0100 Subject: [PATCH 0337/1167] MIPS: generic: Convert SEAD-3 to a generic board Convert the MIPS SEAD-3 board support to be a generic board, supported by generic kernels. Because the SEAD-3 boot protocol was defined long ago and we don't want to force a switch to the UHI protocol, SEAD-3 is added as a legacy board which is detected by reading the REVISION register. This may technically not be a valid memory read & future work will include attempting to handle that gracefully. In practice since SEAD-3 is the only legacy board supported by the generic kernel so far the read will only happen on SEAD-3 boards, and even once Malta is converted the same REVISION register exists there too. Other boards such as Boston, Ci20 & Ci40 will use the UHI boot protocol & thus not run any of the legacy board detect functions. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14354/ Signed-off-by: Ralf Baechle --- arch/mips/Kbuild.platforms | 1 - arch/mips/Kconfig | 37 +---- arch/mips/Makefile | 13 ++ arch/mips/boot/dts/mti/Makefile | 2 +- arch/mips/boot/dts/mti/sead3.dts | 1 + arch/mips/configs/generic/board-sead-3.config | 32 +++++ arch/mips/configs/sead3_defconfig | 129 ------------------ arch/mips/configs/sead3micro_defconfig | 122 ----------------- arch/mips/generic/Kconfig | 7 + arch/mips/generic/Makefile | 2 + .../sead3-dtshim.c => generic/board-sead3.c} | 106 ++++++++++++-- .../asm/mach-sead3/cpu-feature-overrides.h | 72 ---------- arch/mips/include/asm/mach-sead3/irq.h | 9 -- .../asm/mach-sead3/kernel-entry-init.h | 21 --- .../include/asm/mach-sead3/sead3-dtshim.h | 29 ---- arch/mips/include/asm/mach-sead3/war.h | 24 ---- arch/mips/mti-sead3/Makefile | 15 -- arch/mips/mti-sead3/Platform | 7 - arch/mips/mti-sead3/sead3-init.c | 100 -------------- arch/mips/mti-sead3/sead3-int.c | 23 ---- arch/mips/mti-sead3/sead3-setup.c | 39 ------ arch/mips/mti-sead3/sead3-time.c | 91 ------------ 22 files changed, 152 insertions(+), 730 deletions(-) create mode 100644 arch/mips/configs/generic/board-sead-3.config delete mode 100644 arch/mips/configs/sead3_defconfig delete mode 100644 arch/mips/configs/sead3micro_defconfig rename arch/mips/{mti-sead3/sead3-dtshim.c => generic/board-sead3.c} (72%) delete mode 100644 arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h delete mode 100644 arch/mips/include/asm/mach-sead3/irq.h delete mode 100644 arch/mips/include/asm/mach-sead3/kernel-entry-init.h delete mode 100644 arch/mips/include/asm/mach-sead3/sead3-dtshim.h delete mode 100644 arch/mips/include/asm/mach-sead3/war.h delete mode 100644 arch/mips/mti-sead3/Makefile delete mode 100644 arch/mips/mti-sead3/Platform delete mode 100644 arch/mips/mti-sead3/sead3-init.c delete mode 100644 arch/mips/mti-sead3/sead3-int.c delete mode 100644 arch/mips/mti-sead3/sead3-setup.c delete mode 100644 arch/mips/mti-sead3/sead3-time.c diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 9c1e8f9f854aa..f5f1bdb292de0 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -19,7 +19,6 @@ platforms += lasat platforms += loongson32 platforms += loongson64 platforms += mti-malta -platforms += mti-sead3 platforms += netlogic platforms += paravirt platforms += pic32 diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 82b45dc9fa4de..a7d9224c2a508 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -546,41 +546,6 @@ config MACH_PIC32 Microchip PIC32 is a family of general-purpose 32 bit MIPS core microcontrollers. -config MIPS_SEAD3 - bool "MIPS SEAD3 board" - select BOOT_ELF32 - select BOOT_RAW - select BUILTIN_DTB - select CEVT_R4K - select CSRC_R4K - select CLKSRC_MIPS_GIC - select COMMON_CLK - select CPU_MIPSR2_IRQ_VI - select CPU_MIPSR2_IRQ_EI - select DMA_NONCOHERENT - select IRQ_MIPS_CPU - select MIPS_GIC - select LIBFDT - select MIPS_MSC - select SYS_HAS_CPU_MIPS32_R1 - select SYS_HAS_CPU_MIPS32_R2 - select SYS_HAS_CPU_MIPS32_R6 - select SYS_HAS_CPU_MIPS64_R1 - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_64BIT_KERNEL - select SYS_SUPPORTS_BIG_ENDIAN - select SYS_SUPPORTS_LITTLE_ENDIAN - select SYS_SUPPORTS_SMARTMIPS - select SYS_SUPPORTS_MICROMIPS - select SYS_SUPPORTS_MIPS16 - select SYS_SUPPORTS_RELOCATABLE - select USB_EHCI_BIG_ENDIAN_DESC - select USB_EHCI_BIG_ENDIAN_MMIO - select USE_OF - help - This enables support for the MIPS Technologies SEAD3 evaluation - board. - config NEC_MARKEINS bool "NEC EMMA2RH Mark-eins board" select SOC_EMMA2RH @@ -2976,7 +2941,7 @@ endchoice choice prompt "Kernel command line type" if !CMDLINE_OVERRIDE default MIPS_CMDLINE_FROM_DTB if USE_OF && !ATH79 && !MACH_INGENIC && \ - !MIPS_MALTA && !MIPS_SEAD3 && \ + !MIPS_MALTA && \ !CAVIUM_OCTEON_SOC default MIPS_CMDLINE_FROM_BOOTLOADER diff --git a/arch/mips/Makefile b/arch/mips/Makefile index f3e768a69a52b..fbf40d3c81239 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -488,3 +488,16 @@ $(generic_defconfigs): # Prevent generic merge_config rules attempting to merge single fragments # $(generic_config_dir)/%.config: ; + +# +# Legacy defconfig compatibility - these targets used to be real defconfigs but +# now that the boards have been converted to use the generic kernel they are +# wrappers around the generic rules above. +# +.PHONY: sead3_defconfig +sead3_defconfig: + $(Q)$(MAKE) 32r2el_defconfig BOARDS=sead-3 + +.PHONY: sead3micro_defconfig +sead3micro_defconfig: + $(Q)$(MAKE) micro32r2el_defconfig BOARDS=sead-3 diff --git a/arch/mips/boot/dts/mti/Makefile b/arch/mips/boot/dts/mti/Makefile index 144d776cc9f2a..fcabd69b70301 100644 --- a/arch/mips/boot/dts/mti/Makefile +++ b/arch/mips/boot/dts/mti/Makefile @@ -1,5 +1,5 @@ dtb-$(CONFIG_MIPS_MALTA) += malta.dtb -dtb-$(CONFIG_MIPS_SEAD3) += sead3.dtb +dtb-$(CONFIG_LEGACY_BOARD_SEAD3) += sead3.dtb obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y)) diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index 2579ca51c0b61..b112879a5d9d3 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -10,6 +10,7 @@ #address-cells = <1>; #size-cells = <1>; compatible = "mti,sead-3"; + model = "MIPS SEAD-3"; interrupt-parent = <&gic>; chosen { diff --git a/arch/mips/configs/generic/board-sead-3.config b/arch/mips/configs/generic/board-sead-3.config new file mode 100644 index 0000000000000..3b5e1ac579ebb --- /dev/null +++ b/arch/mips/configs/generic/board-sead-3.config @@ -0,0 +1,32 @@ +CONFIG_LEGACY_BOARD_SEAD3=y + +CONFIG_AUXDISPLAY=y +CONFIG_IMG_ASCII_LCD=y + +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_SYSCON=y + +CONFIG_MMC=y +CONFIG_MMC_SPI=y + +CONFIG_MTD=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_GLUEBI=y + +CONFIG_NETDEVICES=y +CONFIG_SMSC911X=y +CONFIG_SMSC_PHY=y + +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y + +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y diff --git a/arch/mips/configs/sead3_defconfig b/arch/mips/configs/sead3_defconfig deleted file mode 100644 index ab4c465d8025e..0000000000000 --- a/arch/mips/configs/sead3_defconfig +++ /dev/null @@ -1,129 +0,0 @@ -CONFIG_MIPS_SEAD3=y -CONFIG_CPU_LITTLE_ENDIAN=y -CONFIG_CPU_MIPS32_R2=y -CONFIG_HZ_100=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=15 -CONFIG_EMBEDDED=y -CONFIG_SLAB=y -CONFIG_PROFILING=y -CONFIG_OPROFILE=y -CONFIG_MODULES=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="earlycon" -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_LRO is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -# CONFIG_WIRELESS is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_DEVTMPFS=y -CONFIG_MTD=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_UBI=y -CONFIG_MTD_UBI_GLUEBI=y -CONFIG_OF=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_CRYPTOLOOP=m -CONFIG_SCSI=y -# CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_SG=y -# CONFIG_SCSI_LOWLEVEL is not set -CONFIG_NETDEVICES=y -CONFIG_SMSC911X=y -# CONFIG_NET_VENDOR_WIZNET is not set -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_QSEMI_PHY=y -CONFIG_LXT_PHY=y -CONFIG_CICADA_PHY=y -CONFIG_VITESSE_PHY=y -CONFIG_SMSC_PHY=y -CONFIG_BROADCOM_PHY=y -CONFIG_ICPLUS_PHY=y -# CONFIG_WLAN is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_CONSOLE_TRANSLATIONS is not set -CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_LEGACY_PTY_COUNT=32 -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=2 -CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -# CONFIG_I2C_COMPAT is not set -CONFIG_I2C_CHARDEV=y -# CONFIG_I2C_HELPER_AUTO is not set -CONFIG_SPI=y -CONFIG_POWER_RESET=y -CONFIG_POWER_RESET_RESTART=y -CONFIG_POWER_RESET_SYSCON=y -CONFIG_SENSORS_ADT7475=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_LCD_CLASS_DEVICE=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_USB=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_ROOT_HUB_TT=y -CONFIG_USB_STORAGE=y -CONFIG_MMC=y -CONFIG_MMC_DEBUG=y -CONFIG_MMC_SPI=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_SYSCON=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_M41T80=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -CONFIG_XFS_POSIX_ACL=y -CONFIG_QUOTA=y -# CONFIG_PRINT_QUOTA_WARNING is not set -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_ISO8859_15=y -CONFIG_NLS_UTF8=y -# CONFIG_FTRACE is not set -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_ARC4=y -# CONFIG_CRYPTO_ANSI_CPRNG is not set -# CONFIG_CRYPTO_HW is not set diff --git a/arch/mips/configs/sead3micro_defconfig b/arch/mips/configs/sead3micro_defconfig deleted file mode 100644 index cd91a775c74ef..0000000000000 --- a/arch/mips/configs/sead3micro_defconfig +++ /dev/null @@ -1,122 +0,0 @@ -CONFIG_MIPS_SEAD3=y -CONFIG_CPU_LITTLE_ENDIAN=y -CONFIG_CPU_MIPS32_R2=y -CONFIG_CPU_MICROMIPS=y -CONFIG_HZ_100=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=15 -CONFIG_EMBEDDED=y -CONFIG_SLAB=y -CONFIG_PROFILING=y -CONFIG_OPROFILE=y -CONFIG_MODULES=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_LRO is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -# CONFIG_WIRELESS is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_DEVTMPFS=y -CONFIG_MTD=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_UBI=y -CONFIG_MTD_UBI_GLUEBI=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_CRYPTOLOOP=m -CONFIG_SCSI=y -# CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_SG=y -# CONFIG_SCSI_LOWLEVEL is not set -CONFIG_NETDEVICES=y -CONFIG_SMSC911X=y -# CONFIG_NET_VENDOR_WIZNET is not set -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_QSEMI_PHY=y -CONFIG_LXT_PHY=y -CONFIG_CICADA_PHY=y -CONFIG_VITESSE_PHY=y -CONFIG_SMSC_PHY=y -CONFIG_BROADCOM_PHY=y -CONFIG_ICPLUS_PHY=y -# CONFIG_WLAN is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_CONSOLE_TRANSLATIONS is not set -CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_LEGACY_PTY_COUNT=32 -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=2 -CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -# CONFIG_I2C_COMPAT is not set -CONFIG_I2C_CHARDEV=y -# CONFIG_I2C_HELPER_AUTO is not set -CONFIG_SPI=y -CONFIG_SENSORS_ADT7475=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_LCD_CLASS_DEVICE=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_USB=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_ROOT_HUB_TT=y -CONFIG_USB_STORAGE=y -CONFIG_MMC=y -CONFIG_MMC_DEBUG=y -CONFIG_MMC_SPI=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_M41T80=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -CONFIG_XFS_POSIX_ACL=y -CONFIG_QUOTA=y -# CONFIG_PRINT_QUOTA_WARNING is not set -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_ISO8859_15=y -CONFIG_NLS_UTF8=y -# CONFIG_FTRACE is not set -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_ARC4=y -# CONFIG_CRYPTO_ANSI_CPRNG is not set -# CONFIG_CRYPTO_HW is not set diff --git a/arch/mips/generic/Kconfig b/arch/mips/generic/Kconfig index baddb0646b23c..a606b3f9196c6 100644 --- a/arch/mips/generic/Kconfig +++ b/arch/mips/generic/Kconfig @@ -9,4 +9,11 @@ config LEGACY_BOARDS kernel is booted without being provided with an FDT via the UHI boot protocol. +config LEGACY_BOARD_SEAD3 + bool "Support MIPS SEAD-3 boards" + select LEGACY_BOARDS + help + Enable this to include support for booting on MIPS SEAD-3 FPGA-based + development boards, which boot using a legacy boot protocol. + endif diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile index 26e64207f7ad1..7c66494151db5 100644 --- a/arch/mips/generic/Makefile +++ b/arch/mips/generic/Makefile @@ -11,3 +11,5 @@ obj-y += init.o obj-y += irq.o obj-y += proc.o + +obj-$(CONFIG_LEGACY_BOARD_SEAD3) += board-sead3.o diff --git a/arch/mips/mti-sead3/sead3-dtshim.c b/arch/mips/generic/board-sead3.c similarity index 72% rename from arch/mips/mti-sead3/sead3-dtshim.c rename to arch/mips/generic/board-sead3.c index d6b0708d7a6f4..f4ae0584a33bd 100644 --- a/arch/mips/mti-sead3/sead3-dtshim.c +++ b/arch/mips/generic/board-sead3.c @@ -4,11 +4,11 @@ * * 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; either version 2 of the License, or (at your + * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#define pr_fmt(fmt) "sead3-dtshim: " fmt +#define pr_fmt(fmt) "sead3: " fmt #include #include @@ -16,13 +16,49 @@ #include #include +#include #define SEAD_CONFIG CKSEG1ADDR(0x1b100110) #define SEAD_CONFIG_GIC_PRESENT BIT(1) -static unsigned char fdt_buf[16 << 10] __initdata; +#define MIPS_REVISION CKSEG1ADDR(0x1fc00010) +#define MIPS_REVISION_MACHINE (0xf << 4) +#define MIPS_REVISION_MACHINE_SEAD3 (0x4 << 4) -static int append_memory(void *fdt) +static __init bool sead3_detect(void) +{ + uint32_t rev; + + rev = __raw_readl((void *)MIPS_REVISION); + return (rev & MIPS_REVISION_MACHINE) == MIPS_REVISION_MACHINE_SEAD3; +} + +static __init int append_cmdline(void *fdt) +{ + int err, chosen_off; + + /* find or add chosen node */ + chosen_off = fdt_path_offset(fdt, "/chosen"); + if (chosen_off == -FDT_ERR_NOTFOUND) + chosen_off = fdt_path_offset(fdt, "/chosen@0"); + if (chosen_off == -FDT_ERR_NOTFOUND) + chosen_off = fdt_add_subnode(fdt, 0, "chosen"); + if (chosen_off < 0) { + pr_err("Unable to find or add DT chosen node: %d\n", + chosen_off); + return chosen_off; + } + + err = fdt_setprop_string(fdt, chosen_off, "bootargs", fw_getcmdline()); + if (err) { + pr_err("Unable to set bootargs property: %d\n", err); + return err; + } + + return 0; +} + +static __init int append_memory(void *fdt) { unsigned long phys_memsize, memsize; __be32 mem_array[2]; @@ -89,7 +125,7 @@ static int append_memory(void *fdt) return 0; } -static int remove_gic(void *fdt) +static __init int remove_gic(void *fdt) { const unsigned int cpu_ehci_int = 2; const unsigned int cpu_uart_int = 4; @@ -163,7 +199,7 @@ static int remove_gic(void *fdt) return err; } - ehci_off = fdt_node_offset_by_compatible(fdt, -1, "mti,sead3-ehci"); + ehci_off = fdt_node_offset_by_compatible(fdt, -1, "generic-ehci"); if (ehci_off < 0) { pr_err("unable to find EHCI DT node: %d\n", ehci_off); return ehci_off; @@ -178,7 +214,7 @@ static int remove_gic(void *fdt) return 0; } -static int serial_config(void *fdt) +static __init int serial_config(void *fdt) { const char *yamontty, *mode_var; char mode_var_name[9], path[18], parity; @@ -257,21 +293,28 @@ static int serial_config(void *fdt) return 0; } -void __init *sead3_dt_shim(void *fdt) +static __init const void *sead3_fixup_fdt(const void *fdt, + const void *match_data) { + static unsigned char fdt_buf[16 << 10] __initdata; int err; if (fdt_check_header(fdt)) panic("Corrupt DT"); - /* if this isn't SEAD3, leave the DT alone */ - if (fdt_node_check_compatible(fdt, 0, "mti,sead-3")) - return fdt; + /* if this isn't SEAD3, something went wrong */ + BUG_ON(fdt_node_check_compatible(fdt, 0, "mti,sead-3")); + + fw_init_cmdline(); err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf)); if (err) panic("Unable to open FDT: %d", err); + err = append_cmdline(fdt_buf); + if (err) + panic("Unable to patch FDT: %d", err); + err = append_memory(fdt_buf); if (err) panic("Unable to patch FDT: %d", err); @@ -290,3 +333,44 @@ void __init *sead3_dt_shim(void *fdt) return fdt_buf; } + +static __init unsigned int sead3_measure_hpt_freq(void) +{ + void __iomem *status_reg = (void __iomem *)0xbf000410; + unsigned int freq, orig, tick = 0; + unsigned long flags; + + local_irq_save(flags); + + orig = readl(status_reg) & 0x2; /* get original sample */ + /* wait for transition */ + while ((readl(status_reg) & 0x2) == orig) + ; + orig = orig ^ 0x2; /* flip the bit */ + + write_c0_count(0); + + /* wait 1 second (the sampling clock transitions every 10ms) */ + while (tick < 100) { + /* wait for transition */ + while ((readl(status_reg) & 0x2) == orig) + ; + orig = orig ^ 0x2; /* flip the bit */ + tick++; + } + + freq = read_c0_count(); + + local_irq_restore(flags); + + return freq; +} + +extern char __dtb_sead3_begin[]; + +MIPS_MACHINE(sead3) = { + .fdt = __dtb_sead3_begin, + .detect = sead3_detect, + .fixup_fdt = sead3_fixup_fdt, + .measure_hpt_freq = sead3_measure_hpt_freq, +}; diff --git a/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h b/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h deleted file mode 100644 index bfbd7035d4c54..0000000000000 --- a/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2003, 2004 Chris Dearman - * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) - */ -#ifndef __ASM_MACH_MIPS_CPU_FEATURE_OVERRIDES_H -#define __ASM_MACH_MIPS_CPU_FEATURE_OVERRIDES_H - - -/* - * CPU feature overrides for MIPS boards - */ -#ifdef CONFIG_CPU_MIPS32 -#define cpu_has_tlb 1 -#define cpu_has_4kex 1 -#define cpu_has_4k_cache 1 -/* #define cpu_has_fpu ? */ -/* #define cpu_has_32fpr ? */ -#define cpu_has_counter 1 -/* #define cpu_has_watch ? */ -#define cpu_has_divec 1 -#define cpu_has_vce 0 -/* #define cpu_has_cache_cdex_p ? */ -/* #define cpu_has_cache_cdex_s ? */ -/* #define cpu_has_prefetch ? */ -#define cpu_has_mcheck 1 -/* #define cpu_has_ejtag ? */ -#ifdef CONFIG_CPU_MICROMIPS -#define cpu_has_llsc 0 -#else -#define cpu_has_llsc 1 -#endif -/* #define cpu_has_vtag_icache ? */ -/* #define cpu_has_dc_aliases ? */ -/* #define cpu_has_ic_fills_f_dc ? */ -#define cpu_has_nofpuex 0 -/* #define cpu_has_64bits ? */ -/* #define cpu_has_64bit_zero_reg ? */ -/* #define cpu_has_inclusive_pcaches ? */ -#define cpu_icache_snoops_remote_store 1 -#endif - -#ifdef CONFIG_CPU_MIPS64 -#define cpu_has_tlb 1 -#define cpu_has_4kex 1 -#define cpu_has_4k_cache 1 -/* #define cpu_has_fpu ? */ -/* #define cpu_has_32fpr ? */ -#define cpu_has_counter 1 -/* #define cpu_has_watch ? */ -#define cpu_has_divec 1 -#define cpu_has_vce 0 -/* #define cpu_has_cache_cdex_p ? */ -/* #define cpu_has_cache_cdex_s ? */ -/* #define cpu_has_prefetch ? */ -#define cpu_has_mcheck 1 -/* #define cpu_has_ejtag ? */ -#define cpu_has_llsc 1 -/* #define cpu_has_vtag_icache ? */ -/* #define cpu_has_dc_aliases ? */ -/* #define cpu_has_ic_fills_f_dc ? */ -#define cpu_has_nofpuex 0 -/* #define cpu_has_64bits ? */ -/* #define cpu_has_64bit_zero_reg ? */ -/* #define cpu_has_inclusive_pcaches ? */ -#define cpu_icache_snoops_remote_store 1 -#endif - -#endif /* __ASM_MACH_MIPS_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/include/asm/mach-sead3/irq.h b/arch/mips/include/asm/mach-sead3/irq.h deleted file mode 100644 index 5d154cfbcf4c7..0000000000000 --- a/arch/mips/include/asm/mach-sead3/irq.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __ASM_MACH_MIPS_IRQ_H -#define __ASM_MACH_MIPS_IRQ_H - -#define NR_IRQS 256 - - -#include_next - -#endif /* __ASM_MACH_MIPS_IRQ_H */ diff --git a/arch/mips/include/asm/mach-sead3/kernel-entry-init.h b/arch/mips/include/asm/mach-sead3/kernel-entry-init.h deleted file mode 100644 index 6cccd4d558d74..0000000000000 --- a/arch/mips/include/asm/mach-sead3/kernel-entry-init.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Chris Dearman (chris@mips.com) - * Copyright (C) 2007 Mips Technologies, Inc. - */ -#ifndef __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H -#define __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H - - .macro kernel_entry_setup - .endm - -/* - * Do SMP slave processor setup necessary before we can safely execute C code. - */ - .macro smp_slave_setup - .endm - -#endif /* __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H */ diff --git a/arch/mips/include/asm/mach-sead3/sead3-dtshim.h b/arch/mips/include/asm/mach-sead3/sead3-dtshim.h deleted file mode 100644 index f5d7d9c9dd177..0000000000000 --- a/arch/mips/include/asm/mach-sead3/sead3-dtshim.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2016 Imagination Technologies - * Author: Paul Burton - * - * 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; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifndef __MIPS_SEAD3_DTSHIM_H__ -#define __MIPS_SEAD3_DTSHIM_H__ - -#include - -#ifdef CONFIG_MIPS_SEAD3 - -extern void __init *sead3_dt_shim(void *fdt); - -#else /* !CONFIG_MIPS_SEAD3 */ - -static inline void *sead3_dt_shim(void *fdt) -{ - return fdt; -} - -#endif /* !CONFIG_MIPS_SEAD3 */ - -#endif /* __MIPS_SEAD3_DTSHIM_H__ */ diff --git a/arch/mips/include/asm/mach-sead3/war.h b/arch/mips/include/asm/mach-sead3/war.h deleted file mode 100644 index d068fc411f478..0000000000000 --- a/arch/mips/include/asm/mach-sead3/war.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2002, 2004, 2007 by Ralf Baechle - */ -#ifndef __ASM_MIPS_MACH_MIPS_WAR_H -#define __ASM_MIPS_MACH_MIPS_WAR_H - -#define R4600_V1_INDEX_ICACHEOP_WAR 0 -#define R4600_V1_HIT_CACHEOP_WAR 0 -#define R4600_V2_HIT_CACHEOP_WAR 0 -#define R5432_CP0_INTERRUPT_WAR 0 -#define BCM1250_M3_WAR 0 -#define SIBYTE_1956_WAR 0 -#define MIPS4K_ICACHE_REFILL_WAR 1 -#define MIPS_CACHE_SYNC_WAR 1 -#define TX49XX_ICACHE_INDEX_INV_WAR 0 -#define ICACHE_REFILLS_WORKAROUND_WAR 1 -#define R10000_LLSC_WAR 0 -#define MIPS34K_MISSED_ITLB_WAR 0 - -#endif /* __ASM_MIPS_MACH_MIPS_WAR_H */ diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile deleted file mode 100644 index 1674b9cf75279..0000000000000 --- a/arch/mips/mti-sead3/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Carsten Langgaard, carstenl@mips.com -# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. -# -# Copyright (C) 2008 Wind River Systems, Inc. -# written by Ralf Baechle -# -# Copyright (C) 2012 MIPS Technoligies, Inc. All rights reserved. -# Steven J. Hill -# -obj-y := sead3-dtshim.o -obj-y += sead3-init.o -obj-y += sead3-int.o -obj-y += sead3-setup.o -obj-y += sead3-time.o diff --git a/arch/mips/mti-sead3/Platform b/arch/mips/mti-sead3/Platform deleted file mode 100644 index 3870924271450..0000000000000 --- a/arch/mips/mti-sead3/Platform +++ /dev/null @@ -1,7 +0,0 @@ -# -# MIPS SEAD-3 board -# -platform-$(CONFIG_MIPS_SEAD3) += mti-sead3/ -cflags-$(CONFIG_MIPS_SEAD3) += -I$(srctree)/arch/mips/include/asm/mach-sead3 -load-$(CONFIG_MIPS_SEAD3) += 0xffffffff80100000 -all-$(CONFIG_MIPS_SEAD3) := $(COMPRESSION_FNAME).srec diff --git a/arch/mips/mti-sead3/sead3-init.c b/arch/mips/mti-sead3/sead3-init.c deleted file mode 100644 index 50f3fcb0fd806..0000000000000 --- a/arch/mips/mti-sead3/sead3-init.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include -#include - -#include -#include -#include -#include -#include - -extern char except_vec_nmi; -extern char except_vec_ejtag_debug; - -static void __init mips_nmi_setup(void) -{ - void *base; - - base = cpu_has_veic ? - (void *)(CAC_BASE + 0xa80) : - (void *)(CAC_BASE + 0x380); -#ifdef CONFIG_CPU_MICROMIPS - /* - * Decrement the exception vector address by one for microMIPS. - */ - memcpy(base, (&except_vec_nmi - 1), 0x80); - - /* - * This is a hack. We do not know if the boot loader was built with - * microMIPS instructions or not. If it was not, the NMI exception - * code at 0x80000a80 will be taken in MIPS32 mode. The hand coded - * assembly below forces us into microMIPS mode if we are a pure - * microMIPS kernel. The assembly instructions are: - * - * 3C1A8000 lui k0,0x8000 - * 375A0381 ori k0,k0,0x381 - * 03400008 jr k0 - * 00000000 nop - * - * The mode switch occurs by jumping to the unaligned exception - * vector address at 0x80000381 which would have been 0x80000380 - * in MIPS32 mode. The jump to the unaligned address transitions - * us into microMIPS mode. - */ - if (!cpu_has_veic) { - void *base2 = (void *)(CAC_BASE + 0xa80); - *((unsigned int *)base2) = 0x3c1a8000; - *((unsigned int *)base2 + 1) = 0x375a0381; - *((unsigned int *)base2 + 2) = 0x03400008; - *((unsigned int *)base2 + 3) = 0x00000000; - flush_icache_range((unsigned long)base2, - (unsigned long)base2 + 0x10); - } -#else - memcpy(base, &except_vec_nmi, 0x80); -#endif - flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); -} - -static void __init mips_ejtag_setup(void) -{ - void *base; - - base = cpu_has_veic ? - (void *)(CAC_BASE + 0xa00) : - (void *)(CAC_BASE + 0x300); -#ifdef CONFIG_CPU_MICROMIPS - /* Deja vu... */ - memcpy(base, (&except_vec_ejtag_debug - 1), 0x80); - if (!cpu_has_veic) { - void *base2 = (void *)(CAC_BASE + 0xa00); - *((unsigned int *)base2) = 0x3c1a8000; - *((unsigned int *)base2 + 1) = 0x375a0301; - *((unsigned int *)base2 + 2) = 0x03400008; - *((unsigned int *)base2 + 3) = 0x00000000; - flush_icache_range((unsigned long)base2, - (unsigned long)base2 + 0x10); - } -#else - memcpy(base, &except_vec_ejtag_debug, 0x80); -#endif - flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); -} - -void __init prom_init(void) -{ - board_nmi_handler_setup = mips_nmi_setup; - board_ejtag_handler_setup = mips_ejtag_setup; - - fw_init_cmdline(); -} - -void __init prom_free_prom_memory(void) -{ -} diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c deleted file mode 100644 index 2e6b73244ecda..0000000000000 --- a/arch/mips/mti-sead3/sead3-int.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include -#include -#include - -#include -#include - -void __init arch_init_irq(void) -{ - irqchip_init(); - - pr_info("GIC: %spresent\n", (gic_present) ? "" : "not "); - pr_info("EIC: %s\n", - (current_cpu_data.options & MIPS_CPU_VEIC) ? "on" : "off"); -} - diff --git a/arch/mips/mti-sead3/sead3-setup.c b/arch/mips/mti-sead3/sead3-setup.c deleted file mode 100644 index c915e54f10ace..0000000000000 --- a/arch/mips/mti-sead3/sead3-setup.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - * Copyright (C) 2013 Imagination Technologies Ltd. - */ -#include -#include -#include - -#include - -#include -#include - -const char *get_system_type(void) -{ - return "MIPS SEAD3"; -} - -void __init *plat_get_fdt(void) -{ - return (void *)__dtb_start; -} - -void __init plat_mem_setup(void) -{ - void *fdt = plat_get_fdt(); - - fdt = sead3_dt_shim(fdt); - __dt_setup_arch(fdt); -} - -void __init device_tree_init(void) -{ - unflatten_and_copy_device_tree(); -} diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c deleted file mode 100644 index 71feb51944783..0000000000000 --- a/arch/mips/mti-sead3/sead3-time.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include -#include - -#include -#include -#include -#include -#include - -static void __iomem *status_reg = (void __iomem *)0xbf000410; - -/* - * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect. - */ -static unsigned int __init estimate_cpu_frequency(void) -{ - unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK); - unsigned int tick = 0; - unsigned int freq; - unsigned int orig; - unsigned long flags; - - local_irq_save(flags); - - orig = readl(status_reg) & 0x2; /* get original sample */ - /* wait for transition */ - while ((readl(status_reg) & 0x2) == orig) - ; - orig = orig ^ 0x2; /* flip the bit */ - - write_c0_count(0); - - /* wait 1 second (the sampling clock transitions every 10ms) */ - while (tick < 100) { - /* wait for transition */ - while ((readl(status_reg) & 0x2) == orig) - ; - orig = orig ^ 0x2; /* flip the bit */ - tick++; - } - - freq = read_c0_count(); - - local_irq_restore(flags); - - mips_hpt_frequency = freq; - - /* Adjust for processor */ - if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && - (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) - freq *= 2; - - freq += 5000; /* rounding */ - freq -= freq%10000; - - return freq ; -} - -int get_c0_perfcount_int(void) -{ - if (gic_present) - return gic_get_c0_perfcount_int(); - if (cp0_perfcount_irq >= 0) - return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; - return -1; -} -EXPORT_SYMBOL_GPL(get_c0_perfcount_int); - -unsigned int get_c0_compare_int(void) -{ - if (gic_present) - return gic_get_c0_compare_int(); - return MIPS_CPU_IRQ_BASE + cp0_compare_irq; -} - -void __init plat_time_init(void) -{ - unsigned int est_freq; - - est_freq = estimate_cpu_frequency(); - - pr_debug("CPU frequency %d.%02d MHz\n", (est_freq / 1000000), - (est_freq % 1000000) * 100 / 1000000); -} -- GitLab From 1e54134ccad00f76ddf00f3e77db3dc8fdefbb47 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Thu, 29 Sep 2016 15:40:54 -0400 Subject: [PATCH 0338/1167] rtl8xxxu: Fix memory leak in handling rxdesc16 packets A device running without RX package aggregation could return more data in the USB packet than the actual network packet. In this case we could would clone the skb but then determine that that there was no packet to handle and exit without freeing the cloned skb first. This has so far only been observed with 8188eu devices, but could affect others. Signed-off-by: Jes Sorensen Cc: stable@vger.kernel.org # 4.8+ Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index b2d7f6e696675..a96ff17759e46 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5197,7 +5197,12 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) pkt_offset = roundup(pkt_len + drvinfo_sz + desc_shift + sizeof(struct rtl8xxxu_rxdesc16), 128); - if (pkt_cnt > 1) + /* + * Only clone the skb if there's enough data at the end to + * at least cover the rx descriptor + */ + if (pkt_cnt > 1 && + urb_len > (pkt_offset + sizeof(struct rtl8xxxu_rxdesc16))) next_skb = skb_clone(skb, GFP_ATOMIC); rx_status = IEEE80211_SKB_RXCB(skb); -- GitLab From 8a55698f2f29d227825173420d7b99b9277ca88c Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Thu, 29 Sep 2016 15:40:55 -0400 Subject: [PATCH 0339/1167] rtl8xxxu: Fix big-endian problem reporting mactime The full RX descriptor is converted so converting tsfl again would return it to it's original endian value. Signed-off-by: Jes Sorensen Cc: stable@vger.kernel.org # 4.8+ Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 4 ++-- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 1016628926d22..08d587a342d32 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -238,7 +238,7 @@ struct rtl8xxxu_rxdesc16 { u32 pattern1match:1; u32 pattern0match:1; #endif - __le32 tsfl; + u32 tsfl; #if 0 u32 bassn:12; u32 bavld:1; @@ -368,7 +368,7 @@ struct rtl8xxxu_rxdesc24 { u32 ldcp:1; u32 splcp:1; #endif - __le32 tsfl; + u32 tsfl; }; struct rtl8xxxu_txdesc32 { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index a96ff17759e46..a5e6ec2152bff 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5220,7 +5220,7 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats, rx_desc->rxmcs); - rx_status->mactime = le32_to_cpu(rx_desc->tsfl); + rx_status->mactime = rx_desc->tsfl; rx_status->flag |= RX_FLAG_MACTIME_START; if (!rx_desc->swdec) @@ -5290,7 +5290,7 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb) rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats, rx_desc->rxmcs); - rx_status->mactime = le32_to_cpu(rx_desc->tsfl); + rx_status->mactime = rx_desc->tsfl; rx_status->flag |= RX_FLAG_MACTIME_START; if (!rx_desc->swdec) -- GitLab From ab05e5ec81c76f3a852919c22984c885edd2414a Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Fri, 30 Sep 2016 19:35:17 -0400 Subject: [PATCH 0340/1167] rtl8xxxu: Fix rtl8723bu driver reload issue The generic disable_rf() function clears bits 22 and 23 in REG_RX_WAIT_CCA, however we did not re-enable them again in rtl8723b_enable_rf() This resolves the problem for me with 8723bu devices not working again after reloading the driver. Signed-off-by: Jes Sorensen Cc: stable@vger.kernel.org # 4.7+ Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index 6c086b5657e94..02b8ddd98a95d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -1498,6 +1498,10 @@ static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv) u32 val32; u8 val8; + val32 = rtl8xxxu_read32(priv, REG_RX_WAIT_CCA); + val32 |= (BIT(22) | BIT(23)); + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, val32); + /* * No indication anywhere as to what 0x0790 does. The 2 antenna * vendor code preserves bits 6-7 here. -- GitLab From 29d5e6fbd65be89dcd32f070fc45ee0e3b2f82b6 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Fri, 30 Sep 2016 19:35:18 -0400 Subject: [PATCH 0341/1167] rtl8xxxu: Fix rtl8192eu driver reload issue The 8192eu suffered from two issues when reloading the driver. The same problems as with the 8723bu where REG_RX_WAIT_CCA bits 22 and 23 didn't get set in rtl8192e_enable_rf(). In addition it also seems prone to issues when setting REG_RF_CTRL to 0 intead of just disabling the RF_ENABLE bit. Similar to what was causing issues with the 8188eu. With this patch I can successfully reload the driver and reassociate to an APi with an 8192eu dongle. Signed-off-by: Jes Sorensen Cc: stable@vger.kernel.org # 4.8+ Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index df54d27e78516..a793fedc36546 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -1461,7 +1461,9 @@ static int rtl8192eu_active_to_emu(struct rtl8xxxu_priv *priv) int count, ret = 0; /* Turn off RF */ - rtl8xxxu_write8(priv, REG_RF_CTRL, 0); + val8 = rtl8xxxu_read8(priv, REG_RF_CTRL); + val8 &= ~RF_ENABLE; + rtl8xxxu_write8(priv, REG_RF_CTRL, val8); /* Switch DPDT_SEL_P output from register 0x65[2] */ val8 = rtl8xxxu_read8(priv, REG_LEDCFG2); @@ -1593,6 +1595,10 @@ static void rtl8192e_enable_rf(struct rtl8xxxu_priv *priv) u32 val32; u8 val8; + val32 = rtl8xxxu_read32(priv, REG_RX_WAIT_CCA); + val32 |= (BIT(22) | BIT(23)); + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, val32); + val8 = rtl8xxxu_read8(priv, REG_GPIO_MUXCFG); val8 |= BIT(5); rtl8xxxu_write8(priv, REG_GPIO_MUXCFG, val8); -- GitLab From 35d04077ad96ed33ceea2501f5a4f1eacda77218 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 7 Oct 2016 10:40:59 -0700 Subject: [PATCH 0342/1167] metag: Only define atomic_dec_if_positive conditionally The definition of atomic_dec_if_positive() assumes that atomic_sub_if_positive() exists, which is only the case if metag specific atomics are used. This results in the following build error when trying to build metag1_defconfig. kernel/ucount.c: In function 'dec_ucount': kernel/ucount.c:211: error: implicit declaration of function 'atomic_sub_if_positive' Moving the definition of atomic_dec_if_positive() into the metag conditional code fixes the problem. Fixes: 6006c0d8ce94 ("metag: Atomics, locks and bitops") Signed-off-by: Guenter Roeck Signed-off-by: James Hogan Cc: # 3.9.x- --- arch/metag/include/asm/atomic.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/metag/include/asm/atomic.h b/arch/metag/include/asm/atomic.h index 470e365f04ea4..8ff0a70865f65 100644 --- a/arch/metag/include/asm/atomic.h +++ b/arch/metag/include/asm/atomic.h @@ -39,11 +39,10 @@ #define atomic_dec(v) atomic_sub(1, (v)) #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) +#define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v) #endif -#define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v) - #include #endif /* __ASM_METAG_ATOMIC_H */ -- GitLab From 62837b3c1a95535d1a287c9c8c6563bbd8d37033 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 5 Oct 2016 22:49:30 -0700 Subject: [PATCH 0343/1167] Input: elantech - add Fujitsu Lifebook E556 to force crc_enabled Another Lifebook machine that needs the same quirk as other similar models to make the driver working. Also let's reorder elantech_dmi_force_crc_enabled list so LIfebook enries are in alphabetical order. Reported-by: William Linna Tested-by: William Linna Reviewed-by: Benjamin Tissoires Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 37b52f150664e..db7d1d666ac10 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1516,6 +1516,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"), }, }, + { + /* Fujitsu LIFEBOOK E544 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"), + }, + }, { /* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */ .matches = { @@ -1524,10 +1531,10 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { }, }, { - /* Fujitsu LIFEBOOK E544 does not work with crc_enabled == 0 */ + /* Fujitsu LIFEBOOK E556 does not work with crc_enabled == 0 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E556"), }, }, { -- GitLab From e687abfe9dc1ea7fc7a51258e3da76d06851b64d Mon Sep 17 00:00:00 2001 From: Sangwon Jee Date: Fri, 7 Oct 2016 16:19:33 -0700 Subject: [PATCH 0344/1167] Input: melfas_mip4 - add devicetree binding documentations Add devicetree binding documentations. Signed-off-by: Sangwon Jee Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/melfas_mip4.txt | 21 +++++++++++++++++++ .../devicetree/bindings/vendor-prefixes.txt | 1 + 2 files changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt b/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt new file mode 100644 index 0000000000000..7b8944c2cb317 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt @@ -0,0 +1,21 @@ +* MELFAS MIP4 Touchscreen + +Required properties: +- compatible: must be "melfas,mip4_ts" +- reg: I2C slave address of the chip (0x48 or 0x34) +- interrupt-parent: interrupt controller to which the chip is connected +- interrupts: interrupt to which the chip is connected + +Optional properties: +- ce-gpios: GPIO connected to the CE (chip enable) pin of the chip + +Example: + i2c@00000000 { + touchscreen: melfas_mip4@48 { + compatible = "melfas,mip4_ts"; + reg = <0x48>; + interrupt-parent = <&gpio>; + interrupts = <0 IRQ_TYPE_EDGE_FALLING>; + ce-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 99029cfed4593..1457fd4d035f4 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -143,6 +143,7 @@ marvell Marvell Technology Group Ltd. maxim Maxim Integrated Products mediatek MediaTek Inc. melexis Melexis N.V. +melfas MELFAS Inc. merrii Merrii Technology Co., Ltd. micrel Micrel Inc. microchip Microchip Technology Inc. -- GitLab From ff43f433e011ba2851383f8ea426266ec8fbc230 Mon Sep 17 00:00:00 2001 From: Sangwon Jee Date: Fri, 7 Oct 2016 16:25:12 -0700 Subject: [PATCH 0345/1167] Input: melfas_mip4 - add maintainer information Add maintainer information. Signed-off-by: Sangwon Jee Signed-off-by: Dmitry Torokhov --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 630151ff1b262..c232980e65958 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7155,6 +7155,13 @@ F: Documentation/scsi/megaraid.txt F: drivers/scsi/megaraid.* F: drivers/scsi/megaraid/ +MELFAS MIP4 TOUCHSCREEN DRIVER +M: Sangwon Jee +W: http://www.melfas.com +S: Supported +F: drivers/input/touchscreen/melfas_mip4.c +F: Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt + MELLANOX ETHERNET DRIVER (mlx4_en) M: Eugenia Emantayev L: netdev@vger.kernel.org -- GitLab From 30982583e4e57c4648fee4a4d6511e23b6e5db2b Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sat, 23 Jul 2016 22:36:41 +1000 Subject: [PATCH 0346/1167] fs/befs/linuxvfs.c: move useless assignment Control is transfered to unacquire_none when sb->s_fs_info is equal to NULL, so the assignment to NULL is useless and it is moved above unacquire_none. Link: http://lkml.kernel.org/r/ed41da113fc693c7daa4e8813ca04cc766ddfc05.1464226521.git.salah.triki@acm.org Signed-off-by: Salah Triki Signed-off-by: Andrew Morton --- fs/befs/linuxvfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 7da05b159ade2..75ec9a74d8ffa 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -870,9 +870,9 @@ befs_fill_super(struct super_block *sb, void *data, int silent) unacquire_priv_sbp: kfree(befs_sb->mount_opts.iocharset); kfree(sb->s_fs_info); + sb->s_fs_info = NULL; unacquire_none: - sb->s_fs_info = NULL; return ret; } -- GitLab From dceee2e230e07d25e50478dde3f0621a1381da53 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sat, 23 Jul 2016 22:36:41 +1000 Subject: [PATCH 0347/1167] fs/befs/linuxvfs.c: check silent flag before logging errors Log errors only when silent flag is not set. Link: http://lkml.kernel.org/r/d400aaf5a7430de79bd956e40ec075fb1cb08474.1464226521.git.salah.triki@acm.org Signed-off-by: Salah Triki Signed-off-by: Andrew Morton --- fs/befs/linuxvfs.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 75ec9a74d8ffa..edee857c2b084 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -772,7 +772,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent) befs_sb = BEFS_SB(sb); if (!parse_options((char *) data, &befs_sb->mount_opts)) { - befs_error(sb, "cannot parse mount options"); + if (!silent) + befs_error(sb, "cannot parse mount options"); goto unacquire_priv_sbp; } @@ -796,7 +797,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent) sb_min_blocksize(sb, 1024); if (!(bh = sb_bread(sb, sb_block))) { - befs_error(sb, "unable to read superblock"); + if (!silent) + befs_error(sb, "unable to read superblock"); goto unacquire_priv_sbp; } @@ -820,9 +822,9 @@ befs_fill_super(struct super_block *sb, void *data, int silent) brelse(bh); if( befs_sb->num_blocks > ~((sector_t)0) ) { - befs_error(sb, "blocks count: %llu " - "is larger than the host can use", - befs_sb->num_blocks); + if (!silent) + befs_error(sb, "blocks count: %llu is larger than the host can use", + befs_sb->num_blocks); goto unacquire_priv_sbp; } @@ -841,7 +843,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent) } sb->s_root = d_make_root(root); if (!sb->s_root) { - befs_error(sb, "get root inode failed"); + if (!silent) + befs_error(sb, "get root inode failed"); goto unacquire_priv_sbp; } -- GitLab From c625426fb61a64427f4e12b83a6710161fd9489b Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sat, 23 Jul 2016 22:36:41 +1000 Subject: [PATCH 0348/1167] fs/befs/linuxvfs.c: remove useless pr_err in befs_fill_super() Remove pr_err since when kzalloc fails there is a generic out of memory and stack dump. Link: http://lkml.kernel.org/r/c5a7f2d42ec0fc8465c118248e88cd221c483391.1464226521.git.salah.triki@acm.org Signed-off-by: Salah Triki Signed-off-by: Andrew Morton --- fs/befs/linuxvfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index edee857c2b084..5b47b0fbffdd5 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -764,11 +764,9 @@ befs_fill_super(struct super_block *sb, void *data, int silent) save_mount_options(sb, data); sb->s_fs_info = kzalloc(sizeof(*befs_sb), GFP_KERNEL); - if (sb->s_fs_info == NULL) { - pr_err("(%s): Unable to allocate memory for private " - "portion of superblock. Bailing.\n", sb->s_id); + if (sb->s_fs_info == NULL) goto unacquire_none; - } + befs_sb = BEFS_SB(sb); if (!parse_options((char *) data, &befs_sb->mount_opts)) { -- GitLab From e808792784e5a4f4532e660697385d3d370f8803 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sat, 23 Jul 2016 22:36:41 +1000 Subject: [PATCH 0349/1167] fs/befs/linuxvfs.c: remove useless befs_error Remove befs_error since when kmalloc fails there is a generic out of memory and stack dump. Link: http://lkml.kernel.org/r/3de4d388d98bbb570462a5eb8e64623e17fb5d74.1464226521.git.salah.triki@acm.org Signed-off-by: Salah Triki Signed-off-by: Andrew Morton --- fs/befs/linuxvfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 5b47b0fbffdd5..04541f37fe833 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -524,7 +524,6 @@ befs_utf2nls(struct super_block *sb, const char *in, *out = result = kmalloc(maxlen, GFP_NOFS); if (!*out) { - befs_error(sb, "%s cannot allocate memory", __func__); *out_len = 0; return -ENOMEM; } @@ -604,7 +603,6 @@ befs_nls2utf(struct super_block *sb, const char *in, *out = result = kmalloc(maxlen, GFP_NOFS); if (!*out) { - befs_error(sb, "%s cannot allocate memory", __func__); *out_len = 0; return -ENOMEM; } -- GitLab From c08f1cb627c43d7b0a1d04a5a0efaf385f0391ad Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sat, 23 Jul 2016 22:36:41 +1000 Subject: [PATCH 0350/1167] fs: befs: remove useless pr_err in befs_init_inodecache() Remove pr_err since kmem_cache_create log error and dump stack. Link: http://lkml.kernel.org/r/e6d03cbc9542495dc6174b59e32fcd41c1393cfc.1464226521.git.salah.triki@acm.org Signed-off-by: Salah Triki --- fs/befs/linuxvfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 04541f37fe833..c734f21fd5812 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -436,10 +436,9 @@ befs_init_inodecache(void) 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD|SLAB_ACCOUNT), init_once); - if (befs_inode_cachep == NULL) { - pr_err("%s: Couldn't initialize inode slabcache\n", __func__); + if (befs_inode_cachep == NULL) return -ENOMEM; - } + return 0; } @@ -524,7 +523,6 @@ befs_utf2nls(struct super_block *sb, const char *in, *out = result = kmalloc(maxlen, GFP_NOFS); if (!*out) { - *out_len = 0; return -ENOMEM; } -- GitLab From 173b066f5826e8eca9b67e8091cab67fcda74f2f Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Sat, 23 Jul 2016 22:36:42 +1000 Subject: [PATCH 0351/1167] befs: check return of sb_min_blocksize Confirm sb_min_blocksize() succeeded before continuing. Link: http://lkml.kernel.org/r/1465700235-22881-1-git-send-email-luisbg@osg.samsung.com Signed-off-by: Luis de Bethencourt Signed-off-by: Andrew Morton --- fs/befs/linuxvfs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index c734f21fd5812..453bb68da219d 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -756,6 +756,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent) long ret = -EINVAL; const unsigned long sb_block = 0; const off_t x86_sb_off = 512; + int blocksize; save_mount_options(sb, data); @@ -788,7 +789,11 @@ befs_fill_super(struct super_block *sb, void *data, int silent) * least 1k to get the second 512 bytes of the volume. * -WD 10-26-01 */ - sb_min_blocksize(sb, 1024); + blocksize = sb_min_blocksize(sb, 1024); + if (!blocksize) { + befs_error(sb, "unable to set blocksize"); + goto unacquire_priv_sbp; + } if (!(bh = sb_bread(sb, sb_block))) { if (!silent) -- GitLab From 10145d6116325266728e423c42d84a89f8f129d2 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Sat, 23 Jul 2016 22:36:42 +1000 Subject: [PATCH 0352/1167] befs: fix function name in documentation Documentation of function befs_load_cb() lists it as load_befs_sb(). Fix the misnomer. Link: http://lkml.kernel.org/r/1465700235-22881-2-git-send-email-luisbg@osg.samsung.com Signed-off-by: Luis de Bethencourt Signed-off-by: Andrew Morton --- fs/befs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/befs/super.c b/fs/befs/super.c index aeafc4d842788..9d1b56cd6f19d 100644 --- a/fs/befs/super.c +++ b/fs/befs/super.c @@ -14,7 +14,7 @@ #include "super.h" /** - * load_befs_sb -- Read from disk and properly byteswap all the fields + * befs_load_sb -- Read from disk and properly byteswap all the fields * of the befs superblock * * -- GitLab From f0f2536fe36671028209e0bd15a2940f2b61cdb5 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Sat, 23 Jul 2016 22:36:42 +1000 Subject: [PATCH 0353/1167] befs: remove unused functions befs_iaddr_is_empty() and befs_brun_size() are unused. Remove them. Link: http://lkml.kernel.org/r/1465700235-22881-3-git-send-email-luisbg@osg.samsung.com Signed-off-by: Luis de Bethencourt Signed-off-by: Andrew Morton --- fs/befs/befs.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/fs/befs/befs.h b/fs/befs/befs.h index e0f59263a96d5..c5c6cd13709ca 100644 --- a/fs/befs/befs.h +++ b/fs/befs/befs.h @@ -140,18 +140,6 @@ befs_iaddrs_per_block(struct super_block *sb) return BEFS_SB(sb)->block_size / sizeof (befs_disk_inode_addr); } -static inline int -befs_iaddr_is_empty(const befs_inode_addr *iaddr) -{ - return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len); -} - -static inline size_t -befs_brun_size(struct super_block *sb, befs_block_run run) -{ - return BEFS_SB(sb)->block_size * run.len; -} - #include "endian.h" #endif /* _LINUX_BEFS_H */ -- GitLab From f7f675406be6eb3736a8690217d7b41d60f6a1aa Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sat, 23 Jul 2016 22:36:42 +1000 Subject: [PATCH 0354/1167] fs: befs: replace befs_bread by sb_bread Since befs_bread merely calls sb_bread, replace it by sb_bread. Link: http://lkml.kernel.org/r/1466800258-4542-1-git-send-email-salah.triki@gmail.com Signed-off-by: Salah Triki Acked-by: Luis de Bethencourt Signed-off-by: Andrew Morton --- fs/befs/datastream.c | 6 +++--- fs/befs/io.c | 24 ------------------------ fs/befs/io.h | 2 -- fs/befs/linuxvfs.c | 2 +- 4 files changed, 4 insertions(+), 30 deletions(-) diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index af1bc19b7c85b..26cc417cbdce6 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -326,7 +326,7 @@ befs_find_brun_indirect(struct super_block *sb, /* Examine blocks of the indirect run one at a time */ for (i = 0; i < indirect.len; i++) { - indirblock = befs_bread(sb, indirblockno + i); + indirblock = sb_bread(sb, indirblockno + i); if (indirblock == NULL) { befs_debug(sb, "---> %s failed to read " "disk block %lu from the indirect brun", @@ -471,7 +471,7 @@ befs_find_brun_dblindirect(struct super_block *sb, } dbl_indir_block = - befs_bread(sb, iaddr2blockno(sb, &data->double_indirect) + + sb_bread(sb, iaddr2blockno(sb, &data->double_indirect) + dbl_which_block); if (dbl_indir_block == NULL) { befs_error(sb, "%s couldn't read the " @@ -499,7 +499,7 @@ befs_find_brun_dblindirect(struct super_block *sb, } indir_block = - befs_bread(sb, iaddr2blockno(sb, &indir_run) + which_block); + sb_bread(sb, iaddr2blockno(sb, &indir_run) + which_block); if (indir_block == NULL) { befs_error(sb, "%s couldn't read the indirect block " "at blockno %lu", __func__, (unsigned long) diff --git a/fs/befs/io.c b/fs/befs/io.c index 523c8af2d770b..4223b779fcc43 100644 --- a/fs/befs/io.c +++ b/fs/befs/io.c @@ -59,27 +59,3 @@ befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr) befs_debug(sb, "<--- %s ERROR", __func__); return NULL; } - -struct buffer_head * -befs_bread(struct super_block *sb, befs_blocknr_t block) -{ - struct buffer_head *bh; - - befs_debug(sb, "---> Enter %s %lu", __func__, (unsigned long)block); - - bh = sb_bread(sb, block); - - if (bh == NULL) { - befs_error(sb, "Failed to read block %lu", - (unsigned long)block); - goto error; - } - - befs_debug(sb, "<--- %s", __func__); - - return bh; - - error: - befs_debug(sb, "<--- %s ERROR", __func__); - return NULL; -} diff --git a/fs/befs/io.h b/fs/befs/io.h index 9b78266b6aa57..78d7bc6e60dee 100644 --- a/fs/befs/io.h +++ b/fs/befs/io.h @@ -5,5 +5,3 @@ struct buffer_head *befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr); -struct buffer_head *befs_bread(struct super_block *sb, befs_blocknr_t block); - diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 453bb68da219d..619b998e9a1eb 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -318,7 +318,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) befs_ino->i_inode_num.allocation_group, befs_ino->i_inode_num.start, befs_ino->i_inode_num.len); - bh = befs_bread(sb, inode->i_ino); + bh = sb_bread(sb, inode->i_ino); if (!bh) { befs_error(sb, "unable to read inode block - " "inode = %lu", inode->i_ino); -- GitLab From a64998504ebd766f07cf77f41334ccd8a60297ae Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 29 Jun 2016 21:27:40 +0100 Subject: [PATCH 0355/1167] fs: befs: check silent flag before logging error Log error only when silent flag is not set. Fixes: dbe6460388bc ("fs/befs/linuxvfs.c: check silent flag before logging errors") Signed-off-by: Luis de Bethencourt Acked-by: Salah Triki --- fs/befs/linuxvfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 619b998e9a1eb..9272f614d985b 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -791,7 +791,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent) */ blocksize = sb_min_blocksize(sb, 1024); if (!blocksize) { - befs_error(sb, "unable to set blocksize"); + if (!silent) + befs_error(sb, "unable to set blocksize"); goto unacquire_priv_sbp; } -- GitLab From 39dcfd3b3448e03a77cd918a918cdea5d84d6076 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 29 Jun 2016 21:27:41 +0100 Subject: [PATCH 0356/1167] fs: befs: remove comment that confuses kernel-doc This comment with a mysterious unfinished line confuses the kernel-doc system since, because it starts with /**, it thinks it is documenting a function. Signed-off-by: Luis de Bethencourt --- fs/befs/linuxvfs.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 9272f614d985b..cf8f9206d4eb0 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -633,10 +633,6 @@ befs_nls2utf(struct super_block *sb, const char *in, return -EILSEQ; } -/** - * Use the - * - */ enum { Opt_uid, Opt_gid, Opt_charset, Opt_debug, Opt_err, }; -- GitLab From f7769f9cf95fa1a63eea81f13126f8fe7f708dc1 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 1 Jul 2016 01:07:30 +0100 Subject: [PATCH 0357/1167] befs: avoid dereferencing dentry twice No need to dereference dentry twice to get the name when we already have it stored in a local variable. Signed-off-by: Luis de Bethencourt --- fs/befs/linuxvfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index cf8f9206d4eb0..62889eb4a97e6 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -179,7 +179,7 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) kfree(utfname); } else { - ret = befs_btree_find(sb, ds, dentry->d_name.name, &offset); + ret = befs_btree_find(sb, ds, name, &offset); } if (ret == BEFS_BT_NOT_FOUND) { -- GitLab From 50858ef96deeeeeb36b2113d49007f41d0410763 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 1 Jul 2016 01:07:31 +0100 Subject: [PATCH 0358/1167] befs: remove constant variable Use macro directly instead of via assigning it to an unchanging variable. Signed-off-by: Luis de Bethencourt Acked-by: Salah Triki --- fs/befs/linuxvfs.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 62889eb4a97e6..516a958ba50e4 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -211,7 +211,6 @@ befs_readdir(struct file *file, struct dir_context *ctx) befs_off_t value; int result; size_t keysize; - unsigned char d_type; char keybuf[BEFS_NAME_LEN + 1]; befs_debug(sb, "---> %s name %pD, inode %ld, ctx->pos %lld", @@ -236,8 +235,6 @@ befs_readdir(struct file *file, struct dir_context *ctx) return 0; } - d_type = DT_UNKNOWN; - /* Convert to NLS */ if (BEFS_SB(sb)->nls) { char *nlsname; @@ -249,14 +246,14 @@ befs_readdir(struct file *file, struct dir_context *ctx) return result; } if (!dir_emit(ctx, nlsname, nlsnamelen, - (ino_t) value, d_type)) { + (ino_t) value, DT_UNKNOWN)) { kfree(nlsname); return 0; } kfree(nlsname); } else { if (!dir_emit(ctx, keybuf, keysize, - (ino_t) value, d_type)) + (ino_t) value, DT_UNKNOWN)) return 0; } ctx->pos++; -- GitLab From 9ae51a32b1a060d2db4340d853d989ae622d273f Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 1 Jul 2016 01:07:32 +0100 Subject: [PATCH 0359/1167] befs: use simpler while loop Replace goto with simpler while loop to make befs_readdir() more readable. Signed-off-by: Luis de Bethencourt --- fs/befs/linuxvfs.c | 74 ++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 516a958ba50e4..e0979a471e846 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -216,48 +216,50 @@ befs_readdir(struct file *file, struct dir_context *ctx) befs_debug(sb, "---> %s name %pD, inode %ld, ctx->pos %lld", __func__, file, inode->i_ino, ctx->pos); -more: - result = befs_btree_read(sb, ds, ctx->pos, BEFS_NAME_LEN + 1, - keybuf, &keysize, &value); - - if (result == BEFS_ERR) { - befs_debug(sb, "<--- %s ERROR", __func__); - befs_error(sb, "IO error reading %pD (inode %lu)", - file, inode->i_ino); - return -EIO; - - } else if (result == BEFS_BT_END) { - befs_debug(sb, "<--- %s END", __func__); - return 0; - - } else if (result == BEFS_BT_EMPTY) { - befs_debug(sb, "<--- %s Empty directory", __func__); - return 0; - } + while (1) { + result = befs_btree_read(sb, ds, ctx->pos, BEFS_NAME_LEN + 1, + keybuf, &keysize, &value); - /* Convert to NLS */ - if (BEFS_SB(sb)->nls) { - char *nlsname; - int nlsnamelen; - result = - befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen); - if (result < 0) { + if (result == BEFS_ERR) { befs_debug(sb, "<--- %s ERROR", __func__); - return result; + befs_error(sb, "IO error reading %pD (inode %lu)", + file, inode->i_ino); + return -EIO; + + } else if (result == BEFS_BT_END) { + befs_debug(sb, "<--- %s END", __func__); + return 0; + + } else if (result == BEFS_BT_EMPTY) { + befs_debug(sb, "<--- %s Empty directory", __func__); + return 0; } - if (!dir_emit(ctx, nlsname, nlsnamelen, - (ino_t) value, DT_UNKNOWN)) { + + /* Convert to NLS */ + if (BEFS_SB(sb)->nls) { + char *nlsname; + int nlsnamelen; + + result = + befs_utf2nls(sb, keybuf, keysize, &nlsname, + &nlsnamelen); + if (result < 0) { + befs_debug(sb, "<--- %s ERROR", __func__); + return result; + } + if (!dir_emit(ctx, nlsname, nlsnamelen, + (ino_t) value, DT_UNKNOWN)) { + kfree(nlsname); + return 0; + } kfree(nlsname); - return 0; + } else { + if (!dir_emit(ctx, keybuf, keysize, + (ino_t) value, DT_UNKNOWN)) + return 0; } - kfree(nlsname); - } else { - if (!dir_emit(ctx, keybuf, keysize, - (ino_t) value, DT_UNKNOWN)) - return 0; + ctx->pos++; } - ctx->pos++; - goto more; } static struct inode * -- GitLab From 4c3897cce0774b6196f59f98a44eed7e011db5aa Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Sun, 3 Jul 2016 16:29:44 +0100 Subject: [PATCH 0360/1167] befs: make consistent use of befs_error() befs_error() is used in potential errors that could happen in befs to provide informational log messages. befs_debug() is silent when CONFIG_BEFS_DEBUG=no, and very verbose when switched on, which is why it is used for general debugging but not for errors. Fix a few cases where the befs debug utility usage isn't following the expected pattern. To make sure we have consistent information in the logs. Signed-off-by: Luis de Bethencourt --- fs/befs/btree.c | 6 ++++-- fs/befs/datastream.c | 5 ++++- fs/befs/linuxvfs.c | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 307645f9e284c..679f69df38174 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -301,7 +301,8 @@ befs_btree_find(struct super_block *sb, const befs_data_stream *ds, kfree(this_node); if (res != BEFS_BT_MATCH) { - befs_debug(sb, "<--- %s Key %s not found", __func__, key); + befs_error(sb, "<--- %s Key %s not found", __func__, key); + befs_debug(sb, "<--- %s ERROR", __func__); *value = 0; return BEFS_BT_NOT_FOUND; } @@ -358,7 +359,8 @@ befs_find_key(struct super_block *sb, struct befs_btree_node *node, eq = befs_compare_strings(thiskey, keylen, findkey, findkey_len); if (eq < 0) { - befs_debug(sb, "<--- %s %s not found", __func__, findkey); + befs_error(sb, "<--- %s %s not found", __func__, findkey); + befs_debug(sb, "<--- %s ERROR", __func__); return BEFS_BT_NOT_FOUND; } diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index 26cc417cbdce6..740fabcd57c0a 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -275,6 +275,8 @@ befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data, } } + befs_error(sb, "%s failed to find file block %lu", __func__, + (unsigned long)blockno); befs_debug(sb, "---> %s ERROR", __func__); return BEFS_ERR; } @@ -328,9 +330,10 @@ befs_find_brun_indirect(struct super_block *sb, for (i = 0; i < indirect.len; i++) { indirblock = sb_bread(sb, indirblockno + i); if (indirblock == NULL) { - befs_debug(sb, "---> %s failed to read " + befs_error(sb, "---> %s failed to read " "disk block %lu from the indirect brun", __func__, (unsigned long)indirblockno + i); + befs_debug(sb, "<--- %s ERROR", __func__); return BEFS_ERR; } diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index e0979a471e846..67669a81cfd19 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -187,7 +187,7 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) return ERR_PTR(-ENOENT); } else if (ret != BEFS_OK || offset == 0) { - befs_warning(sb, "<--- %s Error", __func__); + befs_error(sb, "<--- %s Error", __func__); return ERR_PTR(-ENODATA); } -- GitLab From cfe0cb20e6fa09becc5e6f7597c6e2d1ed9ab7dd Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 12 Jul 2016 00:02:49 +0100 Subject: [PATCH 0361/1167] befs: in memory free_node_ptr and max_size never read The only place the values of free_node_ptr and max_size are read is in befs_dump_index_entry(), which both times it is called, it is passed the on disk superblock. Removing assignment of unused values. Signed-off-by: Luis de Bethencourt --- fs/befs/btree.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 679f69df38174..e8827af43dcd8 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -156,8 +156,6 @@ befs_bt_read_super(struct super_block *sb, const befs_data_stream *ds, sup->max_depth = fs32_to_cpu(sb, od_sup->max_depth); sup->data_type = fs32_to_cpu(sb, od_sup->data_type); sup->root_node_ptr = fs64_to_cpu(sb, od_sup->root_node_ptr); - sup->free_node_ptr = fs64_to_cpu(sb, od_sup->free_node_ptr); - sup->max_size = fs64_to_cpu(sb, od_sup->max_size); brelse(bh); if (sup->magic != BEFS_BTREE_MAGIC) { -- GitLab From 2dfa8a6e56f63d2f6c479e7b65ef087e892280e9 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 12 Jul 2016 00:02:50 +0100 Subject: [PATCH 0362/1167] befs: fix typo in befs_bt_read_node documentation Fixing a grammatical error in the documentation. Signed-off-by: Luis de Bethencourt --- fs/befs/btree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/befs/btree.c b/fs/befs/btree.c index e8827af43dcd8..97f5e242d3ab7 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -181,8 +181,8 @@ befs_bt_read_super(struct super_block *sb, const befs_data_stream *ds, * Calls befs_read_datastream to read in the indicated btree node and * makes sure its header fields are in cpu byteorder, byteswapping if * necessary. - * Note: node->bh must be NULL when this function called first - * time. Don't forget brelse(node->bh) after last call. + * Note: node->bh must be NULL when this function is called the first time. + * Don't forget brelse(node->bh) after last call. * * On success, returns BEFS_OK and *@node contains the btree node that * starts at @node_off, with the node->head fields in cpu byte order. -- GitLab From d84e4a5a09c320e209789d263a26617f6f7324e3 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 27 Jul 2016 04:11:52 +0100 Subject: [PATCH 0363/1167] fs: befs: Remove redundant validation from befs_find_brun_direct The only caller of befs_find_brun_direct is befs_fblock2brun, which already validates that the block is within the range of direct blocks. So remove the duplicate validation. Signed-off-by: Salah Triki Acked-by: Luis de Bethencourt --- fs/befs/datastream.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index 740fabcd57c0a..41ce07766328d 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -249,17 +249,9 @@ befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data, int i; const befs_block_run *array = data->direct; befs_blocknr_t sum; - befs_blocknr_t max_block = - data->max_direct_range >> BEFS_SB(sb)->block_shift; befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno); - if (blockno > max_block) { - befs_error(sb, "%s passed block outside of direct region", - __func__); - return BEFS_ERR; - } - for (i = 0, sum = 0; i < BEFS_NUM_DIRECT_BLOCKS; sum += array[i].len, i++) { if (blockno >= sum && blockno < sum + (array[i].len)) { -- GitLab From 4bb594329a35e90ed7ff38db24f54aef8680f346 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 27 Jul 2016 04:11:53 +0100 Subject: [PATCH 0364/1167] fs: befs: Coding style fix Constant has to be capitalized. Signed-off-by: Salah Triki Acked-by: Luis de Bethencourt --- fs/befs/btree.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 97f5e242d3ab7..85453e50bc6e4 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -85,7 +85,7 @@ struct befs_btree_node { }; /* local constants */ -static const befs_off_t befs_bt_inval = 0xffffffffffffffffULL; +static const befs_off_t BEFS_BT_INVAL = 0xffffffffffffffffULL; /* local functions */ static int befs_btree_seekleaf(struct super_block *sb, const befs_data_stream *ds, @@ -467,7 +467,7 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds, while (key_sum + this_node->head.all_key_count <= key_no) { /* no more nodes to look in: key_no is too large */ - if (this_node->head.right == befs_bt_inval) { + if (this_node->head.right == BEFS_BT_INVAL) { *keysize = 0; *value = 0; befs_debug(sb, @@ -608,7 +608,7 @@ static int befs_leafnode(struct befs_btree_node *node) { /* all interior nodes (and only interior nodes) have an overflow node */ - if (node->head.overflow == befs_bt_inval) + if (node->head.overflow == BEFS_BT_INVAL) return 1; else return 0; -- GitLab From d70ee4f2de3de1f56f7b5d0837ad9d53320cf128 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 27 Jul 2016 04:11:54 +0100 Subject: [PATCH 0365/1167] fs: befs: Remove useless calls to brelse in befs_find_brun_dblindirect The calls to brelse are useless since dbl_indir_block and indir_block are NULL. Signed-off-by: Salah Triki Acked-by: Luis de Bethencourt --- fs/befs/datastream.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index 41ce07766328d..d7c4bb07e1e49 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -474,7 +474,6 @@ befs_find_brun_dblindirect(struct super_block *sb, (unsigned long) iaddr2blockno(sb, &data->double_indirect) + dbl_which_block); - brelse(dbl_indir_block); return BEFS_ERR; } @@ -499,7 +498,6 @@ befs_find_brun_dblindirect(struct super_block *sb, befs_error(sb, "%s couldn't read the indirect block " "at blockno %lu", __func__, (unsigned long) iaddr2blockno(sb, &indir_run) + which_block); - brelse(indir_block); return BEFS_ERR; } -- GitLab From a26bc1adc74063ec116159d45f305d2a1dd4a07b Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 27 Jul 2016 03:35:59 +0100 Subject: [PATCH 0366/1167] fs: befs: Insert NULL inode to dentry As VFS expects, lookup inserts NULL inode to dentry when the named inode does not exist. Signed-off-by: Salah Triki Acked-by: Luis de Bethencourt --- fs/befs/linuxvfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 67669a81cfd19..ebfc9f0b8a2da 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -184,6 +184,7 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) if (ret == BEFS_BT_NOT_FOUND) { befs_debug(sb, "<--- %s %pd not found", __func__, dentry); + d_add(dentry, NULL); return ERR_PTR(-ENOENT); } else if (ret != BEFS_OK || offset == 0) { -- GitLab From 88ff34446b33c15340c45888dbe325e2ef7ba8c8 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sun, 31 Jul 2016 21:34:27 +0100 Subject: [PATCH 0367/1167] fs: befs: remove in vain variable assignment There is no need to set *value, it will be overwritten later. Signed-off-by: Salah Triki Acked-by: Luis de Bethencourt --- fs/befs/btree.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 85453e50bc6e4..d5641852c5ff9 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -347,8 +347,6 @@ befs_find_key(struct super_block *sb, struct befs_btree_node *node, befs_debug(sb, "---> %s %s", __func__, findkey); - *value = 0; - findkey_len = strlen(findkey); /* if node can not contain key, just skeep this node */ -- GitLab From 143d2a615fe39dd972a6446d24b298f7544588e9 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sun, 31 Jul 2016 21:34:28 +0100 Subject: [PATCH 0368/1167] fs: befs: remove useless initialization to zero node_off is unconditionally set to bt_super.root_node_ptr, so no need to init it to zero. Signed-off-by: Salah Triki Acked-by: Luis de Bethencourt --- fs/befs/btree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/befs/btree.c b/fs/befs/btree.c index d5641852c5ff9..3f1a39166d89f 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -420,7 +420,7 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds, { struct befs_btree_node *this_node; befs_btree_super bt_super; - befs_off_t node_off = 0; + befs_off_t node_off; int cur_key; fs64 *valarray; char *keystart; -- GitLab From f30661035b01910c5da248b6e67fb66182e40f6f Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sun, 31 Jul 2016 21:34:29 +0100 Subject: [PATCH 0369/1167] fs: befs: remove unnecessary *befs_sb variable Remove *befs_sb and just call BEFS_SB(sb) directly, since the returned value by this function is only used once. Signed-off-by: Salah Triki Acked-by: Luis de Bethencourt --- fs/befs/datastream.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index d7c4bb07e1e49..6889644e65f8a 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -425,10 +425,9 @@ befs_find_brun_dblindirect(struct super_block *sb, struct buffer_head *indir_block; befs_block_run indir_run; befs_disk_inode_addr *iaddr_array; - struct befs_sb_info *befs_sb = BEFS_SB(sb); befs_blocknr_t indir_start_blk = - data->max_indirect_range >> befs_sb->block_shift; + data->max_indirect_range >> BEFS_SB(sb)->block_shift; off_t dbl_indir_off = blockno - indir_start_blk; -- GitLab From abcf911691ee2a4e3fd8c71adc397f67c56565a2 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sun, 31 Jul 2016 21:34:30 +0100 Subject: [PATCH 0370/1167] fs: befs: remove in vain variable assignment There is no need to init res, since it will be overwitten later by befs_fblock2brun(). Signed-off-by: Salah Triki Acked-by: Luis de Bethencourt --- fs/befs/linuxvfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index ebfc9f0b8a2da..c3909a6a24a35 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -120,7 +120,7 @@ befs_get_block(struct inode *inode, sector_t block, struct super_block *sb = inode->i_sb; befs_data_stream *ds = &BEFS_I(inode)->i_data.ds; befs_block_run run = BAD_IADDR; - int res = 0; + int res; ulong disk_off; befs_debug(sb, "---> befs_get_block() for inode %lu, block %ld", -- GitLab From 33c712b4fcf23fba57cb9a8d947d9ab41e363b08 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sun, 31 Jul 2016 21:34:31 +0100 Subject: [PATCH 0371/1167] fs: befs: remove ret variable ret is initialized to -EIO and is never modified, so remove ret and use -EIO directly. Signed-off-by: Salah Triki Acked-by: Luis de Bethencourt --- fs/befs/linuxvfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index c3909a6a24a35..d307c1e44f499 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -299,7 +299,6 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) struct befs_sb_info *befs_sb = BEFS_SB(sb); struct befs_inode_info *befs_ino; struct inode *inode; - long ret = -EIO; befs_debug(sb, "---> %s inode = %lu", __func__, ino); @@ -421,7 +420,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) unacquire_none: iget_failed(inode); befs_debug(sb, "<--- %s - Bad inode", __func__); - return ERR_PTR(ret); + return ERR_PTR(-EIO); } /* Initialize the inode cache. Called at fs setup. -- GitLab From 672a8515ee7ce3931daba8ed24f43de476d8e29a Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 8 Aug 2016 15:21:20 +0100 Subject: [PATCH 0372/1167] befs: remove unused BEFS_BT_PARMATCH befs_btree_find(), the only caller of befs_find_key(), only cares about if the return from that function is BEFS_BT_MATCH or not. It never uses the partial match given with BEFS_BT_PARMATCH. Make the overflow return clearer by having BEFS_BT_OVERFLOW instead of BEFS_BT_PARMATCH. Signed-off-by: Luis de Bethencourt Signed-off-by: Salah Triki --- fs/befs/befs.h | 2 +- fs/befs/btree.c | 33 +++++++++++++++------------------ 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/fs/befs/befs.h b/fs/befs/befs.h index c5c6cd13709ca..a8ca7fcf07959 100644 --- a/fs/befs/befs.h +++ b/fs/befs/befs.h @@ -79,7 +79,7 @@ enum befs_err { BEFS_BT_END, BEFS_BT_EMPTY, BEFS_BT_MATCH, - BEFS_BT_PARMATCH, + BEFS_BT_OVERFLOW, BEFS_BT_NOT_FOUND }; diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 3f1a39166d89f..5670d845b2ef7 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -281,9 +281,9 @@ befs_btree_find(struct super_block *sb, const befs_data_stream *ds, while (!befs_leafnode(this_node)) { res = befs_find_key(sb, this_node, key, &node_off); - if (res == BEFS_BT_NOT_FOUND) + /* if no key set, try the overflow node */ + if (res == BEFS_BT_OVERFLOW) node_off = this_node->head.overflow; - /* if no match, go to overflow node */ if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) { befs_error(sb, "befs_btree_find() failed to read " "node at %llu", node_off); @@ -291,8 +291,7 @@ befs_btree_find(struct super_block *sb, const befs_data_stream *ds, } } - /* at the correct leaf node now */ - + /* at a leaf node now, check if it is correct */ res = befs_find_key(sb, this_node, key, value); brelse(this_node->bh); @@ -323,16 +322,12 @@ befs_btree_find(struct super_block *sb, const befs_data_stream *ds, * @findkey: Keystring to search for * @value: If key is found, the value stored with the key is put here * - * finds exact match if one exists, and returns BEFS_BT_MATCH - * If no exact match, finds first key in node that is greater - * (alphabetically) than the search key and returns BEFS_BT_PARMATCH - * (for partial match, I guess). Can you think of something better to - * call it? - * - * If no key was a match or greater than the search key, return - * BEFS_BT_NOT_FOUND. + * Finds exact match if one exists, and returns BEFS_BT_MATCH. + * If there is no match and node's value array is too small for key, return + * BEFS_BT_OVERFLOW. + * If no match and node should countain this key, return BEFS_BT_NOT_FOUND. * - * Use binary search instead of a linear. + * Uses binary search instead of a linear. */ static int befs_find_key(struct super_block *sb, struct befs_btree_node *node, @@ -355,9 +350,8 @@ befs_find_key(struct super_block *sb, struct befs_btree_node *node, eq = befs_compare_strings(thiskey, keylen, findkey, findkey_len); if (eq < 0) { - befs_error(sb, "<--- %s %s not found", __func__, findkey); - befs_debug(sb, "<--- %s ERROR", __func__); - return BEFS_BT_NOT_FOUND; + befs_debug(sb, "<--- node can't contain %s", findkey); + return BEFS_BT_OVERFLOW; } valarray = befs_bt_valarray(node); @@ -385,12 +379,15 @@ befs_find_key(struct super_block *sb, struct befs_btree_node *node, else first = mid + 1; } + + /* return an existing value so caller can arrive to a leaf node */ if (eq < 0) *value = fs64_to_cpu(sb, valarray[mid + 1]); else *value = fs64_to_cpu(sb, valarray[mid]); - befs_debug(sb, "<--- %s found %s at %d", __func__, thiskey, mid); - return BEFS_BT_PARMATCH; + befs_error(sb, "<--- %s %s not found", __func__, findkey); + befs_debug(sb, "<--- %s ERROR", __func__); + return BEFS_BT_NOT_FOUND; } /** -- GitLab From bb75e66627b28816f472183d5dce0784d5edb87f Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 8 Aug 2016 15:21:21 +0100 Subject: [PATCH 0373/1167] befs: fix typo in befs_find_key Fixing skeep to skip. Signed-off-by: Luis de Bethencourt Signed-off-by: Salah Triki --- fs/befs/btree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 5670d845b2ef7..0807766d8ba82 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -344,7 +344,7 @@ befs_find_key(struct super_block *sb, struct befs_btree_node *node, findkey_len = strlen(findkey); - /* if node can not contain key, just skeep this node */ + /* if node can not contain key, just skip this node */ last = node->head.all_key_count - 1; thiskey = befs_bt_get_key(sb, node, last, &keylen); -- GitLab From 6ea4558f9b373b588162e5d3523bc65fcf669b06 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Tue, 9 Aug 2016 14:46:04 +0100 Subject: [PATCH 0374/1167] befs: add flags field to validate superblock state For validating superblock state, add flags field to befs_sb_info, read the state from the disk and check if it is equal to BEFS_DIRTY. Signed-off-by: Salah Triki Signed-off-by: Luis de Bethencourt --- fs/befs/befs.h | 3 +++ fs/befs/super.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/befs/befs.h b/fs/befs/befs.h index a8ca7fcf07959..af8ea961e88f7 100644 --- a/fs/befs/befs.h +++ b/fs/befs/befs.h @@ -43,6 +43,9 @@ struct befs_sb_info { u32 ag_shift; u32 num_ags; + /* State of the superblock */ + u32 flags; + /* jornal log entry */ befs_block_run log_blocks; befs_off_t log_start; diff --git a/fs/befs/super.c b/fs/befs/super.c index 9d1b56cd6f19d..dc13df8de3e8b 100644 --- a/fs/befs/super.c +++ b/fs/befs/super.c @@ -45,6 +45,8 @@ befs_load_sb(struct super_block *sb, befs_super_block * disk_sb) befs_sb->ag_shift = fs32_to_cpu(sb, disk_sb->ag_shift); befs_sb->num_ags = fs32_to_cpu(sb, disk_sb->num_ags); + befs_sb->flags = fs32_to_cpu(sb, disk_sb->flags); + befs_sb->log_blocks = fsrun_to_cpu(sb, disk_sb->log_blocks); befs_sb->log_start = fs64_to_cpu(sb, disk_sb->log_start); befs_sb->log_end = fs64_to_cpu(sb, disk_sb->log_end); @@ -101,7 +103,7 @@ befs_check_sb(struct super_block *sb) return BEFS_ERR; } - if (befs_sb->log_start != befs_sb->log_end) { + if (befs_sb->log_start != befs_sb->log_end || befs_sb->flags == BEFS_DIRTY) { befs_error(sb, "Filesystem not clean! There are blocks in the " "journal. You must boot into BeOS and mount this volume " "to make it clean."); -- GitLab From 2ac636b4d04702e26421598949fc30c7a9e38988 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Tue, 9 Aug 2016 14:46:05 +0100 Subject: [PATCH 0375/1167] befs: fix typo in befs_sb_info Fixing jornal to Journal. Signed-off-by: Salah Triki Signed-off-by: Luis de Bethencourt --- fs/befs/befs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/befs/befs.h b/fs/befs/befs.h index af8ea961e88f7..c6bad51d8ec7b 100644 --- a/fs/befs/befs.h +++ b/fs/befs/befs.h @@ -46,7 +46,7 @@ struct befs_sb_info { /* State of the superblock */ u32 flags; - /* jornal log entry */ + /* Journal log entry */ befs_block_run log_blocks; befs_off_t log_start; befs_off_t log_end; -- GitLab From 78f647c27f17b10bd7e1ce5d66a3755b1848efa5 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Thu, 11 Aug 2016 12:04:52 +0100 Subject: [PATCH 0376/1167] befs: remove unnecessary initialization There is no need to init block, since it will be overwitten later by iaddr2blockno(). Signed-off-by: Salah Triki Signed-off-by: Luis de Bethencourt --- fs/befs/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/befs/io.c b/fs/befs/io.c index 4223b779fcc43..b4a558126ee17 100644 --- a/fs/befs/io.c +++ b/fs/befs/io.c @@ -27,7 +27,7 @@ struct buffer_head * befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr) { struct buffer_head *bh; - befs_blocknr_t block = 0; + befs_blocknr_t block; struct befs_sb_info *befs_sb = BEFS_SB(sb); befs_debug(sb, "---> Enter %s " -- GitLab From d1a8c70676c7e2cd4b80f494aed17b5813f2be44 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 9 Aug 2016 22:20:23 +0100 Subject: [PATCH 0377/1167] befs: dump inode_size superblock information befs_dump_super_block() wasn't giving the inode_size information when dumping all elements of the superblock. Add this element to have complete information of the superblock. Signed-off-by: Luis de Bethencourt Signed-off-by: Salah Triki --- fs/befs/debug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/befs/debug.c b/fs/befs/debug.c index 4de7cffcd6622..85c13392e9e89 100644 --- a/fs/befs/debug.c +++ b/fs/befs/debug.c @@ -169,6 +169,7 @@ befs_dump_super_block(const struct super_block *sb, befs_super_block * sup) befs_debug(sb, " num_blocks %llu", fs64_to_cpu(sb, sup->num_blocks)); befs_debug(sb, " used_blocks %llu", fs64_to_cpu(sb, sup->used_blocks)); + befs_debug(sb, " inode_size %u", fs32_to_cpu(sb, sup->inode_size)); befs_debug(sb, " magic2 %08x", fs32_to_cpu(sb, sup->magic2)); befs_debug(sb, " blocks_per_ag %u", -- GitLab From bbe1bd0b6bba138eaf441c6c964bde9866da8808 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 9 Aug 2016 22:23:36 +0100 Subject: [PATCH 0378/1167] befs: add check for ag_shift in superblock ag_shift and blocks_per_ag contain the same information in different ways, same as block_shift and block_size do. It is worth checking this two are consistent, but since blocks_per_ag isn't documented as mandatory to use some implementations of befs don't enforce this, so making it non-fatal if they don't match and just having it as a warning. Signed-off-by: Luis de Bethencourt Signed-off-by: Salah Triki --- fs/befs/super.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/befs/super.c b/fs/befs/super.c index dc13df8de3e8b..c36745d2b45f8 100644 --- a/fs/befs/super.c +++ b/fs/befs/super.c @@ -103,6 +103,13 @@ befs_check_sb(struct super_block *sb) return BEFS_ERR; } + + /* ag_shift also encodes the same information as blocks_per_ag in a + * different way, non-fatal consistency check + */ + if ((1 << befs_sb->ag_shift) != befs_sb->blocks_per_ag) + befs_error(sb, "ag_shift disagrees with blocks_per_ag."); + if (befs_sb->log_start != befs_sb->log_end || befs_sb->flags == BEFS_DIRTY) { befs_error(sb, "Filesystem not clean! There are blocks in the " "journal. You must boot into BeOS and mount this volume " -- GitLab From 11674239f927c900bc50f8f2f5a4ec3e4a3df89b Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 9 Aug 2016 22:24:09 +0100 Subject: [PATCH 0379/1167] befs: fix comment style The description of befs_load_sb was confusing the kernel-doc system since, because it starts with /**, it thinks it will document the function with kernel-doc formatting. Which it isn't. Fix other comment style issues in the file while we are at it. Signed-off-by: Luis de Bethencourt Signed-off-by: Salah Triki --- fs/befs/super.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/fs/befs/super.c b/fs/befs/super.c index c36745d2b45f8..80b93c0a1a7bb 100644 --- a/fs/befs/super.c +++ b/fs/befs/super.c @@ -13,13 +13,9 @@ #include "befs.h" #include "super.h" -/** +/* * befs_load_sb -- Read from disk and properly byteswap all the fields * of the befs superblock - * - * - * - * */ int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb) @@ -93,8 +89,8 @@ befs_check_sb(struct super_block *sb) } /* - * block_shift and block_size encode the same information - * in different ways as a consistency check. + * block_shift and block_size encode the same information + * in different ways as a consistency check. */ if ((1 << befs_sb->block_shift) != befs_sb->block_size) { -- GitLab From 103c0fb3400b3efc74c806db2fd18e9eedc510d5 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 9 Aug 2016 22:51:44 +0100 Subject: [PATCH 0380/1167] befs: fix style issues in super.c Fixing the following checkpatch.pl error: ERROR: "foo * bar" should be "foo *bar" +befs_load_sb(struct super_block *sb, befs_super_block * disk_sb) And the following warnings: WARNING: suspect code indent for conditional statements (8, 12) + if (disk_sb->fs_byte_order == BEFS_BYTEORDER_NATIVE_LE) + befs_sb->byte_order = BEFS_BYTESEX_LE; WARNING: suspect code indent for conditional statements (8, 12) + else if (disk_sb->fs_byte_order == BEFS_BYTEORDER_NATIVE_BE) + befs_sb->byte_order = BEFS_BYTESEX_BE; WARNING: break quoted strings at a space character + befs_error(sb, "blocksize(%u) cannot be larger" + "than system pagesize(%lu)", befs_sb->block_size, WARNING: line over 80 characters + if (befs_sb->log_start != befs_sb->log_end || befs_sb->flags == BEFS_DIRTY) { Signed-off-by: Luis de Bethencourt Signed-off-by: Salah Triki --- fs/befs/super.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/befs/super.c b/fs/befs/super.c index 80b93c0a1a7bb..7c50025c99d8a 100644 --- a/fs/befs/super.c +++ b/fs/befs/super.c @@ -18,15 +18,15 @@ * of the befs superblock */ int -befs_load_sb(struct super_block *sb, befs_super_block * disk_sb) +befs_load_sb(struct super_block *sb, befs_super_block *disk_sb) { struct befs_sb_info *befs_sb = BEFS_SB(sb); /* Check the byte order of the filesystem */ if (disk_sb->fs_byte_order == BEFS_BYTEORDER_NATIVE_LE) - befs_sb->byte_order = BEFS_BYTESEX_LE; + befs_sb->byte_order = BEFS_BYTESEX_LE; else if (disk_sb->fs_byte_order == BEFS_BYTEORDER_NATIVE_BE) - befs_sb->byte_order = BEFS_BYTESEX_BE; + befs_sb->byte_order = BEFS_BYTESEX_BE; befs_sb->magic1 = fs32_to_cpu(sb, disk_sb->magic1); befs_sb->magic2 = fs32_to_cpu(sb, disk_sb->magic2); @@ -82,7 +82,7 @@ befs_check_sb(struct super_block *sb) } if (befs_sb->block_size > PAGE_SIZE) { - befs_error(sb, "blocksize(%u) cannot be larger" + befs_error(sb, "blocksize(%u) cannot be larger " "than system pagesize(%lu)", befs_sb->block_size, PAGE_SIZE); return BEFS_ERR; @@ -106,10 +106,11 @@ befs_check_sb(struct super_block *sb) if ((1 << befs_sb->ag_shift) != befs_sb->blocks_per_ag) befs_error(sb, "ag_shift disagrees with blocks_per_ag."); - if (befs_sb->log_start != befs_sb->log_end || befs_sb->flags == BEFS_DIRTY) { + if (befs_sb->log_start != befs_sb->log_end || + befs_sb->flags == BEFS_DIRTY) { befs_error(sb, "Filesystem not clean! There are blocks in the " - "journal. You must boot into BeOS and mount this volume " - "to make it clean."); + "journal. You must boot into BeOS and mount this " + "volume to make it clean."); return BEFS_ERR; } -- GitLab From 02d91f97fdd62e1d01191e3bb1c42092bd807951 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 11 Aug 2016 22:15:16 +0100 Subject: [PATCH 0381/1167] befs: fix typos in btree.c Fixing typos in kernel-doc function descriptions in fs/befs/btree.c. Signed-off-by: Luis de Bethencourt Signed-off-by: Salah Triki --- fs/befs/btree.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 0807766d8ba82..7e135ea73fddf 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -242,7 +242,7 @@ befs_bt_read_node(struct super_block *sb, const befs_data_stream *ds, * Read the superblock and rootnode of the b+tree. * Drill down through the interior nodes using befs_find_key(). * Once at the correct leaf node, use befs_find_key() again to get the - * actuall value stored with the key. + * actual value stored with the key. */ int befs_btree_find(struct super_block *sb, const befs_data_stream *ds, @@ -400,7 +400,7 @@ befs_find_key(struct super_block *sb, struct befs_btree_node *node, * @keysize: Length of the returned key * @value: Value stored with the returned key * - * Heres how it works: Key_no is the index of the key/value pair to + * Here's how it works: Key_no is the index of the key/value pair to * return in keybuf/value. * Bufsize is the size of keybuf (BEFS_NAME_LEN+1 is a good size). Keysize is * the number of characters in the key (just a convenience). @@ -536,7 +536,6 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds, * @node_off: Pointer to offset of current node within datastream. Modified * by the function. * - * * Helper function for btree traverse. Moves the current position to the * start of the first leaf node. * @@ -710,7 +709,7 @@ befs_bt_get_key(struct super_block *sb, struct befs_btree_node *node, * * Returns 0 if @key1 and @key2 are equal. * Returns >0 if @key1 is greater. - * Returns <0 if @key2 is greater.. + * Returns <0 if @key2 is greater. */ static int befs_compare_strings(const void *key1, int keylen1, -- GitLab From d327e612bd1f854f08bc4c419122a41440455cbe Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Sat, 13 Aug 2016 18:11:19 +0100 Subject: [PATCH 0382/1167] befs: fix typos in datastream.c Signed-off-by: Luis de Bethencourt Signed-off-by: Salah Triki --- fs/befs/datastream.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index 6889644e65f8a..b2eb5b5cdff27 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -37,7 +37,7 @@ static int befs_find_brun_dblindirect(struct super_block *sb, /** * befs_read_datastream - get buffer_head containing data, starting from pos. * @sb: Filesystem superblock - * @ds: datastrem to find data with + * @ds: datastream to find data with * @pos: start of data * @off: offset of data in buffer_head->b_data * @@ -115,7 +115,7 @@ befs_fblock2brun(struct super_block *sb, const befs_data_stream *data, /** * befs_read_lsmylink - read long symlink from datastream. * @sb: Filesystem superblock - * @ds: Datastrem to read from + * @ds: Datastream to read from * @buff: Buffer in which to place long symlink data * @len: Length of the long symlink in bytes * @@ -183,7 +183,7 @@ befs_count_blocks(struct super_block *sb, const befs_data_stream *ds) metablocks += ds->indirect.len; /* - Double indir block, plus all the indirect blocks it mapps + Double indir block, plus all the indirect blocks it maps. In the double-indirect range, all block runs of data are BEFS_DBLINDIR_BRUN_LEN blocks long. Therefore, we know how many data block runs are in the double-indirect region, @@ -397,7 +397,7 @@ befs_find_brun_indirect(struct super_block *sb, though the double-indirect run may be several blocks long, we can calculate which of those blocks will contain the index we are after and only read that one. We then follow it to - the indirect block and perform a similar process to find + the indirect block and perform a similar process to find the actual block run that maps the data block we are interested in. -- GitLab From a20af5f9eaac083e2865e94f37e47af74d70f187 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Sat, 13 Aug 2016 18:11:20 +0100 Subject: [PATCH 0383/1167] befs: improve documentation in datastream.c Convert function descriptions to kernel-doc style. Signed-off-by: Luis de Bethencourt Signed-off-by: Salah Triki --- fs/befs/datastream.c | 193 ++++++++++++++++++++++--------------------- 1 file changed, 98 insertions(+), 95 deletions(-) diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index b2eb5b5cdff27..5ce85cfd8ae16 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -75,7 +75,13 @@ befs_read_datastream(struct super_block *sb, const befs_data_stream *ds, return bh; } -/* +/** + * befs_fblock2brun - give back block run for fblock + * @sb: the superblock + * @data: datastream to read from + * @fblock: the blocknumber with the file position to find + * @run: The found run is passed back through this pointer + * * Takes a file position and gives back a brun who's starting block * is block number fblock of the file. * @@ -212,36 +218,35 @@ befs_count_blocks(struct super_block *sb, const befs_data_stream *ds) return blocks; } -/* - Finds the block run that starts at file block number blockno - in the file represented by the datastream data, if that - blockno is in the direct region of the datastream. - - sb: the superblock - data: the datastream - blockno: the blocknumber to find - run: The found run is passed back through this pointer - - Return value is BEFS_OK if the blockrun is found, BEFS_ERR - otherwise. - - Algorithm: - Linear search. Checks each element of array[] to see if it - contains the blockno-th filesystem block. This is necessary - because the block runs map variable amounts of data. Simply - keeps a count of the number of blocks searched so far (sum), - incrementing this by the length of each block run as we come - across it. Adds sum to *count before returning (this is so - you can search multiple arrays that are logicaly one array, - as in the indirect region code). - - When/if blockno is found, if blockno is inside of a block - run as stored on disk, we offset the start and length members - of the block run, so that blockno is the start and len is - still valid (the run ends in the same place). - - 2001-11-15 Will Dyson -*/ +/** + * befs_find_brun_direct - find a direct block run in the datastream + * @sb: the superblock + * @data: the datastream + * @blockno: the blocknumber to find + * @run: The found run is passed back through this pointer + * + * Finds the block run that starts at file block number blockno + * in the file represented by the datastream data, if that + * blockno is in the direct region of the datastream. + * + * Return value is BEFS_OK if the blockrun is found, BEFS_ERR + * otherwise. + * + * Algorithm: + * Linear search. Checks each element of array[] to see if it + * contains the blockno-th filesystem block. This is necessary + * because the block runs map variable amounts of data. Simply + * keeps a count of the number of blocks searched so far (sum), + * incrementing this by the length of each block run as we come + * across it. Adds sum to *count before returning (this is so + * you can search multiple arrays that are logicaly one array, + * as in the indirect region code). + * + * When/if blockno is found, if blockno is inside of a block + * run as stored on disk, we offset the start and length members + * of the block run, so that blockno is the start and len is + * still valid (the run ends in the same place). + */ static int befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data, befs_blocknr_t blockno, befs_block_run * run) @@ -273,29 +278,28 @@ befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data, return BEFS_ERR; } -/* - Finds the block run that starts at file block number blockno - in the file represented by the datastream data, if that - blockno is in the indirect region of the datastream. - - sb: the superblock - data: the datastream - blockno: the blocknumber to find - run: The found run is passed back through this pointer - - Return value is BEFS_OK if the blockrun is found, BEFS_ERR - otherwise. - - Algorithm: - For each block in the indirect run of the datastream, read - it in and search through it for search_blk. - - XXX: - Really should check to make sure blockno is inside indirect - region. - - 2001-11-15 Will Dyson -*/ +/** + * befs_find_brun_indirect - find a block run in the datastream + * @sb: the superblock + * @data: the datastream + * @blockno: the blocknumber to find + * @run: The found run is passed back through this pointer + * + * Finds the block run that starts at file block number blockno + * in the file represented by the datastream data, if that + * blockno is in the indirect region of the datastream. + * + * Return value is BEFS_OK if the blockrun is found, BEFS_ERR + * otherwise. + * + * Algorithm: + * For each block in the indirect run of the datastream, read + * it in and search through it for search_blk. + * + * XXX: + * Really should check to make sure blockno is inside indirect + * region. + */ static int befs_find_brun_indirect(struct super_block *sb, const befs_data_stream *data, @@ -365,47 +369,46 @@ befs_find_brun_indirect(struct super_block *sb, return BEFS_ERR; } -/* - Finds the block run that starts at file block number blockno - in the file represented by the datastream data, if that - blockno is in the double-indirect region of the datastream. - - sb: the superblock - data: the datastream - blockno: the blocknumber to find - run: The found run is passed back through this pointer - - Return value is BEFS_OK if the blockrun is found, BEFS_ERR - otherwise. - - Algorithm: - The block runs in the double-indirect region are different. - They are always allocated 4 fs blocks at a time, so each - block run maps a constant amount of file data. This means - that we can directly calculate how many block runs into the - double-indirect region we need to go to get to the one that - maps a particular filesystem block. - - We do this in two stages. First we calculate which of the - inode addresses in the double-indirect block will point us - to the indirect block that contains the mapping for the data, - then we calculate which of the inode addresses in that - indirect block maps the data block we are after. - - Oh, and once we've done that, we actually read in the blocks - that contain the inode addresses we calculated above. Even - though the double-indirect run may be several blocks long, - we can calculate which of those blocks will contain the index - we are after and only read that one. We then follow it to - the indirect block and perform a similar process to find - the actual block run that maps the data block we are interested - in. - - Then we offset the run as in befs_find_brun_array() and we are - done. - - 2001-11-15 Will Dyson -*/ +/** + * befs_find_brun_dblindirect - find a block run in the datastream + * @sb: the superblock + * @data: the datastream + * @blockno: the blocknumber to find + * @run: The found run is passed back through this pointer + * + * Finds the block run that starts at file block number blockno + * in the file represented by the datastream data, if that + * blockno is in the double-indirect region of the datastream. + * + * Return value is BEFS_OK if the blockrun is found, BEFS_ERR + * otherwise. + * + * Algorithm: + * The block runs in the double-indirect region are different. + * They are always allocated 4 fs blocks at a time, so each + * block run maps a constant amount of file data. This means + * that we can directly calculate how many block runs into the + * double-indirect region we need to go to get to the one that + * maps a particular filesystem block. + * + * We do this in two stages. First we calculate which of the + * inode addresses in the double-indirect block will point us + * to the indirect block that contains the mapping for the data, + * then we calculate which of the inode addresses in that + * indirect block maps the data block we are after. + * + * Oh, and once we've done that, we actually read in the blocks + * that contain the inode addresses we calculated above. Even + * though the double-indirect run may be several blocks long, + * we can calculate which of those blocks will contain the index + * we are after and only read that one. We then follow it to + * the indirect block and perform a similar process to find + * the actual block run that maps the data block we are interested + * in. + * + * Then we offset the run as in befs_find_brun_array() and we are + * done. + */ static int befs_find_brun_dblindirect(struct super_block *sb, const befs_data_stream *data, -- GitLab From a17e7d2010b44103e3b8e00d0c8c510606457bc6 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Sat, 13 Aug 2016 18:11:21 +0100 Subject: [PATCH 0384/1167] befs: befs: fix style issues in datastream.c Fixing the following checkpatch.pl errors: ERROR: "foo * bar" should be "foo *bar" + befs_blocknr_t blockno, befs_block_run * run); WARNING: Missing a blank line after declarations + struct buffer_head *bh; + befs_debug(sb, "---> %s length: %llu", __func__, len); WARNING: Block comments use * on subsequent lines + /* + Double indir block, plus all the indirect blocks it maps. (and other instances of these) Signed-off-by: Luis de Bethencourt Signed-off-by: Salah Triki --- fs/befs/datastream.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index 5ce85cfd8ae16..b4c7ba013c0d6 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -22,17 +22,17 @@ const befs_inode_addr BAD_IADDR = { 0, 0, 0 }; static int befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data, - befs_blocknr_t blockno, befs_block_run * run); + befs_blocknr_t blockno, befs_block_run *run); static int befs_find_brun_indirect(struct super_block *sb, const befs_data_stream *data, befs_blocknr_t blockno, - befs_block_run * run); + befs_block_run *run); static int befs_find_brun_dblindirect(struct super_block *sb, const befs_data_stream *data, befs_blocknr_t blockno, - befs_block_run * run); + befs_block_run *run); /** * befs_read_datastream - get buffer_head containing data, starting from pos. @@ -46,7 +46,7 @@ static int befs_find_brun_dblindirect(struct super_block *sb, */ struct buffer_head * befs_read_datastream(struct super_block *sb, const befs_data_stream *ds, - befs_off_t pos, uint * off) + befs_off_t pos, uint *off) { struct buffer_head *bh; befs_block_run run; @@ -94,7 +94,7 @@ befs_read_datastream(struct super_block *sb, const befs_data_stream *ds, */ int befs_fblock2brun(struct super_block *sb, const befs_data_stream *data, - befs_blocknr_t fblock, befs_block_run * run) + befs_blocknr_t fblock, befs_block_run *run) { int err; befs_off_t pos = fblock << BEFS_SB(sb)->block_shift; @@ -134,6 +134,7 @@ befs_read_lsymlink(struct super_block *sb, const befs_data_stream *ds, befs_off_t bytes_read = 0; /* bytes readed */ u16 plen; struct buffer_head *bh; + befs_debug(sb, "---> %s length: %llu", __func__, len); while (bytes_read < len) { @@ -189,13 +190,13 @@ befs_count_blocks(struct super_block *sb, const befs_data_stream *ds) metablocks += ds->indirect.len; /* - Double indir block, plus all the indirect blocks it maps. - In the double-indirect range, all block runs of data are - BEFS_DBLINDIR_BRUN_LEN blocks long. Therefore, we know - how many data block runs are in the double-indirect region, - and from that we know how many indirect blocks it takes to - map them. We assume that the indirect blocks are also - BEFS_DBLINDIR_BRUN_LEN blocks long. + * Double indir block, plus all the indirect blocks it maps. + * In the double-indirect range, all block runs of data are + * BEFS_DBLINDIR_BRUN_LEN blocks long. Therefore, we know + * how many data block runs are in the double-indirect region, + * and from that we know how many indirect blocks it takes to + * map them. We assume that the indirect blocks are also + * BEFS_DBLINDIR_BRUN_LEN blocks long. */ if (ds->size > ds->max_indirect_range && ds->max_indirect_range != 0) { uint dbl_bytes; @@ -249,7 +250,7 @@ befs_count_blocks(struct super_block *sb, const befs_data_stream *ds) */ static int befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data, - befs_blocknr_t blockno, befs_block_run * run) + befs_blocknr_t blockno, befs_block_run *run) { int i; const befs_block_run *array = data->direct; @@ -261,6 +262,7 @@ befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data, sum += array[i].len, i++) { if (blockno >= sum && blockno < sum + (array[i].len)) { int offset = blockno - sum; + run->allocation_group = array[i].allocation_group; run->start = array[i].start + offset; run->len = array[i].len - offset; @@ -304,7 +306,7 @@ static int befs_find_brun_indirect(struct super_block *sb, const befs_data_stream *data, befs_blocknr_t blockno, - befs_block_run * run) + befs_block_run *run) { int i, j; befs_blocknr_t sum = 0; @@ -413,7 +415,7 @@ static int befs_find_brun_dblindirect(struct super_block *sb, const befs_data_stream *data, befs_blocknr_t blockno, - befs_block_run * run) + befs_block_run *run) { int dblindir_indx; int indir_indx; -- GitLab From 2967999fbceffa8520987ab9b3b00a55d6997dba Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 5 Oct 2016 17:46:50 +0300 Subject: [PATCH 0385/1167] iio: adc: ti-adc081c: Select IIO_TRIGGERED_BUFFER to prevent build errors Commit 08e05d1fce5c ("ti-adc081c: Initial triggered buffer support") added triggered buffer support but that also requires CONFIG_IIO_TRIGGERED_BUFFER, otherwise we get errors from linker such as: drivers/built-in.o: In function `adc081c_remove': drivers/iio/adc/ti-adc081c.c:225: undefined reference to `iio_triggered_buffer_cleanup' Fix these by explicitly selecting both CONFIG_IIO_TRIGGERED_BUFFER and CONFIG_IIO_BUFFER in Kconfig for the driver. Signed-off-by: Mika Westerberg Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7edcf32386206..99c051490effa 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -437,6 +437,8 @@ config STX104 config TI_ADC081C tristate "Texas Instruments ADC081C/ADC101C/ADC121C family" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help If you say yes here you get support for Texas Instruments ADC081C, ADC101C and ADC121C ADC chips. -- GitLab From 6449e31ddebdce68508cfaf0915d31aad3835f4f Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sun, 25 Sep 2016 00:19:05 +0300 Subject: [PATCH 0386/1167] firewire: nosy: do not ignore errors in ioremap_nocache() There is no check if ioremap_nocache() returns a valid pointer. Potentially it can lead to null pointer dereference. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Stefan Richter (renamed goto labels) --- drivers/firewire/nosy.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c index 631c977b0da5f..180f0a96528ce 100644 --- a/drivers/firewire/nosy.c +++ b/drivers/firewire/nosy.c @@ -566,6 +566,11 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused) lynx->registers = ioremap_nocache(pci_resource_start(dev, 0), PCILYNX_MAX_REGISTER); + if (lynx->registers == NULL) { + dev_err(&dev->dev, "Failed to map registers\n"); + ret = -ENOMEM; + goto fail_deallocate_lynx; + } lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device, sizeof(struct pcl), &lynx->rcv_start_pcl_bus); @@ -578,7 +583,7 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused) lynx->rcv_buffer == NULL) { dev_err(&dev->dev, "Failed to allocate receive buffer\n"); ret = -ENOMEM; - goto fail_deallocate; + goto fail_deallocate_buffers; } lynx->rcv_start_pcl->next = cpu_to_le32(lynx->rcv_pcl_bus); lynx->rcv_pcl->next = cpu_to_le32(PCL_NEXT_INVALID); @@ -641,7 +646,7 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused) dev_err(&dev->dev, "Failed to allocate shared interrupt %d\n", dev->irq); ret = -EIO; - goto fail_deallocate; + goto fail_deallocate_buffers; } lynx->misc.parent = &dev->dev; @@ -668,7 +673,7 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused) reg_write(lynx, PCI_INT_ENABLE, 0); free_irq(lynx->pci_device->irq, lynx); -fail_deallocate: +fail_deallocate_buffers: if (lynx->rcv_start_pcl) pci_free_consistent(lynx->pci_device, sizeof(struct pcl), lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); @@ -679,6 +684,8 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused) pci_free_consistent(lynx->pci_device, PAGE_SIZE, lynx->rcv_buffer, lynx->rcv_buffer_bus); iounmap(lynx->registers); + +fail_deallocate_lynx: kfree(lynx); fail_disable: -- GitLab From f9f4872df6e1801572949f8a370c886122d4b6da Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Sat, 8 Oct 2016 12:42:38 -0700 Subject: [PATCH 0387/1167] cpufreq: intel_pstate: Fix unsafe HWP MSR access This is a requirement that MSR MSR_PM_ENABLE must be set to 0x01 before reading MSR_HWP_CAPABILITIES on a given CPU. If cpufreq init() is scheduled on a CPU which is not same as policy->cpu or migrates to a different CPU before calling msr read for MSR_HWP_CAPABILITIES, it is possible that MSR_PM_ENABLE was not to set to 0x01 on that CPU. This will cause GP fault. So like other places in this path rdmsrl_on_cpu should be used instead of rdmsrl. Moreover the scope of MSR_HWP_CAPABILITIES is on per thread basis, so it should be read from the same CPU, for which MSR MSR_HWP_REQUEST is getting set. dmesg dump or warning: [ 22.014488] WARNING: CPU: 139 PID: 1 at arch/x86/mm/extable.c:50 ex_handler_rdmsr_unsafe+0x68/0x70 [ 22.014492] unchecked MSR access error: RDMSR from 0x771 [ 22.014493] Modules linked in: [ 22.014507] CPU: 139 PID: 1 Comm: swapper/0 Not tainted 4.7.5+ #1 ... ... [ 22.014516] Call Trace: [ 22.014542] [] dump_stack+0x63/0x82 [ 22.014558] [] __warn+0xcb/0xf0 [ 22.014561] [] warn_slowpath_fmt+0x4f/0x60 [ 22.014563] [] ex_handler_rdmsr_unsafe+0x68/0x70 [ 22.014564] [] fixup_exception+0x39/0x50 [ 22.014604] [] do_general_protection+0x80/0x150 [ 22.014610] [] general_protection+0x28/0x30 [ 22.014635] [] ? get_target_pstate_use_performance+0xb0/0xb0 [ 22.014642] [] ? native_read_msr+0x7/0x40 [ 22.014657] [] intel_pstate_hwp_set+0x23/0x130 [ 22.014660] [] intel_pstate_set_policy+0x1b6/0x340 [ 22.014662] [] cpufreq_set_policy+0xeb/0x2c0 [ 22.014664] [] cpufreq_init_policy+0x79/0xe0 [ 22.014666] [] ? cpufreq_update_policy+0x120/0x120 [ 22.014669] [] cpufreq_online+0x406/0x820 [ 22.014671] [] cpufreq_add_dev+0x5f/0x90 [ 22.014717] [] subsys_interface_register+0xb8/0x100 [ 22.014719] [] cpufreq_register_driver+0x14c/0x210 [ 22.014749] [] intel_pstate_init+0x39d/0x4d5 [ 22.014751] [] ? cpufreq_gov_dbs_init+0x12/0x12 Cc: 4.3+ # 4.3+ Signed-off-by: Srinivas Pandruvada Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 806f2039571e5..bc976a3db2530 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -562,12 +562,12 @@ static void intel_pstate_hwp_set(const struct cpumask *cpumask) int min, hw_min, max, hw_max, cpu, range, adj_range; u64 value, cap; - rdmsrl(MSR_HWP_CAPABILITIES, cap); - hw_min = HWP_LOWEST_PERF(cap); - hw_max = HWP_HIGHEST_PERF(cap); - range = hw_max - hw_min; - for_each_cpu(cpu, cpumask) { + rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap); + hw_min = HWP_LOWEST_PERF(cap); + hw_max = HWP_HIGHEST_PERF(cap); + range = hw_max - hw_min; + rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value); adj_range = limits->min_perf_pct * range / 100; min = hw_min + adj_range; -- GitLab From f00593a4bdd22e0885db89df8ee8afcc6867994f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 Sep 2016 03:13:34 +0200 Subject: [PATCH 0388/1167] cpufreq: intel_pstate: Clarify comment in get_target_pstate_use_performance() Make the comment explaining the meaning of the perf_scaled variable in get_target_pstate_use_performance() more straightforward. Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index bc976a3db2530..1c7b91c5805bd 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1251,10 +1251,11 @@ static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu) u64 duration_ns; /* - * perf_scaled is the average performance during the last sampling - * period scaled by the ratio of the maximum P-state to the P-state - * requested last time (in percent). That measures the system's - * response to the previous P-state selection. + * perf_scaled is the ratio of the average P-state during the last + * sampling period to the P-state requested last time (in percent). + * + * That measures the system's response to the previous P-state + * selection. */ max_pstate = cpu->pstate.max_pstate_physical; current_pstate = cpu->pstate.current_pstate; -- GitLab From 84baf1725dc532d9746df2d216c1921154767109 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 4 Oct 2016 13:51:40 -0700 Subject: [PATCH 0389/1167] ACPI / fan: Fix error reading cur_state On some platforms with ACPI4 variable speed fan, reading cur_state from cooling device returns "invalid value" error. This confuses user space applications. This issue occurs as the current driver doesn't take account of "FineGrainControl" from _FIF(Fan Information). When the "FineGrainControl" is set, _FSL(FSL Set Level) takes argument as a percent, which doesn't have to match from any control value from _FPS(Fan Performance States). It is also possible that the Fan is not actually running at the requested speed returning a lower speed. On some platforms the BIOS is setting fan speed to a level during boot, which will not have an exact match to _FPS control values. The current implementation will treat this level as invalid value. The simple change is to atleast return state corresponding to a maximum control value in the _FPS compared to the current level. Signed-off-by: Srinivas Pandruvada Signed-off-by: Rafael J. Wysocki --- drivers/acpi/fan.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 384cfc3083e1d..6cf4988206f24 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -129,8 +129,18 @@ static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state) control = obj->package.elements[1].integer.value; for (i = 0; i < fan->fps_count; i++) { - if (control == fan->fps[i].control) + /* + * When Fine Grain Control is set, return the state + * corresponding to maximum fan->fps[i].control + * value compared to the current speed. Here the + * fan->fps[] is sorted array with increasing speed. + */ + if (fan->fif.fine_grain_ctrl && control < fan->fps[i].control) { + i = (i > 0) ? i - 1 : 0; break; + } else if (control == fan->fps[i].control) { + break; + } } if (i == fan->fps_count) { dev_dbg(&device->dev, "Invalid control value returned\n"); -- GitLab From eab05ec38073f72389386f4a77fb58c06e246a4c Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 5 Oct 2016 10:33:16 -0700 Subject: [PATCH 0390/1167] ACPI / EC: Fix unused function warning when CONFIG_PM_SLEEP=n Signed-off-by: Eric Biggers Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 6805310621607..48e19d0131709 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -526,6 +526,7 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) acpi_ec_clear(ec); } +#ifdef CONFIG_PM_SLEEP static bool acpi_ec_query_flushed(struct acpi_ec *ec) { bool flushed; @@ -557,6 +558,7 @@ static void acpi_ec_disable_event(struct acpi_ec *ec) spin_unlock_irqrestore(&ec->lock, flags); __acpi_ec_flush_event(ec); } +#endif /* CONFIG_PM_SLEEP */ static bool acpi_ec_guard_event(struct acpi_ec *ec) { -- GitLab From 3d1355b3cfad53feba76a73b052c757a7de7f4de Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 3 Oct 2016 21:21:42 +0200 Subject: [PATCH 0391/1167] HID: hid-led: fix issue with transfer buffer not being dma capable The hid-led driver works fine under 4.8.0, however with the next kernel from today I get this: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 2578 at drivers/usb/core/hcd.c:1584 usb_hcd_map_urb_for_dma+0x373/0x550 [usbcore] transfer buffer not dma capable Modules linked in: hid_led(+) usbhid vfat fat ir_sony_decoder iwlmvm led_class mac80211 snd_hda_codec_realtek snd_hda_codec_generic x86_pkg_temp_thermal iwlwifi crc32c_intel snd_hda_codec_hdmi i2c_i801 i2c_smbus snd_hda_intel cfg80211 snd_hda_codec snd_hda_core snd_pcm r8169 snd_timer mei_me mii snd mei ir_lirc_codec lirc_dev nuvoton_cir rc_core btusb btintel bluetooth rfkill usb_storage efivarfs ipv6 ehci_pci ehci_hcd xhci_pci xhci_hcd usbcore usb_common ext4 jbd2 mbcache ahci libahci libata CPU: 0 PID: 2578 Comm: systemd-udevd Not tainted 4.8.0-rc8-next-20161003 #1 Hardware name: ZOTAC ZBOX-CI321NANO/ZBOX-CI321NANO, BIOS B246P105 06/01/2015 ffffc90003dbb7e0 ffffffff81280425 ffffc90003dbb830 0000000000000000 ffffc90003dbb820 ffffffff8105b086 0000063003dbb800 ffff88006f374480 0000000000000000 0000000000000000 0000000000000001 ffff880079544000 Call Trace: [] dump_stack+0x68/0x93 [] __warn+0xc6/0xe0 [] warn_slowpath_fmt+0x4a/0x50 [] usb_hcd_map_urb_for_dma+0x373/0x550 [usbcore] [] usb_hcd_submit_urb+0x316/0x9c0 [usbcore] [] ? rcu_read_lock_sched_held+0x40/0x80 [] ? module_assert_mutex_or_preempt+0x13/0x50 [] ? __module_address+0x27/0xf0 [] usb_submit_urb+0x2c4/0x520 [usbcore] [] usb_start_wait_urb+0x5a/0xe0 [usbcore] [] usb_control_msg+0xbc/0xf0 [usbcore] [] ? __module_address+0x27/0xf0 [] usbhid_raw_request+0xa4/0x180 [usbhid] [] hidled_recv+0x71/0xe0 [hid_led] [] thingm_init+0x2d/0x50 [hid_led] [] hidled_probe+0xcb/0x24a [hid_led] [] hid_device_probe+0xd2/0x150 [] driver_probe_device+0x1fd/0x2c0 [] __driver_attach+0x9a/0xa0 [] ? driver_probe_device+0x2c0/0x2c0 [] bus_for_each_dev+0x5d/0x90 [] driver_attach+0x19/0x20 [] bus_add_driver+0x11f/0x220 [] ? 0xffffffffa07ac000 [] driver_register+0x5b/0xd0 [] ? 0xffffffffa07ac000 [] __hid_register_driver+0x61/0xa0 [] hidled_driver_init+0x1e/0x20 [hid_led] [] do_one_initcall+0x38/0x150 [] ? rcu_read_lock_sched_held+0x40/0x80 [] ? kmem_cache_alloc_trace+0x1d0/0x230 [] do_init_module+0x5a/0x1cb [] load_module+0x1e42/0x2530 [] ? __symbol_put+0x50/0x50 [] ? show_coresize+0x30/0x30 [] ? kernel_read_file+0x100/0x190 [] ? kernel_read_file_from_fd+0x44/0x70 [] SYSC_finit_module+0xba/0xc0 [] SyS_finit_module+0x9/0x10 [] entry_SYSCALL_64_fastpath+0x18/0xad ---[ end trace c9e6ea27003ecf9e ]--- Fix this by using a kmalloc'ed buffer when calling hid_hw_raw_request. Signed-off-by: Heiner Kallweit Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-led.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-led.c b/drivers/hid/hid-led.c index d8d55f37b4f56..d3e1ab162f7c6 100644 --- a/drivers/hid/hid-led.c +++ b/drivers/hid/hid-led.c @@ -100,6 +100,7 @@ struct hidled_device { const struct hidled_config *config; struct hid_device *hdev; struct hidled_rgb *rgb; + u8 *buf; struct mutex lock; }; @@ -118,13 +119,19 @@ static int hidled_send(struct hidled_device *ldev, __u8 *buf) mutex_lock(&ldev->lock); + /* + * buffer provided to hid_hw_raw_request must not be on the stack + * and must not be part of a data structure + */ + memcpy(ldev->buf, buf, ldev->config->report_size); + if (ldev->config->report_type == RAW_REQUEST) - ret = hid_hw_raw_request(ldev->hdev, buf[0], buf, + ret = hid_hw_raw_request(ldev->hdev, buf[0], ldev->buf, ldev->config->report_size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); else if (ldev->config->report_type == OUTPUT_REPORT) - ret = hid_hw_output_report(ldev->hdev, buf, + ret = hid_hw_output_report(ldev->hdev, ldev->buf, ldev->config->report_size); else ret = -EINVAL; @@ -147,17 +154,21 @@ static int hidled_recv(struct hidled_device *ldev, __u8 *buf) mutex_lock(&ldev->lock); - ret = hid_hw_raw_request(ldev->hdev, buf[0], buf, + memcpy(ldev->buf, buf, ldev->config->report_size); + + ret = hid_hw_raw_request(ldev->hdev, buf[0], ldev->buf, ldev->config->report_size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); if (ret < 0) goto err; - ret = hid_hw_raw_request(ldev->hdev, buf[0], buf, + ret = hid_hw_raw_request(ldev->hdev, buf[0], ldev->buf, ldev->config->report_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + + memcpy(buf, ldev->buf, ldev->config->report_size); err: mutex_unlock(&ldev->lock); @@ -447,6 +458,10 @@ static int hidled_probe(struct hid_device *hdev, const struct hid_device_id *id) if (!ldev) return -ENOMEM; + ldev->buf = devm_kmalloc(&hdev->dev, MAX_REPORT_SIZE, GFP_KERNEL); + if (!ldev->buf) + return -ENOMEM; + ret = hid_parse(hdev); if (ret) return ret; -- GitLab From e15944099870f374ca7efc62f98cf23ba272ef43 Mon Sep 17 00:00:00 2001 From: Ioan-Adrian Ratiu Date: Tue, 27 Sep 2016 21:41:38 +0300 Subject: [PATCH 0392/1167] HID: hid-dr: add input mapping for axis selection Commit 79346d620e9d ("HID: input: force generic axis to be mapped to their user space axis") made mapping generic axes to their userspace equivalents mandatory and some lower end gamepads which were depending on the previous behaviour suffered severe regressions because they were reusing axes and expecting hid-input to multiplex their map to the respective userspace axis by always searching for and using the next available axis. One solution is to add a hid quirk for this type of "previous" behaviour in hid-input to bypass the new axes policy in favour of the old one, but since only one hardware vendor seems to be affected negatively we're better off making and exception and mapping in the driver for now; if more vendors or drivers turn out to experience the problem we should reconsider the quirk solution. Signed-off-by: Ioan-Adrian Ratiu Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-dr.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c index 8fd4bf77f2649..0ed843939b2c5 100644 --- a/drivers/hid/hid-dr.c +++ b/drivers/hid/hid-dr.c @@ -306,6 +306,30 @@ static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc, return rdesc; } +#define map_abs(c) hid_map_usage(hi, usage, bit, max, EV_ABS, (c)) +#define map_rel(c) hid_map_usage(hi, usage, bit, max, EV_REL, (c)) + +static int dr_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + switch (usage->hid) { + /* + * revert to the old hid-input behavior where axes + * can be randomly assigned when hid->usage is reused. + */ + case HID_GD_X: case HID_GD_Y: case HID_GD_Z: + case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: + if (field->flags & HID_MAIN_ITEM_RELATIVE) + map_rel(usage->hid & 0xf); + else + map_abs(usage->hid & 0xf); + return 1; + } + + return 0; +} + static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; @@ -352,6 +376,7 @@ static struct hid_driver dr_driver = { .id_table = dr_devices, .report_fixup = dr_report_fixup, .probe = dr_probe, + .input_mapping = dr_input_mapping, }; module_hid_driver(dr_driver); -- GitLab From 1bcaa05ebee115213e34f1806cc6a4f7a6175a88 Mon Sep 17 00:00:00 2001 From: Ioan-Adrian Ratiu Date: Tue, 27 Sep 2016 21:41:37 +0300 Subject: [PATCH 0393/1167] Revert "HID: dragonrise: fix HID Descriptor for 0x0006 PID" This reverts commit 18339f59c3a6 ("HID: dragonrise: fix HID...") because it breaks certain dragonrise 0079:0006 gamepads. While it may fix a breakage caused by commit 79346d620e9d ("HID: input: force generic axis to be mapped to their user space axis"), it is probable that the manufacturer released different hardware with the same PID so this fix works for only a subset and breaks the other gamepads sharing the PID. What is needed is another more generic solution which fixes 79346d620e9d ("HID: input: force generic axis ...") breakage for this controller: we need to add an exception for this driver to make it keep the old behaviour previous to the initial breakage (this is done in patch 2 of this series). Signed-off-by: Ioan-Adrian Ratiu Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-dr.c | 58 -------------------------------------------- 1 file changed, 58 deletions(-) diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c index 0ed843939b2c5..818ea7d935333 100644 --- a/drivers/hid/hid-dr.c +++ b/drivers/hid/hid-dr.c @@ -234,58 +234,6 @@ static __u8 pid0011_rdesc_fixed[] = { 0xC0 /* End Collection */ }; -static __u8 pid0006_rdesc_fixed[] = { - 0x05, 0x01, /* Usage Page (Generic Desktop) */ - 0x09, 0x04, /* Usage (Joystick) */ - 0xA1, 0x01, /* Collection (Application) */ - 0xA1, 0x02, /* Collection (Logical) */ - 0x75, 0x08, /* Report Size (8) */ - 0x95, 0x05, /* Report Count (5) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ - 0x35, 0x00, /* Physical Minimum (0) */ - 0x46, 0xFF, 0x00, /* Physical Maximum (255) */ - 0x09, 0x30, /* Usage (X) */ - 0x09, 0x33, /* Usage (Ry) */ - 0x09, 0x32, /* Usage (Z) */ - 0x09, 0x31, /* Usage (Y) */ - 0x09, 0x34, /* Usage (Ry) */ - 0x81, 0x02, /* Input (Variable) */ - 0x75, 0x04, /* Report Size (4) */ - 0x95, 0x01, /* Report Count (1) */ - 0x25, 0x07, /* Logical Maximum (7) */ - 0x46, 0x3B, 0x01, /* Physical Maximum (315) */ - 0x65, 0x14, /* Unit (Centimeter) */ - 0x09, 0x39, /* Usage (Hat switch) */ - 0x81, 0x42, /* Input (Variable) */ - 0x65, 0x00, /* Unit (None) */ - 0x75, 0x01, /* Report Size (1) */ - 0x95, 0x0C, /* Report Count (12) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x45, 0x01, /* Physical Maximum (1) */ - 0x05, 0x09, /* Usage Page (Button) */ - 0x19, 0x01, /* Usage Minimum (0x01) */ - 0x29, 0x0C, /* Usage Maximum (0x0C) */ - 0x81, 0x02, /* Input (Variable) */ - 0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined) */ - 0x75, 0x01, /* Report Size (1) */ - 0x95, 0x08, /* Report Count (8) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x45, 0x01, /* Physical Maximum (1) */ - 0x09, 0x01, /* Usage (0x01) */ - 0x81, 0x02, /* Input (Variable) */ - 0xC0, /* End Collection */ - 0xA1, 0x02, /* Collection (Logical) */ - 0x75, 0x08, /* Report Size (8) */ - 0x95, 0x07, /* Report Count (7) */ - 0x46, 0xFF, 0x00, /* Physical Maximum (255) */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ - 0x09, 0x02, /* Usage (0x02) */ - 0x91, 0x02, /* Output (Variable) */ - 0xC0, /* End Collection */ - 0xC0 /* End Collection */ -}; - static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { @@ -296,12 +244,6 @@ static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc, *rsize = sizeof(pid0011_rdesc_fixed); } break; - case 0x0006: - if (*rsize == sizeof(pid0006_rdesc_fixed)) { - rdesc = pid0006_rdesc_fixed; - *rsize = sizeof(pid0006_rdesc_fixed); - } - break; } return rdesc; } -- GitLab From 4973ca9a01e2354b159acedec1b9b8eb8de02ab7 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 9 Oct 2016 14:21:50 +0200 Subject: [PATCH 0394/1167] HID: add quirk for Akai MIDImix. The Akai MIDImix (09e8:0031) is a MIDI fader controller that speaks regular MIDI and works well with Linux. However, initialization gets delayed due to reports timeout: [3643645.631124] hid-generic 0003:09E8:0031.0020: timeout initializing reports [3643645.632416] hid-generic 0003:09E8:0031.0020: hiddev0: USB HID v1.11 Device [AKAI MIDI Mix] on usb-0000:00:14.0-2/input0 Adding "usbhid.quirks=0x09e8:0x0031:0x20000000" on the kernel command line makes the issues go away. Signed-off-by: Steinar H. Gunderson Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index cd59c79eebdd2..6cfb5cacc2533 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -64,6 +64,9 @@ #define USB_VENDOR_ID_AKAI 0x2011 #define USB_DEVICE_ID_AKAI_MPKMINI2 0x0715 +#define USB_VENDOR_ID_AKAI_09E8 0x09E8 +#define USB_DEVICE_ID_AKAI_09E8_MIDIMIX 0x0031 + #define USB_VENDOR_ID_ALCOR 0x058f #define USB_DEVICE_ID_ALCOR_USBRS232 0x9720 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 0a0eca5da47d0..354d49ea36dd9 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -56,6 +56,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, -- GitLab From b907900ec4065e1d9b65fafa05fd6601b6a2ffc7 Mon Sep 17 00:00:00 2001 From: Andrej Krutak Date: Wed, 5 Oct 2016 17:46:09 +0200 Subject: [PATCH 0395/1167] ALSA: line6: Fix POD X3 Live audio input The commit c039aaa77a7d1d9375665a8b59ec16dc7d23e259 was incomplete, missing part of the setup for Live. This makes also audio input work, in addition to audio output. Fixes: c039aaa77a7d1d9375665a8b59ec16dc7d23e259 Reported-by: Eddi De Pieri Signed-off-by: Andrej Krutak Signed-off-by: Takashi Iwai --- sound/usb/line6/podhd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 9352a44ae6e4a..49cd4a65e390c 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -317,7 +317,8 @@ static int podhd_init(struct usb_line6 *line6, if (pod->line6.properties->capabilities & LINE6_CAP_PCM) { /* initialize PCM subsystem: */ err = line6_init_pcm(line6, - (id->driver_info == LINE6_PODX3) ? &podx3_pcm_properties : + (id->driver_info == LINE6_PODX3 || + id->driver_info == LINE6_PODX3LIVE) ? &podx3_pcm_properties : &podhd_pcm_properties); if (err < 0) return err; -- GitLab From 13d62fd26924b30593ffd970be17c7344149b188 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 25 Sep 2016 15:44:03 +0000 Subject: [PATCH 0396/1167] mmc: sdhci-of-arasan: Fix non static symbol warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following sparse warning: drivers/mmc/host/sdhci-of-arasan.c:253:6: warning: symbol 'sdhci_arasan_reset' was not declared. Should it be static? Signed-off-by: Wei Yongjun Acked-by: Sören Brinkmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index da8e40af6f85e..e263671abab8e 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -250,7 +250,7 @@ static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc, writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER); } -void sdhci_arasan_reset(struct sdhci_host *host, u8 mask) +static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask) { u8 ctrl; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -- GitLab From 48ab086d262e705c4d042228479aaf0b2daffcf9 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Fri, 30 Sep 2016 09:37:38 +0800 Subject: [PATCH 0397/1167] mmc: block: add missing header dependencies We get 1 warning when building kernel with W=1: drivers/mmc/card/block.c:2147:5: warning: no previous prototype for 'mmc_blk_issue_rq' [-Wmissing-prototypes] In fact, this function is declared in drivers/mmc/card/block.h, so this patch adds missing header dependencies. Signed-off-by: Baoyou Xie Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c3335112e68c2..0f2cc9f223579 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -46,6 +46,7 @@ #include #include "queue.h" +#include "block.h" MODULE_ALIAS("mmc:block"); #ifdef MODULE_PARAM_PREFIX -- GitLab From 1720d3545b772c49b2975eeb3b8f4d3f56dc2085 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 30 Sep 2016 14:18:58 +0800 Subject: [PATCH 0398/1167] mmc: core: switch to 1V8 or 1V2 for hs400es mode When introducing hs400es, I didn't notice that we haven't switched voltage to 1V2 or 1V8 for it. That happens to work as the first controller claiming to support hs400es, arasan(5.1), which is designed to only support 1V8. So the voltage is fixed to 1V8. But it actually is wrong, and will not fit for other host controllers. Let's fix it. Fixes: commit 81ac2af65793ecf ("mmc: core: implement enhanced strobe support") Cc: Signed-off-by: Shawn Lin Reviewed-by: Douglas Anderson Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3486bc7fbb64a..f4ed5accafd06 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1263,6 +1263,16 @@ static int mmc_select_hs400es(struct mmc_card *card) goto out_err; } + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V) + err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); + + if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V) + err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); + + /* If fails try again during next card power cycle */ + if (err) + goto out_err; + err = mmc_select_bus_width(card); if (err < 0) goto out_err; -- GitLab From 4f25580fb84d934d7ecffa3c0aa8f10f7e23af92 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 30 Sep 2016 14:18:59 +0800 Subject: [PATCH 0399/1167] mmc: core: changes frequency to hs_max_dtr when selecting hs400es Per JESD84-B51 P49, Host need to change frequency to <=52MHz after setting HS_TIMING to 0x1, and host may changes frequency to <= 200MHz after setting HS_TIMING to 0x3. That means the card expects the clock rate to increase from the current used f_init (which is less than 400KHz, but still being less than 52MHz) to 52MHz, otherwise we find some eMMC devices significantly report failure when sending status. Reported-by: Xiao Yao Signed-off-by: Shawn Lin Reviewed-by: Douglas Anderson Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index f4ed5accafd06..39fc5b2b96c59 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1282,6 +1282,8 @@ static int mmc_select_hs400es(struct mmc_card *card) if (err) goto out_err; + mmc_set_clock(host, card->ext_csd.hs_max_dtr); + err = mmc_switch_status(card); if (err) goto out_err; -- GitLab From 8a3bee9b13824147dd15efb2993fb1b19c0e5555 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 30 Sep 2016 14:19:00 +0800 Subject: [PATCH 0400/1167] mmc: sdhci-of-arasan: add sdhci_arasan_voltage_switch for arasan, 5.1 Per the vendor's requirement, we shouldn't do any setting for 1.8V Signaling Enable, otherwise the interaction/behaviour between phy and controller will be undefined. Mostly it works fine if we do that, but we still see failures. Anyway, let's fix it to meet the vendor's requirement. The error log looks like: [ 93.405085] mmc1: unexpected status 0x800900 after switch [ 93.408474] mmc1: switch to bus width 1 failed [ 93.408482] mmc1: mmc_select_hs200 failed, error -110 [ 93.408492] mmc1: error -110 during resume (card was removed?) [ 93.408705] PM: resume of devices complete after 213.453 msecs Signed-off-by: Shawn Lin Acked-by: Adrian Hunter Reviewed-by: Douglas Anderson Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index e263671abab8e..410a55b1c25fe 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -265,6 +265,28 @@ static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask) } } +static int sdhci_arasan_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_180: + /* + * Plese don't switch to 1V8 as arasan,5.1 doesn't + * actually refer to this setting to indicate the + * signal voltage and the state machine will be broken + * actually if we force to enable 1V8. That's something + * like broken quirk but we could work around here. + */ + return 0; + case MMC_SIGNAL_VOLTAGE_330: + case MMC_SIGNAL_VOLTAGE_120: + /* We don't support 3V3 and 1V2 */ + break; + } + + return -EINVAL; +} + static struct sdhci_ops sdhci_arasan_ops = { .set_clock = sdhci_arasan_set_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock, @@ -661,6 +683,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev) host->mmc_host_ops.hs400_enhanced_strobe = sdhci_arasan_hs400_enhanced_strobe; + host->mmc_host_ops.start_signal_voltage_switch = + sdhci_arasan_voltage_switch; } ret = sdhci_add_host(host); -- GitLab From 3f2d26643595973e835e8356ea90c7c15cb1b0f1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 3 Oct 2016 10:58:28 +0200 Subject: [PATCH 0401/1167] mmc: core: Annotate cmd_hdr as __le32 Commit f68381a70bb2 (mmc: block: fix packed command header endianness) correctly fixed endianness handling of packed_cmd_hdr in mmc_blk_packed_hdr_wrq_prep. But now, sparse complains about incorrect types: drivers/mmc/card/block.c:1613:27: sparse: incorrect type in assignment (different base types) drivers/mmc/card/block.c:1613:27: expected unsigned int [unsigned] [usertype] drivers/mmc/card/block.c:1613:27: got restricted __le32 [usertype] ... So annotate cmd_hdr properly using __le32 to make everyone happy. Signed-off-by: Jiri Slaby Fixes: f68381a70bb2 (mmc: block: fix packed command header endianness) Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 2 +- drivers/mmc/card/queue.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 0f2cc9f223579..709a872ed484a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1787,7 +1787,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq, struct mmc_blk_data *md = mq->data; struct mmc_packed *packed = mqrq->packed; bool do_rel_wr, do_data_tag; - u32 *packed_cmd_hdr; + __le32 *packed_cmd_hdr; u8 hdr_blocks; u8 i = 1; diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index 3c15a75bae862..342f1e3f301e9 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -31,7 +31,7 @@ enum mmc_packed_type { struct mmc_packed { struct list_head list; - u32 cmd_hdr[1024]; + __le32 cmd_hdr[1024]; unsigned int blocks; u8 nr_entries; u8 retries; -- GitLab From fc605f1d8060133596bb6083fc4b7b306d1d5931 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2016 12:11:21 +0300 Subject: [PATCH 0402/1167] mmc: sdhci: Fix SDHCI_QUIRK2_STOP_WITH_TC Multi-block data transfers can specify the number of blocks either using a Set Block Count command (CMD23) or by sending a STOP command (CMD12) after the required number of blocks has transferred. CMD23 is preferred, but some cards don't support it. CMD12 with R1b response is used for writes, and R1 response for reads. Some SDHCI host controllers give a Transfer Complete (TC) interrupt for the STOP command (CMD12) whether or not a R1b response has been specified. The quirk SDHCI_QUIRK2_STOP_WITH_TC identifies those host controllers, but the implementation only considers the case where the TC interrupt arrives at the same time as the Command Complete (CC) interrupt. However, occasionally TC arrives before CC. That is harmless, but does generate an error message "Got data interrupt 0x00000002 even though no data operation was in progress". A simpler approach is to force R1b response onto all STOP commands, because SDHCI will handle TC before CC in the general case, so do that. Signed-off-by: Adrian Hunter Cc: Giuseppe Cavallaro Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 48055666c6557..3711813f5654a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1077,6 +1077,10 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) /* Initially, a command has no error */ cmd->error = 0; + if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) && + cmd->opcode == MMC_STOP_TRANSMISSION) + cmd->flags |= MMC_RSP_BUSY; + /* Wait max 10 ms */ timeout = 10; @@ -2409,7 +2413,7 @@ static void sdhci_timeout_data_timer(unsigned long data) * * \*****************************************************************************/ -static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) +static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) { if (!host->cmd) { /* @@ -2453,11 +2457,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) return; } - if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) && - !(host->cmd->flags & MMC_RSP_BUSY) && !host->data && - host->cmd->opcode == MMC_STOP_TRANSMISSION) - *mask &= ~SDHCI_INT_DATA_END; - if (intmask & SDHCI_INT_RESPONSE) sdhci_finish_command(host); } @@ -2680,8 +2679,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) } if (intmask & SDHCI_INT_CMD_MASK) - sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, - &intmask); + sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); if (intmask & SDHCI_INT_DATA_MASK) sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); -- GitLab From 606d313124094d87050896a10894200cdd2b0514 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2016 12:11:22 +0300 Subject: [PATCH 0403/1167] mmc: sdhci: Rename sdhci_set_power() to sdhci_set_power_noreg() Unlike other cases, sdhci_set_power() does not reflect the default implementation of the ->set_power() callback. Rename it and create sdhci_set_power() that is the default implementation. Signed-off-by: Adrian Hunter Cc: Jisheng Zhang Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pxav3.c | 2 +- drivers/mmc/host/sdhci.c | 26 +++++++++++++------------- drivers/mmc/host/sdhci.h | 2 ++ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index dd1938d341f7a..d0f5c05fbc195 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -315,7 +315,7 @@ static void pxav3_set_power(struct sdhci_host *host, unsigned char mode, struct mmc_host *mmc = host->mmc; u8 pwr = host->pwr; - sdhci_set_power(host, mode, vdd); + sdhci_set_power_noreg(host, mode, vdd); if (host->pwr == pwr) return; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 3711813f5654a..223a91e039dc8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1394,8 +1394,8 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode, sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); } -void sdhci_set_power(struct sdhci_host *host, unsigned char mode, - unsigned short vdd) +void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, + unsigned short vdd) { u8 pwr = 0; @@ -1459,20 +1459,17 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode, mdelay(10); } } -EXPORT_SYMBOL_GPL(sdhci_set_power); +EXPORT_SYMBOL_GPL(sdhci_set_power_noreg); -static void __sdhci_set_power(struct sdhci_host *host, unsigned char mode, - unsigned short vdd) +void sdhci_set_power(struct sdhci_host *host, unsigned char mode, + unsigned short vdd) { - struct mmc_host *mmc = host->mmc; - - if (host->ops->set_power) - host->ops->set_power(host, mode, vdd); - else if (!IS_ERR(mmc->supply.vmmc)) - sdhci_set_power_reg(host, mode, vdd); + if (IS_ERR(host->mmc->supply.vmmc)) + sdhci_set_power_noreg(host, mode, vdd); else - sdhci_set_power(host, mode, vdd); + sdhci_set_power_reg(host, mode, vdd); } +EXPORT_SYMBOL_GPL(sdhci_set_power); /*****************************************************************************\ * * @@ -1613,7 +1610,10 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } - __sdhci_set_power(host, ios->power_mode, ios->vdd); + if (host->ops->set_power) + host->ops->set_power(host, ios->power_mode, ios->vdd); + else + sdhci_set_power(host, ios->power_mode, ios->vdd); if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks(host, ios->power_mode); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index c722cd23205cd..766df17fb7eb0 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -683,6 +683,8 @@ u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, void sdhci_set_clock(struct sdhci_host *host, unsigned int clock); void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd); +void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, + unsigned short vdd); void sdhci_set_bus_width(struct sdhci_host *host, int width); void sdhci_reset(struct sdhci_host *host, u8 mask); void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); -- GitLab From 6bc090631dfc3394da0619e920662e6636dbe89c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2016 12:11:23 +0300 Subject: [PATCH 0404/1167] mmc: sdhci-pci: Let devices define their own sdhci_ops Let devices define their own sdhci_ops so that device-specific variations can be implemented without adding quirks. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 4 +++- drivers/mmc/host/sdhci-pci.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 72a1f1f5180a9..5e11e0e3be63f 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -1648,7 +1648,9 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( } host->hw_name = "PCI"; - host->ops = &sdhci_pci_ops; + host->ops = chip->fixes && chip->fixes->ops ? + chip->fixes->ops : + &sdhci_pci_ops; host->quirks = chip->quirks; host->quirks2 = chip->quirks2; diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 9c7c08b932238..6bccf56bc5fff 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -65,6 +65,8 @@ struct sdhci_pci_fixes { int (*suspend) (struct sdhci_pci_chip *); int (*resume) (struct sdhci_pci_chip *); + + const struct sdhci_ops *ops; }; struct sdhci_pci_slot { -- GitLab From fee686b74a9c115d3c4c851eb6613d1378ad0e0c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2016 12:11:24 +0300 Subject: [PATCH 0405/1167] mmc: sdhci-pci: Fix bus power failing to enable for some Intel controllers Some Intel controllers (e.g. BXT) might fail to set bus power after a D3 -> D0 transition due to the present state not yet having propagated. Retry for up to 2 milliseconds. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 5e11e0e3be63f..1d9e00a00e9fc 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -32,6 +32,14 @@ #include "sdhci-pci.h" #include "sdhci-pci-o2micro.h" +static int sdhci_pci_enable_dma(struct sdhci_host *host); +static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width); +static void sdhci_pci_hw_reset(struct sdhci_host *host); +static int sdhci_pci_select_drive_strength(struct sdhci_host *host, + struct mmc_card *card, + unsigned int max_dtr, int host_drv, + int card_drv, int *drv_type); + /*****************************************************************************\ * * * Hardware specific quirk handling * @@ -390,6 +398,45 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) return 0; } +#define SDHCI_INTEL_PWR_TIMEOUT_CNT 20 +#define SDHCI_INTEL_PWR_TIMEOUT_UDELAY 100 + +static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode, + unsigned short vdd) +{ + int cntr; + u8 reg; + + sdhci_set_power(host, mode, vdd); + + if (mode == MMC_POWER_OFF) + return; + + /* + * Bus power might not enable after D3 -> D0 transition due to the + * present state not yet having propagated. Retry for up to 2ms. + */ + for (cntr = 0; cntr < SDHCI_INTEL_PWR_TIMEOUT_CNT; cntr++) { + reg = sdhci_readb(host, SDHCI_POWER_CONTROL); + if (reg & SDHCI_POWER_ON) + break; + udelay(SDHCI_INTEL_PWR_TIMEOUT_UDELAY); + reg |= SDHCI_POWER_ON; + sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); + } +} + +static const struct sdhci_ops sdhci_intel_byt_ops = { + .set_clock = sdhci_set_clock, + .set_power = sdhci_intel_set_power, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_pci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .hw_reset = sdhci_pci_hw_reset, + .select_drive_strength = sdhci_pci_select_drive_strength, +}; + static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { .allow_runtime_pm = true, .probe_slot = byt_emmc_probe_slot, @@ -397,6 +444,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | SDHCI_QUIRK2_STOP_WITH_TC, + .ops = &sdhci_intel_byt_ops, }; static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { @@ -405,6 +453,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .allow_runtime_pm = true, .probe_slot = byt_sdio_probe_slot, + .ops = &sdhci_intel_byt_ops, }; static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { @@ -415,6 +464,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { .allow_runtime_pm = true, .own_cd_for_runtime_pm = true, .probe_slot = byt_sd_probe_slot, + .ops = &sdhci_intel_byt_ops, }; /* Define Host controllers for Intel Merrifield platform */ -- GitLab From 184892925118d924aa9304b466946ae18c029932 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 6 Oct 2016 16:00:50 -0600 Subject: [PATCH 0406/1167] samples: move blackfin gptimers-example from Documentation Move blackfin gptimers-example to samples and remove it from Documentation Makefile. Update samples Kconfig and Makefile to build gptimers-example. blackfin is the last CONFIG_BUILD_DOCSRC target in Documentation/Makefile. Hence this patch also includes changes to remove CONFIG_BUILD_DOCSRC from Makefile and lib/Kconfig.debug and updates VIDEO_PCI_SKELETON dependency on BUILD_DOCSRC. Documentation/Makefile is not deleted to avoid braking make htmldocs and make distclean. Acked-by: Michal Marek Acked-by: Jonathan Corbet Reviewed-by: Kees Cook Reported-by: Valentin Rothberg Reported-by: Paul Gortmaker Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/blackfin/00-INDEX | 4 ---- Documentation/blackfin/Makefile | 5 ----- Makefile | 3 --- drivers/media/v4l2-core/Kconfig | 2 +- lib/Kconfig.debug | 9 --------- samples/Kconfig | 6 ++++++ samples/Makefile | 2 +- samples/blackfin/Makefile | 1 + {Documentation => samples}/blackfin/gptimers-example.c | 0 10 files changed, 10 insertions(+), 24 deletions(-) delete mode 100644 Documentation/blackfin/Makefile create mode 100644 samples/blackfin/Makefile rename {Documentation => samples}/blackfin/gptimers-example.c (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index 84359654cfcbd..c2a469112c37b 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1 +1 @@ -subdir-y := blackfin +subdir-y := diff --git a/Documentation/blackfin/00-INDEX b/Documentation/blackfin/00-INDEX index c54fcdd4ae9f6..265a1effebde9 100644 --- a/Documentation/blackfin/00-INDEX +++ b/Documentation/blackfin/00-INDEX @@ -1,10 +1,6 @@ 00-INDEX - This file -Makefile - - Makefile for gptimers example file. bfin-gpio-notes.txt - Notes in developing/using bfin-gpio driver. bfin-spi-notes.txt - Notes for using bfin spi bus driver. -gptimers-example.c - - gptimers example diff --git a/Documentation/blackfin/Makefile b/Documentation/blackfin/Makefile deleted file mode 100644 index 6782c58fbc297..0000000000000 --- a/Documentation/blackfin/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifneq ($(CONFIG_BLACKFIN),) -ifneq ($(CONFIG_BFIN_GPTIMERS),) -obj-m := gptimers-example.o -endif -endif diff --git a/Makefile b/Makefile index 70de1448c5717..92b38ac151a29 100644 --- a/Makefile +++ b/Makefile @@ -933,9 +933,6 @@ vmlinux_prereq: $(vmlinux-deps) FORCE ifdef CONFIG_HEADERS_CHECK $(Q)$(MAKE) -f $(srctree)/Makefile headers_check endif -ifdef CONFIG_BUILD_DOCSRC - $(Q)$(MAKE) $(build)=Documentation -endif ifdef CONFIG_GDB_SCRIPTS $(Q)ln -fsn `cd $(srctree) && /bin/pwd`/scripts/gdb/vmlinux-gdb.py endif diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 29b3436d0910f..367523a3c774c 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -27,7 +27,7 @@ config VIDEO_FIXED_MINOR_RANGES config VIDEO_PCI_SKELETON tristate "Skeleton PCI V4L2 driver" - depends on PCI && BUILD_DOCSRC + depends on PCI depends on VIDEO_V4L2 && VIDEOBUF2_CORE depends on VIDEOBUF2_MEMOPS && VIDEOBUF2_DMA_CONTIG ---help--- diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2307d7c89dac9..a6620838afc31 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1875,15 +1875,6 @@ config PROVIDE_OHCI1394_DMA_INIT See Documentation/debugging-via-ohci1394.txt for more information. -config BUILD_DOCSRC - bool "Build targets in Documentation/ tree" - depends on HEADERS_CHECK - help - This option attempts to build objects from the source files in the - kernel Documentation/ tree. - - Say N if you are unsure. - config DMA_API_DEBUG bool "Enable debugging of DMA-API usage" depends on HAVE_DMA_API_DEBUG diff --git a/samples/Kconfig b/samples/Kconfig index 85c405fcccb0c..a6d2a43bbf2e2 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -99,4 +99,10 @@ config SAMPLE_SECCOMP Build samples of seccomp filters using various methods of BPF filter construction. +config SAMPLE_BLACKFIN_GPTIMERS + tristate "Build blackfin gptimers sample code -- loadable modules only" + depends on BLACKFIN && BFIN_GPTIMERS && m + help + Build samples of blackfin gptimers sample module. + endif # SAMPLES diff --git a/samples/Makefile b/samples/Makefile index 1a20169d85acf..e17d66d77f099 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ - configfs/ connector/ v4l/ trace_printk/ + configfs/ connector/ v4l/ trace_printk/ blackfin/ diff --git a/samples/blackfin/Makefile b/samples/blackfin/Makefile new file mode 100644 index 0000000000000..89b86cfd83a24 --- /dev/null +++ b/samples/blackfin/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SAMPLE_BLACKFIN_GPTIMERS) += gptimers-example.o diff --git a/Documentation/blackfin/gptimers-example.c b/samples/blackfin/gptimers-example.c similarity index 100% rename from Documentation/blackfin/gptimers-example.c rename to samples/blackfin/gptimers-example.c -- GitLab From f59c668c0b898bbeba7179cd34e38a53e2f86c42 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 6 Oct 2016 16:12:29 -0600 Subject: [PATCH 0407/1167] Doc: update 00-INDEX files to reflect the runnable code move Update 00-INDEX files with the current file list to reflect the runnable code move. Acked-by: Michal Marek Acked-by: Jonathan Corbet Reviewed-by: Kees Cook Signed-off-by: Shuah Khan --- Documentation/00-INDEX | 3 ++- Documentation/arm/00-INDEX | 2 -- Documentation/filesystems/00-INDEX | 2 -- Documentation/networking/00-INDEX | 2 -- Documentation/spi/00-INDEX | 2 -- Documentation/timers/00-INDEX | 4 ---- 6 files changed, 2 insertions(+), 13 deletions(-) diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index cb9a6c6fa83b2..3acc4f1a6f842 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -46,7 +46,8 @@ IRQ.txt Intel-IOMMU.txt - basic info on the Intel IOMMU virtualization support. Makefile - - some files in Documentation dir are actually sample code to build + - This file does nothing. Removing it breaks make htmldocs and + make distclean. ManagementStyle - how to (attempt to) manage kernel hackers. RCU/ diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX index dea011c8d7c71..b6e69fd371c4f 100644 --- a/Documentation/arm/00-INDEX +++ b/Documentation/arm/00-INDEX @@ -8,8 +8,6 @@ Interrupts - ARM Interrupt subsystem documentation IXP4xx - Intel IXP4xx Network processor. -Makefile - - Build sourcefiles as part of the Documentation-build for arm Netwinder - Netwinder specific documentation Porting diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 9922939e7d99e..f66e748fc5e4e 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX @@ -2,8 +2,6 @@ - this file (info on some of the filesystems supported by linux). Locking - info on locking rules as they pertain to Linux VFS. -Makefile - - Makefile for building the filsystems-part of DocBook. 9p.txt - 9p (v9fs) is an implementation of the Plan 9 remote fs protocol. adfs.txt diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index 415154a487d07..98f3d4b1bec99 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -10,8 +10,6 @@ LICENSE.qlge - GPLv2 for QLogic Linux qlge NIC Driver LICENSE.qlcnic - GPLv2 for QLogic Linux qlcnic NIC Driver -Makefile - - Makefile for docsrc. PLIP.txt - PLIP: The Parallel Line Internet Protocol device driver README.ipw2100 diff --git a/Documentation/spi/00-INDEX b/Documentation/spi/00-INDEX index 4644bf0d9832e..8e4bb17d70ebb 100644 --- a/Documentation/spi/00-INDEX +++ b/Documentation/spi/00-INDEX @@ -1,7 +1,5 @@ 00-INDEX - this file. -Makefile - - Makefile for the example sourcefiles. butterfly - AVR Butterfly SPI driver overview and pin configuration. ep93xx_spi diff --git a/Documentation/timers/00-INDEX b/Documentation/timers/00-INDEX index ee212a27772f6..3be05fe0f1f9e 100644 --- a/Documentation/timers/00-INDEX +++ b/Documentation/timers/00-INDEX @@ -4,12 +4,8 @@ highres.txt - High resolution timers and dynamic ticks design notes hpet.txt - High Precision Event Timer Driver for Linux -hpet_example.c - - sample hpet timer test program hrtimers.txt - subsystem for high-resolution kernel timers -Makefile - - Build and link hpet_example NO_HZ.txt - Summary of the different methods for the scheduler clock-interrupts management. timekeeping.txt -- GitLab From 8c136b590f79f7f4f60ae4709fc1340885ca2eba Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 5 Oct 2016 18:30:43 +0200 Subject: [PATCH 0408/1167] drm/etnaviv: ensure write caches are flushed at end of user cmdstream If the GPU is done with one user command stream the buffers referenced by this command stream may go away and get unmapped from the MMU. If the write caches are still dirty at this point later evictions will run into MMU faults, killing the GPU. Make sure the write caches are flushed before signaling completion of the user command stream. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index cb86c7e5495c5..d9230132dfbcc 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -329,20 +329,34 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, /* * Append a LINK to the submitted command buffer to return to * the ring buffer. return_target is the ring target address. - * We need three dwords: event, wait, link. + * We need at most 7 dwords in the return target: 2 cache flush + + * 2 semaphore stall + 1 event + 1 wait + 1 link. */ - return_dwords = 3; + return_dwords = 7; return_target = etnaviv_buffer_reserve(gpu, buffer, return_dwords); CMD_LINK(cmdbuf, return_dwords, return_target); /* - * Append event, wait and link pointing back to the wait - * command to the ring buffer. + * Append a cache flush, stall, event, wait and link pointing back to + * the wait command to the ring buffer. */ + if (gpu->exec_state == ETNA_PIPE_2D) { + CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, + VIVS_GL_FLUSH_CACHE_PE2D); + } else { + CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, + VIVS_GL_FLUSH_CACHE_DEPTH | + VIVS_GL_FLUSH_CACHE_COLOR); + CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE, + VIVS_TS_FLUSH_CACHE_FLUSH); + } + CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); + CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) | VIVS_GL_EVENT_FROM_PE); CMD_WAIT(buffer); - CMD_LINK(buffer, 2, return_target + 8); + CMD_LINK(buffer, 2, etnaviv_iommu_get_cmdbuf_va(gpu, buffer) + + buffer->user_size - 4); if (drm_debug & DRM_UT_DRIVER) pr_info("stream link to 0x%08x @ 0x%08x %p\n", -- GitLab From 8814d2dce00f77c5eeb7278981ac6fd08835629e Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 6 Oct 2016 17:03:28 +0200 Subject: [PATCH 0409/1167] drm/etnaviv: block 64K of address space behind each cmdstream To make sure we don't place anything there which might confuse the FE prefetcher. This gets rid of another case of FE MMU faults when the address space gets crowded before triggering the reaper. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index d3796ed8d8c5b..169ac96e8f086 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -330,7 +330,8 @@ u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu, return (u32)buf->vram_node.start; mutex_lock(&mmu->lock); - ret = etnaviv_iommu_find_iova(mmu, &buf->vram_node, buf->size); + ret = etnaviv_iommu_find_iova(mmu, &buf->vram_node, + buf->size + SZ_64K); if (ret < 0) { mutex_unlock(&mmu->lock); return 0; -- GitLab From cabca8c098f00c91aeb59170e86e5c5fa4f494c2 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Sat, 8 Oct 2016 22:47:14 +0100 Subject: [PATCH 0410/1167] MIPS: Enable hardened usercopy Enable CONFIG_HARDENED_USERCOPY checks for MIPS, calling check_object size in all of copy_{to,from}_user(), __copy_{to,from}_user() & __copy_{to,from}_user_inatomic(). Signed-off-by: Paul Burton Cc: Kees Cook Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14371/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + arch/mips/include/asm/uaccess.h | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index a7d9224c2a508..7f6da2c8023de 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -66,6 +66,7 @@ config MIPS select HANDLE_DOMAIN_IRQ select HAVE_EXIT_THREAD select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_ARCH_HARDENED_USERCOPY menu "Machine selection" diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h index 21a2aaba20d5e..c65707df61f41 100644 --- a/arch/mips/include/asm/uaccess.h +++ b/arch/mips/include/asm/uaccess.h @@ -858,7 +858,10 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n); __cu_to = (to); \ __cu_from = (from); \ __cu_len = (n); \ + \ + check_object_size(__cu_from, __cu_len, true); \ might_fault(); \ + \ if (eva_kernel_access()) \ __cu_len = __invoke_copy_to_kernel(__cu_to, __cu_from, \ __cu_len); \ @@ -879,6 +882,9 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); __cu_to = (to); \ __cu_from = (from); \ __cu_len = (n); \ + \ + check_object_size(__cu_from, __cu_len, true); \ + \ if (eva_kernel_access()) \ __cu_len = __invoke_copy_to_kernel(__cu_to, __cu_from, \ __cu_len); \ @@ -897,6 +903,9 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); __cu_to = (to); \ __cu_from = (from); \ __cu_len = (n); \ + \ + check_object_size(__cu_to, __cu_len, false); \ + \ if (eva_kernel_access()) \ __cu_len = __invoke_copy_from_kernel_inatomic(__cu_to, \ __cu_from,\ @@ -931,6 +940,9 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); __cu_to = (to); \ __cu_from = (from); \ __cu_len = (n); \ + \ + check_object_size(__cu_from, __cu_len, true); \ + \ if (eva_kernel_access()) { \ __cu_len = __invoke_copy_to_kernel(__cu_to, \ __cu_from, \ @@ -1123,6 +1135,9 @@ extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n); __cu_to = (to); \ __cu_from = (from); \ __cu_len = (n); \ + \ + check_object_size(__cu_to, __cu_len, false); \ + \ if (eva_kernel_access()) { \ __cu_len = __invoke_copy_from_kernel(__cu_to, \ __cu_from, \ @@ -1161,6 +1176,9 @@ extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n); __cu_to = (to); \ __cu_from = (from); \ __cu_len = (n); \ + \ + check_object_size(__cu_to, __cu_len, false); \ + \ if (eva_kernel_access()) { \ __cu_len = __invoke_copy_from_kernel(__cu_to, \ __cu_from, \ -- GitLab From 2d8e60e8b0742b7a5cddc806fe38bb81ee876c33 Mon Sep 17 00:00:00 2001 From: Baole Ni Date: Tue, 2 Aug 2016 18:50:25 +0800 Subject: [PATCH 0411/1167] drm/vmwgfx: Replace numeric parameter like 0444 with macro I find that the developers often just specified the numeric value when calling a macro which is defined with a parameter for access permission. As we know, these numeric value for access permission have had the corresponding macro, and that using macro can improve the robustness and readability of the code, thus, I suggest replacing the numeric parameter with the macro. Signed-off-by: Chuansheng Liu Signed-off-by: Baole Ni Reviewed-by: Sinclair Yeh Signed-off-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index e8ae3dc476d16..18061a4bc2f28 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -241,15 +241,15 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, void *ptr); MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev"); -module_param_named(enable_fbdev, enable_fbdev, int, 0600); +module_param_named(enable_fbdev, enable_fbdev, int, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(force_dma_api, "Force using the DMA API for TTM pages"); -module_param_named(force_dma_api, vmw_force_iommu, int, 0600); +module_param_named(force_dma_api, vmw_force_iommu, int, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages"); -module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600); +module_param_named(restrict_iommu, vmw_restrict_iommu, int, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages"); -module_param_named(force_coherent, vmw_force_coherent, int, 0600); +module_param_named(force_coherent, vmw_force_coherent, int, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(restrict_dma_mask, "Restrict DMA mask to 44 bits with IOMMU"); -module_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, 0600); +module_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(assume_16bpp, "Assume 16-bpp when filtering modes"); module_param_named(assume_16bpp, vmw_assume_16bpp, int, 0600); -- GitLab From 07028959bcc674dc8ca143323aeab05849a83742 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Aug 2016 08:08:28 +0100 Subject: [PATCH 0412/1167] drm/vmwgfx: Remove call to reservation_object_test_signaled_rcu before wait Since fence_wait_timeout_reservation_object_wait_timeout_rcu() with a timeout of 0 becomes reservation_object_test_signaled_rcu(), we do not need to handle such conversion in the caller. The only challenge are those callers that wish to differentiate the error code between the nonblocking busy check and potentially blocking wait. Signed-off-by: Chris Wilson Cc: Sinclair Yeh Cc: Thomas Hellstrom Reviewed-by: Sinclair Yeh Signed-off-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 6a328d507a285..52ca1c9d070ee 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -574,10 +574,8 @@ static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo, bool nonblock = !!(flags & drm_vmw_synccpu_dontblock); long lret; - if (nonblock) - return reservation_object_test_signaled_rcu(bo->resv, true) ? 0 : -EBUSY; - - lret = reservation_object_wait_timeout_rcu(bo->resv, true, true, MAX_SCHEDULE_TIMEOUT); + lret = reservation_object_wait_timeout_rcu(bo->resv, true, true, + nonblock ? 0 : MAX_SCHEDULE_TIMEOUT); if (!lret) return -EBUSY; else if (lret < 0) -- GitLab From 1f982e4e390b31d6c44fb8bf03e3462ab33b8244 Mon Sep 17 00:00:00 2001 From: Charmaine Lee Date: Mon, 10 Oct 2016 10:37:03 -0700 Subject: [PATCH 0413/1167] drm/vmwgfx: Enable SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER command And bump VMWGFX_DRIVER_MINOR to 11 Signed-off-by: Charmaine Lee Reviewed-by: Sinclair Yeh Reviewed-by: Brian Paul Signed-off-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 32 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 74304b03f9d48..7d01c183079de 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -43,7 +43,7 @@ #define VMWGFX_DRIVER_DATE "20160210" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 10 +#define VMWGFX_DRIVER_MINOR 11 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index dc5beff2b4aaf..0243acc8845f4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -3029,6 +3029,35 @@ static int vmw_cmd_dx_genmips(struct vmw_private *dev_priv, cmd->body.shaderResourceViewId); } +/** + * vmw_cmd_dx_transfer_from_buffer - + * Validate an SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_transfer_from_buffer(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDXTransferFromBuffer body; + } *cmd = container_of(header, typeof(*cmd), header); + int ret; + + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.srcSid, NULL); + if (ret != 0) + return ret; + + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.destSid, NULL); +} + static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, void *buf, uint32_t *size) @@ -3379,6 +3408,9 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { &vmw_cmd_buffer_copy_check, true, false, true), VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY_REGION, &vmw_cmd_pred_copy_check, true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER, + &vmw_cmd_dx_transfer_from_buffer, + true, false, true), }; static int vmw_cmd_check(struct vmw_private *dev_priv, -- GitLab From e7a45284ba1abcea591f7c01b05227b6698b596c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 10 Oct 2016 10:44:00 -0700 Subject: [PATCH 0414/1167] drm/vmwgfx: Allow resource relocations on byte boundaries So far, resource allocations have only been allowed on 4-byte boundaries. As commands get packed tighter, allow them on byte boundaries. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh Signed-off-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 41 ++++++++++++++++--------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 0243acc8845f4..b915f621187f6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -39,7 +39,7 @@ * * @head: List head for the software context's relocation list. * @res: Non-ref-counted pointer to the resource. - * @offset: Offset of 4 byte entries into the command buffer where the + * @offset: Offset of single byte entries into the command buffer where the * id that needs fixup is located. */ struct vmw_resource_relocation { @@ -109,7 +109,18 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, struct vmw_dma_buffer *vbo, bool validate_as_mob, uint32_t *p_val_node); - +/** + * vmw_ptr_diff - Compute the offset from a to b in bytes + * + * @a: A starting pointer. + * @b: A pointer offset in the same address space. + * + * Returns: The offset in bytes between the two pointers. + */ +static size_t vmw_ptr_diff(void *a, void *b) +{ + return (unsigned long) b - (unsigned long) a; +} /** * vmw_resources_unreserve - unreserve resources previously reserved for @@ -409,7 +420,7 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv, * @list: Pointer to head of relocation list. * @res: The resource. * @offset: Offset into the command buffer currently being parsed where the - * id that needs fixup is located. Granularity is 4 bytes. + * id that needs fixup is located. Granularity is one byte. */ static int vmw_resource_relocation_add(struct list_head *list, const struct vmw_resource *res, @@ -460,10 +471,11 @@ static void vmw_resource_relocations_apply(uint32_t *cb, struct vmw_resource_relocation *rel; list_for_each_entry(rel, list, head) { + u32 *addr = (u32 *)((unsigned long) cb + rel->offset); if (likely(rel->res != NULL)) - cb[rel->offset] = rel->res->id; + *addr = rel->res->id; else - cb[rel->offset] = SVGA_3D_CMD_NOP; + *addr = SVGA_3D_CMD_NOP; } } @@ -655,7 +667,8 @@ static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv, *p_val = NULL; ret = vmw_resource_relocation_add(&sw_context->res_relocations, res, - id_loc - sw_context->buf_start); + vmw_ptr_diff(sw_context->buf_start, + id_loc)); if (unlikely(ret != 0)) return ret; @@ -721,7 +734,7 @@ vmw_cmd_res_check(struct vmw_private *dev_priv, return vmw_resource_relocation_add (&sw_context->res_relocations, res, - id_loc - sw_context->buf_start); + vmw_ptr_diff(sw_context->buf_start, id_loc)); } ret = vmw_user_resource_lookup_handle(dev_priv, @@ -2143,10 +2156,9 @@ static int vmw_cmd_shader_define(struct vmw_private *dev_priv, return ret; return vmw_resource_relocation_add(&sw_context->res_relocations, - NULL, &cmd->header.id - - sw_context->buf_start); - - return 0; + NULL, + vmw_ptr_diff(sw_context->buf_start, + &cmd->header.id)); } /** @@ -2188,10 +2200,9 @@ static int vmw_cmd_shader_destroy(struct vmw_private *dev_priv, return ret; return vmw_resource_relocation_add(&sw_context->res_relocations, - NULL, &cmd->header.id - - sw_context->buf_start); - - return 0; + NULL, + vmw_ptr_diff(sw_context->buf_start, + &cmd->header.id)); } /** -- GitLab From 728c3b53995f71e4b175d5939b8ba3211b6bc34d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 10 Oct 2016 10:45:55 -0700 Subject: [PATCH 0415/1167] drm/vmwgfx: Remove a leftover debug printout Remove a leftover debug printout Signed-off-by: Thomas Hellstrom Reviewed-by: Brian Paul Reviewed-by: Sinclair Yeh Signed-off-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index b915f621187f6..ddd5e8a597235 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -4275,9 +4275,6 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv, ttm_bo_unref(&query_val.bo); ttm_bo_unref(&pinned_val.bo); vmw_dmabuf_unreference(&dev_priv->pinned_bo); - DRM_INFO("Dummy query bo pin count: %d\n", - dev_priv->dummy_query_bo->pin_count); - out_unlock: return; -- GitLab From 51ab70bed997f64f091a639dbe22b629725a7faf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 10 Oct 2016 10:51:24 -0700 Subject: [PATCH 0416/1167] drm/vmwgfx: Limit the user-space command buffer size With older hardware versions, the user could specify arbitrarily large command buffer sizes, causing a vmalloc / vmap space exhaustion. Signed-off-by: Thomas Hellstrom Reviewed-by: Brian Paul Reviewed-by: Sinclair Yeh Signed-off-by: Sinclair Yeh Cc: stable@vger.kernel.org --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index ddd5e8a597235..d1f4a48dee0f0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -3891,14 +3891,14 @@ static void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv, int ret; *header = NULL; - if (!dev_priv->cman || kernel_commands) - return kernel_commands; - if (command_size > SVGA_CB_MAX_SIZE) { DRM_ERROR("Command buffer is too large.\n"); return ERR_PTR(-EINVAL); } + if (!dev_priv->cman || kernel_commands) + return kernel_commands; + /* If possible, add a little space for fencing. */ cmdbuf_size = command_size + 512; cmdbuf_size = min_t(size_t, cmdbuf_size, SVGA_CB_MAX_SIZE); -- GitLab From a19440304db2d97aed5cee9bfa5017c98d2348bf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 10 Oct 2016 11:06:45 -0700 Subject: [PATCH 0417/1167] drm/vmwgfx: Avoid validating views on view destruction When a view destruction command was present in the command stream, the view was validated to avoid a device error. That caused excessive and unnecessary validations of views, surfaces and mobs on view destruction. Replace this with a new relocation type that patches the view destruction command to a NOP if the view is not present in the device after the execbuf validation sequence. Also add checks for the member size of the vmw_res_relocation struct. Fixes sporadic command submission errors on google-earth exit. Reported-by: Brian Paul Signed-off-by: Thomas Hellstrom Reviewed-by: Brian Paul Reviewed-by: Sinclair Yeh Signed-off-by: Sinclair Yeh Cc: stable@vger.kernel.org --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 71 ++++++++++++++++++++----- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index d1f4a48dee0f0..c7b53d987f06c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -34,6 +34,24 @@ #define VMW_RES_HT_ORDER 12 +/** + * enum vmw_resource_relocation_type - Relocation type for resources + * + * @vmw_res_rel_normal: Traditional relocation. The resource id in the + * command stream is replaced with the actual id after validation. + * @vmw_res_rel_nop: NOP relocation. The command is unconditionally replaced + * with a NOP. + * @vmw_res_rel_cond_nop: Conditional NOP relocation. If the resource id + * after validation is -1, the command is replaced with a NOP. Otherwise no + * action. + */ +enum vmw_resource_relocation_type { + vmw_res_rel_normal, + vmw_res_rel_nop, + vmw_res_rel_cond_nop, + vmw_res_rel_max +}; + /** * struct vmw_resource_relocation - Relocation info for resources * @@ -41,11 +59,13 @@ * @res: Non-ref-counted pointer to the resource. * @offset: Offset of single byte entries into the command buffer where the * id that needs fixup is located. + * @rel_type: Type of relocation. */ struct vmw_resource_relocation { struct list_head head; const struct vmw_resource *res; - unsigned long offset; + u32 offset:29; + enum vmw_resource_relocation_type rel_type:3; }; /** @@ -421,10 +441,13 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv, * @res: The resource. * @offset: Offset into the command buffer currently being parsed where the * id that needs fixup is located. Granularity is one byte. + * @rel_type: Relocation type. */ static int vmw_resource_relocation_add(struct list_head *list, const struct vmw_resource *res, - unsigned long offset) + unsigned long offset, + enum vmw_resource_relocation_type + rel_type) { struct vmw_resource_relocation *rel; @@ -436,6 +459,7 @@ static int vmw_resource_relocation_add(struct list_head *list, rel->res = res; rel->offset = offset; + rel->rel_type = rel_type; list_add_tail(&rel->head, list); return 0; @@ -470,12 +494,24 @@ static void vmw_resource_relocations_apply(uint32_t *cb, { struct vmw_resource_relocation *rel; + /* Validate the struct vmw_resource_relocation member size */ + BUILD_BUG_ON(SVGA_CB_MAX_SIZE >= (1 << 29)); + BUILD_BUG_ON(vmw_res_rel_max >= (1 << 3)); + list_for_each_entry(rel, list, head) { u32 *addr = (u32 *)((unsigned long) cb + rel->offset); - if (likely(rel->res != NULL)) + switch (rel->rel_type) { + case vmw_res_rel_normal: *addr = rel->res->id; - else + break; + case vmw_res_rel_nop: *addr = SVGA_3D_CMD_NOP; + break; + default: + if (rel->res->id == -1) + *addr = SVGA_3D_CMD_NOP; + break; + } } } @@ -668,7 +704,8 @@ static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv, ret = vmw_resource_relocation_add(&sw_context->res_relocations, res, vmw_ptr_diff(sw_context->buf_start, - id_loc)); + id_loc), + vmw_res_rel_normal); if (unlikely(ret != 0)) return ret; @@ -734,7 +771,8 @@ vmw_cmd_res_check(struct vmw_private *dev_priv, return vmw_resource_relocation_add (&sw_context->res_relocations, res, - vmw_ptr_diff(sw_context->buf_start, id_loc)); + vmw_ptr_diff(sw_context->buf_start, id_loc), + vmw_res_rel_normal); } ret = vmw_user_resource_lookup_handle(dev_priv, @@ -2158,7 +2196,8 @@ static int vmw_cmd_shader_define(struct vmw_private *dev_priv, return vmw_resource_relocation_add(&sw_context->res_relocations, NULL, vmw_ptr_diff(sw_context->buf_start, - &cmd->header.id)); + &cmd->header.id), + vmw_res_rel_nop); } /** @@ -2202,7 +2241,8 @@ static int vmw_cmd_shader_destroy(struct vmw_private *dev_priv, return vmw_resource_relocation_add(&sw_context->res_relocations, NULL, vmw_ptr_diff(sw_context->buf_start, - &cmd->header.id)); + &cmd->header.id), + vmw_res_rel_nop); } /** @@ -2859,8 +2899,7 @@ static int vmw_cmd_dx_cid_check(struct vmw_private *dev_priv, * @header: Pointer to the command header in the command stream. * * Check that the view exists, and if it was not created using this - * command batch, make sure it's validated (present in the device) so that - * the remove command will not confuse the device. + * command batch, conditionally make this command a NOP. */ static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, @@ -2888,10 +2927,16 @@ static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv, return ret; /* - * Add view to the validate list iff it was not created using this - * command batch. + * If the view wasn't created during this command batch, it might + * have been removed due to a context swapout, so add a + * relocation to conditionally make this command a NOP to avoid + * device errors. */ - return vmw_view_res_val_add(sw_context, view); + return vmw_resource_relocation_add(&sw_context->res_relocations, + view, + vmw_ptr_diff(sw_context->buf_start, + &cmd->header.id), + vmw_res_rel_cond_nop); } /** -- GitLab From 7ed3b3943281e9da32b52e2aac77bdb2c42c5117 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 22 Sep 2016 21:54:33 +0200 Subject: [PATCH 0418/1167] drm/vmwgfx: Use kmalloc_array() in vmw_surface_define_ioctl() Multiplications for the size determination of memory allocations indicated that array data structures should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Reviewed-by: Sinclair Yeh Signed-off-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index c2a721a8cef9d..f55754936d908 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -763,14 +763,16 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels)); srf->num_sizes = num_sizes; user_srf->size = size; - - srf->sizes = kmalloc(srf->num_sizes * sizeof(*srf->sizes), GFP_KERNEL); + srf->sizes = kmalloc_array(srf->num_sizes, + sizeof(*srf->sizes), + GFP_KERNEL); if (unlikely(srf->sizes == NULL)) { ret = -ENOMEM; goto out_no_sizes; } - srf->offsets = kmalloc(srf->num_sizes * sizeof(*srf->offsets), - GFP_KERNEL); + srf->offsets = kmalloc_array(srf->num_sizes, + sizeof(*srf->offsets), + GFP_KERNEL); if (unlikely(srf->offsets == NULL)) { ret = -ENOMEM; goto out_no_offsets; -- GitLab From c138d03f1bf3b9c7bfd449e890cc003658b5c45a Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 23 Sep 2016 17:26:02 +0200 Subject: [PATCH 0419/1167] drm/vmwgfx: Use memdup_user() rather than duplicating its implementation * Reuse existing functionality from memdup_user() instead of keeping duplicate source code. * Try this copy operation before allocating memory for the data structure member "offsets". * Delete the local variable "user_sizes" which became unnecessary with this refactoring. Signed-off-by: Markus Elfring Reviewed-by: Sinclair Yeh Signed-off-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index f55754936d908..15504c6ca3e0e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -700,7 +700,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, struct drm_vmw_surface_create_req *req = &arg->req; struct drm_vmw_surface_arg *rep = &arg->rep; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct drm_vmw_size __user *user_sizes; int ret; int i, j; uint32_t cur_bo_offset; @@ -763,11 +762,11 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels)); srf->num_sizes = num_sizes; user_srf->size = size; - srf->sizes = kmalloc_array(srf->num_sizes, - sizeof(*srf->sizes), - GFP_KERNEL); - if (unlikely(srf->sizes == NULL)) { - ret = -ENOMEM; + srf->sizes = memdup_user((struct drm_vmw_size __user *)(unsigned long) + req->size_addr, + sizeof(*srf->sizes) * srf->num_sizes); + if (IS_ERR(srf->sizes)) { + ret = PTR_ERR(srf->sizes); goto out_no_sizes; } srf->offsets = kmalloc_array(srf->num_sizes, @@ -778,16 +777,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, goto out_no_offsets; } - user_sizes = (struct drm_vmw_size __user *)(unsigned long) - req->size_addr; - - ret = copy_from_user(srf->sizes, user_sizes, - srf->num_sizes * sizeof(*srf->sizes)); - if (unlikely(ret != 0)) { - ret = -EFAULT; - goto out_no_copy; - } - srf->base_size = *srf->sizes; srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; srf->multisample_count = 0; -- GitLab From 862f6157d176c9db5a7ed423245108d9bb3d7038 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 23 Sep 2016 17:53:49 +0200 Subject: [PATCH 0420/1167] drm/vmwgfx: Adjust checks for null pointers in 13 functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The script "checkpatch.pl" can point information out like the following. Comparison to NULL could be written !… Thus fix the affected source code places. Signed-off-by: Markus Elfring Reviewed-by: Sinclair Yeh Signed-off-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 31 ++++++++++++------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 15504c6ca3e0e..b445ce9b97578 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -324,7 +324,7 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res) if (res->id != -1) { cmd = vmw_fifo_reserve(dev_priv, vmw_surface_destroy_size()); - if (unlikely(cmd == NULL)) { + if (unlikely(!cmd)) { DRM_ERROR("Failed reserving FIFO space for surface " "destruction.\n"); return; @@ -397,7 +397,7 @@ static int vmw_legacy_srf_create(struct vmw_resource *res) submit_size = vmw_surface_define_size(srf); cmd = vmw_fifo_reserve(dev_priv, submit_size); - if (unlikely(cmd == NULL)) { + if (unlikely(!cmd)) { DRM_ERROR("Failed reserving FIFO space for surface " "creation.\n"); ret = -ENOMEM; @@ -446,11 +446,10 @@ static int vmw_legacy_srf_dma(struct vmw_resource *res, uint8_t *cmd; struct vmw_private *dev_priv = res->dev_priv; - BUG_ON(val_buf->bo == NULL); - + BUG_ON(!val_buf->bo); submit_size = vmw_surface_dma_size(srf); cmd = vmw_fifo_reserve(dev_priv, submit_size); - if (unlikely(cmd == NULL)) { + if (unlikely(!cmd)) { DRM_ERROR("Failed reserving FIFO space for surface " "DMA.\n"); return -ENOMEM; @@ -538,7 +537,7 @@ static int vmw_legacy_srf_destroy(struct vmw_resource *res) submit_size = vmw_surface_destroy_size(); cmd = vmw_fifo_reserve(dev_priv, submit_size); - if (unlikely(cmd == NULL)) { + if (unlikely(!cmd)) { DRM_ERROR("Failed reserving FIFO space for surface " "eviction.\n"); return -ENOMEM; @@ -578,7 +577,7 @@ static int vmw_surface_init(struct vmw_private *dev_priv, int ret; struct vmw_resource *res = &srf->res; - BUG_ON(res_free == NULL); + BUG_ON(!res_free); if (!dev_priv->has_mob) vmw_fifo_resource_inc(dev_priv); ret = vmw_resource_init(dev_priv, res, true, res_free, @@ -747,7 +746,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, } user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); - if (unlikely(user_srf == NULL)) { + if (unlikely(!user_srf)) { ret = -ENOMEM; goto out_no_user_srf; } @@ -772,7 +771,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, srf->offsets = kmalloc_array(srf->num_sizes, sizeof(*srf->offsets), GFP_KERNEL); - if (unlikely(srf->offsets == NULL)) { + if (unlikely(!srf->offsets)) { ret = -ENOMEM; goto out_no_offsets; } @@ -914,7 +913,7 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, ret = -EINVAL; base = ttm_base_object_lookup_for_ref(dev_priv->tdev, handle); - if (unlikely(base == NULL)) { + if (unlikely(!base)) { DRM_ERROR("Could not find surface to reference.\n"); goto out_no_lookup; } @@ -1060,7 +1059,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res) cmd = vmw_fifo_reserve(dev_priv, submit_len); cmd2 = (typeof(cmd2))cmd; - if (unlikely(cmd == NULL)) { + if (unlikely(!cmd)) { DRM_ERROR("Failed reserving FIFO space for surface " "creation.\n"); ret = -ENOMEM; @@ -1126,7 +1125,7 @@ static int vmw_gb_surface_bind(struct vmw_resource *res, submit_size = sizeof(*cmd1) + (res->backup_dirty ? sizeof(*cmd2) : 0); cmd1 = vmw_fifo_reserve(dev_priv, submit_size); - if (unlikely(cmd1 == NULL)) { + if (unlikely(!cmd1)) { DRM_ERROR("Failed reserving FIFO space for surface " "binding.\n"); return -ENOMEM; @@ -1176,7 +1175,7 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res, submit_size = sizeof(*cmd3) + (readback ? sizeof(*cmd1) : sizeof(*cmd2)); cmd = vmw_fifo_reserve(dev_priv, submit_size); - if (unlikely(cmd == NULL)) { + if (unlikely(!cmd)) { DRM_ERROR("Failed reserving FIFO space for surface " "unbinding.\n"); return -ENOMEM; @@ -1235,7 +1234,7 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res) vmw_binding_res_list_scrub(&res->binding_head); cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); - if (unlikely(cmd == NULL)) { + if (unlikely(!cmd)) { DRM_ERROR("Failed reserving FIFO space for surface " "destruction.\n"); mutex_unlock(&dev_priv->binding_mutex); @@ -1401,7 +1400,7 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, user_srf = container_of(base, struct vmw_user_surface, prime.base); srf = &user_srf->srf; - if (srf->res.backup == NULL) { + if (!srf->res.backup) { DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); goto out_bad_resource; } @@ -1515,7 +1514,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, } user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); - if (unlikely(user_srf == NULL)) { + if (unlikely(!user_srf)) { ret = -ENOMEM; goto out_no_user_srf; } -- GitLab From daeb20167ddb934d4d604b361406dda858dfa0aa Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 5 Oct 2016 12:25:40 +0100 Subject: [PATCH 0421/1167] MAINTAINERS: Add ARM64-specific ACPI maintainers entry The ARM64 architecture defines ARM64 specific ACPI bindings to configure and set-up arch specific components. To simplify code reviews/updates and streamline the maintainership structure supporting the arch specific code, a new arm64 directory was created in /drivers/acpi, to contain ACPI code that is specific to ARM64 architecture. Add the ARM64-specific ACPI maintainers entry in MAINTAINERS for the newly created subdirectory and respective code content. Lorenzo Pieralisi will be in charge of submitting and managing the pull requests on behalf of all maintainers listed. Link: http://lkml.kernel.org/r/1603704.EGiVTcCxLR@vostro.rjw.lan Signed-off-by: Lorenzo Pieralisi Acked-by: Hanjun Guo Acked-by: Will Deacon Acked-by: Sudeep Holla Signed-off-by: Rafael J. Wysocki --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f593300e310b8..2a70dd97d8faa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -316,6 +316,14 @@ W: https://01.org/linux-acpi S: Supported F: drivers/acpi/fan.c +ACPI FOR ARM64 (ACPI/arm64) +M: Lorenzo Pieralisi +M: Hanjun Guo +M: Sudeep Holla +L: linux-acpi@vger.kernel.org +S: Maintained +F: drivers/acpi/arm64 + ACPI THERMAL DRIVER M: Zhang Rui L: linux-acpi@vger.kernel.org -- GitLab From 38addce8b600ca335dc86fa3d48c890f1c6fa1f4 Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Mon, 20 Jun 2016 20:41:19 +0200 Subject: [PATCH 0422/1167] gcc-plugins: Add latent_entropy plugin This adds a new gcc plugin named "latent_entropy". It is designed to extract as much possible uncertainty from a running system at boot time as possible, hoping to capitalize on any possible variation in CPU operation (due to runtime data differences, hardware differences, SMP ordering, thermal timing variation, cache behavior, etc). At the very least, this plugin is a much more comprehensive example for how to manipulate kernel code using the gcc plugin internals. The need for very-early boot entropy tends to be very architecture or system design specific, so this plugin is more suited for those sorts of special cases. The existing kernel RNG already attempts to extract entropy from reliable runtime variation, but this plugin takes the idea to a logical extreme by permuting a global variable based on any variation in code execution (e.g. a different value (and permutation function) is used to permute the global based on loop count, case statement, if/then/else branching, etc). To do this, the plugin starts by inserting a local variable in every marked function. The plugin then adds logic so that the value of this variable is modified by randomly chosen operations (add, xor and rol) and random values (gcc generates separate static values for each location at compile time and also injects the stack pointer at runtime). The resulting value depends on the control flow path (e.g., loops and branches taken). Before the function returns, the plugin mixes this local variable into the latent_entropy global variable. The value of this global variable is added to the kernel entropy pool in do_one_initcall() and _do_fork(), though it does not credit any bytes of entropy to the pool; the contents of the global are just used to mix the pool. Additionally, the plugin can pre-initialize arrays with build-time random contents, so that two different kernel builds running on identical hardware will not have the same starting values. Signed-off-by: Emese Revfy [kees: expanded commit message and code comments] Signed-off-by: Kees Cook --- arch/Kconfig | 18 + arch/powerpc/kernel/Makefile | 5 + include/linux/random.h | 11 + init/main.c | 1 + kernel/fork.c | 1 + mm/page_alloc.c | 5 + scripts/Makefile.gcc-plugins | 9 +- scripts/gcc-plugins/latent_entropy_plugin.c | 640 ++++++++++++++++++++ 8 files changed, 689 insertions(+), 1 deletion(-) create mode 100644 scripts/gcc-plugins/latent_entropy_plugin.c diff --git a/arch/Kconfig b/arch/Kconfig index fd6e9712af81b..ae80cd24e8f04 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -383,6 +383,24 @@ config GCC_PLUGIN_SANCOV gcc-4.5 on). It is based on the commit "Add fuzzing coverage support" by Dmitry Vyukov . +config GCC_PLUGIN_LATENT_ENTROPY + bool "Generate some entropy during boot and runtime" + depends on GCC_PLUGINS + help + By saying Y here the kernel will instrument some kernel code to + extract some entropy from both original and artificially created + program state. This will help especially embedded systems where + there is little 'natural' source of entropy normally. The cost + is some slowdown of the boot process (about 0.5%) and fork and + irq processing. + + Note that entropy extracted this way is not cryptographically + secure! + + This plugin was ported from grsecurity/PaX. More information at: + * https://grsecurity.net/ + * https://pax.grsecurity.net/ + config HAVE_CC_STACKPROTECTOR bool help diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index fe4c075bcf50e..62df36c3f138c 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -14,6 +14,11 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif +CFLAGS_cputable.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) +CFLAGS_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) +CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) +CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) + ifdef CONFIG_FUNCTION_TRACER # Do not trace early boot code CFLAGS_REMOVE_cputable.o = -mno-sched-epilog $(CC_FLAGS_FTRACE) diff --git a/include/linux/random.h b/include/linux/random.h index 3d6e9815cd854..a59c74cdb1eb0 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -18,6 +18,17 @@ struct random_ready_callback { }; extern void add_device_randomness(const void *, unsigned int); + +#if defined(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) && !defined(__CHECKER__) +static inline void add_latent_entropy(void) +{ + add_device_randomness((const void *)&latent_entropy, + sizeof(latent_entropy)); +} +#else +static inline void add_latent_entropy(void) {} +#endif + extern void add_input_randomness(unsigned int type, unsigned int code, unsigned int value); extern void add_interrupt_randomness(int irq, int irq_flags); diff --git a/init/main.c b/init/main.c index a8a58e2794a50..2858be732f6d2 100644 --- a/init/main.c +++ b/init/main.c @@ -789,6 +789,7 @@ int __init_or_module do_one_initcall(initcall_t fn) } WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf); + add_latent_entropy(); return ret; } diff --git a/kernel/fork.c b/kernel/fork.c index beb31725f7e27..001b18473a07a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1780,6 +1780,7 @@ long _do_fork(unsigned long clone_flags, p = copy_process(clone_flags, stack_start, stack_size, child_tidptr, NULL, trace, tls, NUMA_NO_NODE); + add_latent_entropy(); /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. diff --git a/mm/page_alloc.c b/mm/page_alloc.c index a2214c64ed3cd..248851d1fc868 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -91,6 +91,11 @@ EXPORT_PER_CPU_SYMBOL(_numa_mem_); int _node_numa_mem_[MAX_NUMNODES]; #endif +#ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY +volatile u64 latent_entropy; +EXPORT_SYMBOL(latent_entropy); +#endif + /* * Array of node states. */ diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index 61f0e6db909bb..060d2cb373dbe 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -6,6 +6,12 @@ ifdef CONFIG_GCC_PLUGINS gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so + gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += latent_entropy_plugin.so + gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += -DLATENT_ENTROPY_PLUGIN + ifdef CONFIG_PAX_LATENT_ENTROPY + DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable + endif + ifdef CONFIG_GCC_PLUGIN_SANCOV ifeq ($(CFLAGS_KCOV),) # It is needed because of the gcc-plugin.sh and gcc version checks. @@ -21,7 +27,8 @@ ifdef CONFIG_GCC_PLUGINS GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) - export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR SANCOV_PLUGIN + export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR + export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN ifneq ($(PLUGINCC),) # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication. diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c new file mode 100644 index 0000000000000..ff1939b804aef --- /dev/null +++ b/scripts/gcc-plugins/latent_entropy_plugin.c @@ -0,0 +1,640 @@ +/* + * Copyright 2012-2016 by the PaX Team + * Copyright 2016 by Emese Revfy + * Licensed under the GPL v2 + * + * Note: the choice of the license means that the compilation process is + * NOT 'eligible' as defined by gcc's library exception to the GPL v3, + * but for the kernel it doesn't matter since it doesn't link against + * any of the gcc libraries + * + * This gcc plugin helps generate a little bit of entropy from program state, + * used throughout the uptime of the kernel. Here is an instrumentation example: + * + * before: + * void __latent_entropy test(int argc, char *argv[]) + * { + * if (argc <= 1) + * printf("%s: no command arguments :(\n", *argv); + * else + * printf("%s: %d command arguments!\n", *argv, args - 1); + * } + * + * after: + * void __latent_entropy test(int argc, char *argv[]) + * { + * // latent_entropy_execute() 1. + * unsigned long local_entropy; + * // init_local_entropy() 1. + * void *local_entropy_frameaddr; + * // init_local_entropy() 3. + * unsigned long tmp_latent_entropy; + * + * // init_local_entropy() 2. + * local_entropy_frameaddr = __builtin_frame_address(0); + * local_entropy = (unsigned long) local_entropy_frameaddr; + * + * // init_local_entropy() 4. + * tmp_latent_entropy = latent_entropy; + * // init_local_entropy() 5. + * local_entropy ^= tmp_latent_entropy; + * + * // latent_entropy_execute() 3. + * if (argc <= 1) { + * // perturb_local_entropy() + * local_entropy += 4623067384293424948; + * printf("%s: no command arguments :(\n", *argv); + * // perturb_local_entropy() + * } else { + * local_entropy ^= 3896280633962944730; + * printf("%s: %d command arguments!\n", *argv, args - 1); + * } + * + * // latent_entropy_execute() 4. + * tmp_latent_entropy = rol(tmp_latent_entropy, local_entropy); + * latent_entropy = tmp_latent_entropy; + * } + * + * TODO: + * - add ipa pass to identify not explicitly marked candidate functions + * - mix in more program state (function arguments/return values, + * loop variables, etc) + * - more instrumentation control via attribute parameters + * + * BUGS: + * - none known + * + * Options: + * -fplugin-arg-latent_entropy_plugin-disable + * + * Attribute: __attribute__((latent_entropy)) + * The latent_entropy gcc attribute can be only on functions and variables. + * If it is on a function then the plugin will instrument it. If the attribute + * is on a variable then the plugin will initialize it with a random value. + * The variable must be an integer, an integer array type or a structure + * with integer fields. + */ + +#include "gcc-common.h" + +int plugin_is_GPL_compatible; + +static GTY(()) tree latent_entropy_decl; + +static struct plugin_info latent_entropy_plugin_info = { + .version = "201606141920vanilla", + .help = "disable\tturn off latent entropy instrumentation\n", +}; + +static unsigned HOST_WIDE_INT seed; +/* + * get_random_seed() (this is a GCC function) generates the seed. + * This is a simple random generator without any cryptographic security because + * the entropy doesn't come from here. + */ +static unsigned HOST_WIDE_INT get_random_const(void) +{ + unsigned int i; + unsigned HOST_WIDE_INT ret = 0; + + for (i = 0; i < 8 * sizeof(ret); i++) { + ret = (ret << 1) | (seed & 1); + seed >>= 1; + if (ret & 1) + seed ^= 0xD800000000000000ULL; + } + + return ret; +} + +static tree tree_get_random_const(tree type) +{ + unsigned long long mask; + + mask = 1ULL << (TREE_INT_CST_LOW(TYPE_SIZE(type)) - 1); + mask = 2 * (mask - 1) + 1; + + if (TYPE_UNSIGNED(type)) + return build_int_cstu(type, mask & get_random_const()); + return build_int_cst(type, mask & get_random_const()); +} + +static tree handle_latent_entropy_attribute(tree *node, tree name, + tree args __unused, + int flags __unused, + bool *no_add_attrs) +{ + tree type; +#if BUILDING_GCC_VERSION <= 4007 + VEC(constructor_elt, gc) *vals; +#else + vec *vals; +#endif + + switch (TREE_CODE(*node)) { + default: + *no_add_attrs = true; + error("%qE attribute only applies to functions and variables", + name); + break; + + case VAR_DECL: + if (DECL_INITIAL(*node)) { + *no_add_attrs = true; + error("variable %qD with %qE attribute must not be initialized", + *node, name); + break; + } + + if (!TREE_STATIC(*node)) { + *no_add_attrs = true; + error("variable %qD with %qE attribute must not be local", + *node, name); + break; + } + + type = TREE_TYPE(*node); + switch (TREE_CODE(type)) { + default: + *no_add_attrs = true; + error("variable %qD with %qE attribute must be an integer or a fixed length integer array type or a fixed sized structure with integer fields", + *node, name); + break; + + case RECORD_TYPE: { + tree fld, lst = TYPE_FIELDS(type); + unsigned int nelt = 0; + + for (fld = lst; fld; nelt++, fld = TREE_CHAIN(fld)) { + tree fieldtype; + + fieldtype = TREE_TYPE(fld); + if (TREE_CODE(fieldtype) == INTEGER_TYPE) + continue; + + *no_add_attrs = true; + error("structure variable %qD with %qE attribute has a non-integer field %qE", + *node, name, fld); + break; + } + + if (fld) + break; + +#if BUILDING_GCC_VERSION <= 4007 + vals = VEC_alloc(constructor_elt, gc, nelt); +#else + vec_alloc(vals, nelt); +#endif + + for (fld = lst; fld; fld = TREE_CHAIN(fld)) { + tree random_const, fld_t = TREE_TYPE(fld); + + random_const = tree_get_random_const(fld_t); + CONSTRUCTOR_APPEND_ELT(vals, fld, random_const); + } + + /* Initialize the fields with random constants */ + DECL_INITIAL(*node) = build_constructor(type, vals); + break; + } + + /* Initialize the variable with a random constant */ + case INTEGER_TYPE: + DECL_INITIAL(*node) = tree_get_random_const(type); + break; + + case ARRAY_TYPE: { + tree elt_type, array_size, elt_size; + unsigned int i, nelt; + HOST_WIDE_INT array_size_int, elt_size_int; + + elt_type = TREE_TYPE(type); + elt_size = TYPE_SIZE_UNIT(TREE_TYPE(type)); + array_size = TYPE_SIZE_UNIT(type); + + if (TREE_CODE(elt_type) != INTEGER_TYPE || !array_size + || TREE_CODE(array_size) != INTEGER_CST) { + *no_add_attrs = true; + error("array variable %qD with %qE attribute must be a fixed length integer array type", + *node, name); + break; + } + + array_size_int = TREE_INT_CST_LOW(array_size); + elt_size_int = TREE_INT_CST_LOW(elt_size); + nelt = array_size_int / elt_size_int; + +#if BUILDING_GCC_VERSION <= 4007 + vals = VEC_alloc(constructor_elt, gc, nelt); +#else + vec_alloc(vals, nelt); +#endif + + for (i = 0; i < nelt; i++) { + tree cst = size_int(i); + tree rand_cst = tree_get_random_const(elt_type); + + CONSTRUCTOR_APPEND_ELT(vals, cst, rand_cst); + } + + /* + * Initialize the elements of the array with random + * constants + */ + DECL_INITIAL(*node) = build_constructor(type, vals); + break; + } + } + break; + + case FUNCTION_DECL: + break; + } + + return NULL_TREE; +} + +static struct attribute_spec latent_entropy_attr = { + .name = "latent_entropy", + .min_length = 0, + .max_length = 0, + .decl_required = true, + .type_required = false, + .function_type_required = false, + .handler = handle_latent_entropy_attribute, +#if BUILDING_GCC_VERSION >= 4007 + .affects_type_identity = false +#endif +}; + +static void register_attributes(void *event_data __unused, void *data __unused) +{ + register_attribute(&latent_entropy_attr); +} + +static bool latent_entropy_gate(void) +{ + tree list; + + /* don't bother with noreturn functions for now */ + if (TREE_THIS_VOLATILE(current_function_decl)) + return false; + + /* gcc-4.5 doesn't discover some trivial noreturn functions */ + if (EDGE_COUNT(EXIT_BLOCK_PTR_FOR_FN(cfun)->preds) == 0) + return false; + + list = DECL_ATTRIBUTES(current_function_decl); + return lookup_attribute("latent_entropy", list) != NULL_TREE; +} + +static tree create_var(tree type, const char *name) +{ + tree var; + + var = create_tmp_var(type, name); + add_referenced_var(var); + mark_sym_for_renaming(var); + return var; +} + +/* + * Set up the next operation and its constant operand to use in the latent + * entropy PRNG. When RHS is specified, the request is for perturbing the + * local latent entropy variable, otherwise it is for perturbing the global + * latent entropy variable where the two operands are already given by the + * local and global latent entropy variables themselves. + * + * The operation is one of add/xor/rol when instrumenting the local entropy + * variable and one of add/xor when perturbing the global entropy variable. + * Rotation is not used for the latter case because it would transmit less + * entropy to the global variable than the other two operations. + */ +static enum tree_code get_op(tree *rhs) +{ + static enum tree_code op; + unsigned HOST_WIDE_INT random_const; + + random_const = get_random_const(); + + switch (op) { + case BIT_XOR_EXPR: + op = PLUS_EXPR; + break; + + case PLUS_EXPR: + if (rhs) { + op = LROTATE_EXPR; + /* + * This code limits the value of random_const to + * the size of a wide int for the rotation + */ + random_const &= HOST_BITS_PER_WIDE_INT - 1; + break; + } + + case LROTATE_EXPR: + default: + op = BIT_XOR_EXPR; + break; + } + if (rhs) + *rhs = build_int_cstu(unsigned_intDI_type_node, random_const); + return op; +} + +static gimple create_assign(enum tree_code code, tree lhs, tree op1, + tree op2) +{ + return gimple_build_assign_with_ops(code, lhs, op1, op2); +} + +static void perturb_local_entropy(basic_block bb, tree local_entropy) +{ + gimple_stmt_iterator gsi; + gimple assign; + tree rhs; + enum tree_code op; + + op = get_op(&rhs); + assign = create_assign(op, local_entropy, local_entropy, rhs); + gsi = gsi_after_labels(bb); + gsi_insert_before(&gsi, assign, GSI_NEW_STMT); + update_stmt(assign); +} + +static void __perturb_latent_entropy(gimple_stmt_iterator *gsi, + tree local_entropy) +{ + gimple assign; + tree temp; + enum tree_code op; + + /* 1. create temporary copy of latent_entropy */ + temp = create_var(unsigned_intDI_type_node, "tmp_latent_entropy"); + + /* 2. read... */ + add_referenced_var(latent_entropy_decl); + mark_sym_for_renaming(latent_entropy_decl); + assign = gimple_build_assign(temp, latent_entropy_decl); + gsi_insert_before(gsi, assign, GSI_NEW_STMT); + update_stmt(assign); + + /* 3. ...modify... */ + op = get_op(NULL); + assign = create_assign(op, temp, temp, local_entropy); + gsi_insert_after(gsi, assign, GSI_NEW_STMT); + update_stmt(assign); + + /* 4. ...write latent_entropy */ + assign = gimple_build_assign(latent_entropy_decl, temp); + gsi_insert_after(gsi, assign, GSI_NEW_STMT); + update_stmt(assign); +} + +static bool handle_tail_calls(basic_block bb, tree local_entropy) +{ + gimple_stmt_iterator gsi; + + for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { + gcall *call; + gimple stmt = gsi_stmt(gsi); + + if (!is_gimple_call(stmt)) + continue; + + call = as_a_gcall(stmt); + if (!gimple_call_tail_p(call)) + continue; + + __perturb_latent_entropy(&gsi, local_entropy); + return true; + } + + return false; +} + +static void perturb_latent_entropy(tree local_entropy) +{ + edge_iterator ei; + edge e, last_bb_e; + basic_block last_bb; + + gcc_assert(single_pred_p(EXIT_BLOCK_PTR_FOR_FN(cfun))); + last_bb_e = single_pred_edge(EXIT_BLOCK_PTR_FOR_FN(cfun)); + + FOR_EACH_EDGE(e, ei, last_bb_e->src->preds) { + if (ENTRY_BLOCK_PTR_FOR_FN(cfun) == e->src) + continue; + if (EXIT_BLOCK_PTR_FOR_FN(cfun) == e->src) + continue; + + handle_tail_calls(e->src, local_entropy); + } + + last_bb = single_pred(EXIT_BLOCK_PTR_FOR_FN(cfun)); + if (!handle_tail_calls(last_bb, local_entropy)) { + gimple_stmt_iterator gsi = gsi_last_bb(last_bb); + + __perturb_latent_entropy(&gsi, local_entropy); + } +} + +static void init_local_entropy(basic_block bb, tree local_entropy) +{ + gimple assign, call; + tree frame_addr, rand_const, tmp, fndecl, udi_frame_addr; + enum tree_code op; + unsigned HOST_WIDE_INT rand_cst; + gimple_stmt_iterator gsi = gsi_after_labels(bb); + + /* 1. create local_entropy_frameaddr */ + frame_addr = create_var(ptr_type_node, "local_entropy_frameaddr"); + + /* 2. local_entropy_frameaddr = __builtin_frame_address() */ + fndecl = builtin_decl_implicit(BUILT_IN_FRAME_ADDRESS); + call = gimple_build_call(fndecl, 1, integer_zero_node); + gimple_call_set_lhs(call, frame_addr); + gsi_insert_before(&gsi, call, GSI_NEW_STMT); + update_stmt(call); + + udi_frame_addr = fold_convert(unsigned_intDI_type_node, frame_addr); + assign = gimple_build_assign(local_entropy, udi_frame_addr); + gsi_insert_after(&gsi, assign, GSI_NEW_STMT); + update_stmt(assign); + + /* 3. create temporary copy of latent_entropy */ + tmp = create_var(unsigned_intDI_type_node, "tmp_latent_entropy"); + + /* 4. read the global entropy variable into local entropy */ + add_referenced_var(latent_entropy_decl); + mark_sym_for_renaming(latent_entropy_decl); + assign = gimple_build_assign(tmp, latent_entropy_decl); + gsi_insert_after(&gsi, assign, GSI_NEW_STMT); + update_stmt(assign); + + /* 5. mix local_entropy_frameaddr into local entropy */ + assign = create_assign(BIT_XOR_EXPR, local_entropy, local_entropy, tmp); + gsi_insert_after(&gsi, assign, GSI_NEW_STMT); + update_stmt(assign); + + rand_cst = get_random_const(); + rand_const = build_int_cstu(unsigned_intDI_type_node, rand_cst); + op = get_op(NULL); + assign = create_assign(op, local_entropy, local_entropy, rand_const); + gsi_insert_after(&gsi, assign, GSI_NEW_STMT); + update_stmt(assign); +} + +static bool create_latent_entropy_decl(void) +{ + varpool_node_ptr node; + + if (latent_entropy_decl != NULL_TREE) + return true; + + FOR_EACH_VARIABLE(node) { + tree name, var = NODE_DECL(node); + + if (DECL_NAME_LENGTH(var) < sizeof("latent_entropy") - 1) + continue; + + name = DECL_NAME(var); + if (strcmp(IDENTIFIER_POINTER(name), "latent_entropy")) + continue; + + latent_entropy_decl = var; + break; + } + + return latent_entropy_decl != NULL_TREE; +} + +static unsigned int latent_entropy_execute(void) +{ + basic_block bb; + tree local_entropy; + + if (!create_latent_entropy_decl()) + return 0; + + /* prepare for step 2 below */ + gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); + bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); + if (!single_pred_p(bb)) { + split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); + gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); + bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); + } + + /* 1. create the local entropy variable */ + local_entropy = create_var(unsigned_intDI_type_node, "local_entropy"); + + /* 2. initialize the local entropy variable */ + init_local_entropy(bb, local_entropy); + + bb = bb->next_bb; + + /* + * 3. instrument each BB with an operation on the + * local entropy variable + */ + while (bb != EXIT_BLOCK_PTR_FOR_FN(cfun)) { + perturb_local_entropy(bb, local_entropy); + bb = bb->next_bb; + }; + + /* 4. mix local entropy into the global entropy variable */ + perturb_latent_entropy(local_entropy); + return 0; +} + +static void latent_entropy_start_unit(void *gcc_data __unused, + void *user_data __unused) +{ + tree type, id; + int quals; + + seed = get_random_seed(false); + + if (in_lto_p) + return; + + /* extern volatile u64 latent_entropy */ + gcc_assert(TYPE_PRECISION(long_long_unsigned_type_node) == 64); + quals = TYPE_QUALS(long_long_unsigned_type_node) | TYPE_QUAL_VOLATILE; + type = build_qualified_type(long_long_unsigned_type_node, quals); + id = get_identifier("latent_entropy"); + latent_entropy_decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, id, type); + + TREE_STATIC(latent_entropy_decl) = 1; + TREE_PUBLIC(latent_entropy_decl) = 1; + TREE_USED(latent_entropy_decl) = 1; + DECL_PRESERVE_P(latent_entropy_decl) = 1; + TREE_THIS_VOLATILE(latent_entropy_decl) = 1; + DECL_EXTERNAL(latent_entropy_decl) = 1; + DECL_ARTIFICIAL(latent_entropy_decl) = 1; + lang_hooks.decls.pushdecl(latent_entropy_decl); +} + +#define PASS_NAME latent_entropy +#define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg +#define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func \ + | TODO_update_ssa +#include "gcc-generate-gimple-pass.h" + +int plugin_init(struct plugin_name_args *plugin_info, + struct plugin_gcc_version *version) +{ + bool enabled = true; + const char * const plugin_name = plugin_info->base_name; + const int argc = plugin_info->argc; + const struct plugin_argument * const argv = plugin_info->argv; + int i; + + struct register_pass_info latent_entropy_pass_info; + + latent_entropy_pass_info.pass = make_latent_entropy_pass(); + latent_entropy_pass_info.reference_pass_name = "optimized"; + latent_entropy_pass_info.ref_pass_instance_number = 1; + latent_entropy_pass_info.pos_op = PASS_POS_INSERT_BEFORE; + static const struct ggc_root_tab gt_ggc_r_gt_latent_entropy[] = { + { + .base = &latent_entropy_decl, + .nelt = 1, + .stride = sizeof(latent_entropy_decl), + .cb = >_ggc_mx_tree_node, + .pchw = >_pch_nx_tree_node + }, + LAST_GGC_ROOT_TAB + }; + + if (!plugin_default_version_check(version, &gcc_version)) { + error(G_("incompatible gcc/plugin versions")); + return 1; + } + + for (i = 0; i < argc; ++i) { + if (!(strcmp(argv[i].key, "disable"))) { + enabled = false; + continue; + } + error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); + } + + register_callback(plugin_name, PLUGIN_INFO, NULL, + &latent_entropy_plugin_info); + if (enabled) { + register_callback(plugin_name, PLUGIN_START_UNIT, + &latent_entropy_start_unit, NULL); + register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, + NULL, (void *)>_ggc_r_gt_latent_entropy); + register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, + &latent_entropy_pass_info); + } + register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, + NULL); + + return 0; +} -- GitLab From 0766f788eb727e2e330d55d30545db65bcf2623f Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Mon, 20 Jun 2016 20:42:34 +0200 Subject: [PATCH 0423/1167] latent_entropy: Mark functions with __latent_entropy The __latent_entropy gcc attribute can be used only on functions and variables. If it is on a function then the plugin will instrument it for gathering control-flow entropy. If the attribute is on a variable then the plugin will initialize it with random contents. The variable must be an integer, an integer array type or a structure with integer fields. These specific functions have been selected because they are init functions (to help gather boot-time entropy), are called at unpredictable times, or they have variable loops, each of which provide some level of latent entropy. Signed-off-by: Emese Revfy [kees: expanded commit message] Signed-off-by: Kees Cook --- block/blk-softirq.c | 2 +- drivers/char/random.c | 4 ++-- fs/namespace.c | 1 + include/linux/compiler-gcc.h | 7 +++++++ include/linux/compiler.h | 4 ++++ include/linux/fdtable.h | 2 +- include/linux/genhd.h | 2 +- include/linux/init.h | 5 +++-- include/linux/random.h | 4 ++-- kernel/fork.c | 6 ++++-- kernel/rcu/tiny.c | 2 +- kernel/rcu/tree.c | 2 +- kernel/sched/fair.c | 2 +- kernel/softirq.c | 4 ++-- kernel/time/timer.c | 2 +- lib/irq_poll.c | 2 +- lib/random32.c | 2 +- mm/page_alloc.c | 2 +- net/core/dev.c | 4 ++-- 19 files changed, 37 insertions(+), 22 deletions(-) diff --git a/block/blk-softirq.c b/block/blk-softirq.c index 53b1737e978d5..489eab825a8ae 100644 --- a/block/blk-softirq.c +++ b/block/blk-softirq.c @@ -18,7 +18,7 @@ static DEFINE_PER_CPU(struct list_head, blk_cpu_done); * Softirq action handler - move entries to local list and loop over them * while passing them to the queue registered handler. */ -static void blk_done_softirq(struct softirq_action *h) +static __latent_entropy void blk_done_softirq(struct softirq_action *h) { struct list_head *cpu_list, local_list; diff --git a/drivers/char/random.c b/drivers/char/random.c index 3efb3bf0ab839..7274ae89ddb39 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -479,8 +479,8 @@ static ssize_t _extract_entropy(struct entropy_store *r, void *buf, static void crng_reseed(struct crng_state *crng, struct entropy_store *r); static void push_to_pool(struct work_struct *work); -static __u32 input_pool_data[INPUT_POOL_WORDS]; -static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; +static __u32 input_pool_data[INPUT_POOL_WORDS] __latent_entropy; +static __u32 blocking_pool_data[OUTPUT_POOL_WORDS] __latent_entropy; static struct entropy_store input_pool = { .poolinfo = &poolinfo_table[0], diff --git a/fs/namespace.c b/fs/namespace.c index 7bb2cda3bfef5..4a9568b81138f 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2759,6 +2759,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) return new_ns; } +__latent_entropy struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, struct user_namespace *user_ns, struct fs_struct *new_fs) { diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 573c5a18908fd..432f5c97e18f4 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -188,6 +188,13 @@ #endif /* GCC_VERSION >= 40300 */ #if GCC_VERSION >= 40500 + +#ifndef __CHECKER__ +#ifdef LATENT_ENTROPY_PLUGIN +#define __latent_entropy __attribute__((latent_entropy)) +#endif +#endif + /* * Mark a position in code as unreachable. This can be used to * suppress control flow warnings after asm blocks that transfer diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 668569844d37c..ceaddaf76ff1d 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -406,6 +406,10 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s # define __attribute_const__ /* unimplemented */ #endif +#ifndef __latent_entropy +# define __latent_entropy +#endif + /* * Tell gcc if a function is cold. The compiler will assume any path * directly leading to the call is unlikely. diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index 5295535b60c60..9852c7e334660 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -105,7 +105,7 @@ struct files_struct *get_files_struct(struct task_struct *); void put_files_struct(struct files_struct *fs); void reset_files_struct(struct files_struct *); int unshare_files(struct files_struct **); -struct files_struct *dup_fd(struct files_struct *, int *); +struct files_struct *dup_fd(struct files_struct *, int *) __latent_entropy; void do_close_on_exec(struct files_struct *); int iterate_fd(struct files_struct *, unsigned, int (*)(const void *, struct file *, unsigned), diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 1dbf52f9c24b8..e0341af6950e2 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -437,7 +437,7 @@ extern void disk_flush_events(struct gendisk *disk, unsigned int mask); extern unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask); /* drivers/char/random.c */ -extern void add_disk_randomness(struct gendisk *disk); +extern void add_disk_randomness(struct gendisk *disk) __latent_entropy; extern void rand_initialize_disk(struct gendisk *disk); static inline sector_t get_start_sect(struct block_device *bdev) diff --git a/include/linux/init.h b/include/linux/init.h index 6935d02474aae..1e5c131d5c9a1 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -39,7 +39,7 @@ /* These are for everybody (although not all archs will actually discard it in modules) */ -#define __init __section(.init.text) __cold notrace +#define __init __section(.init.text) __cold notrace __latent_entropy #define __initdata __section(.init.data) #define __initconst __constsection(.init.rodata) #define __exitdata __section(.exit.data) @@ -86,7 +86,8 @@ #define __exit __section(.exit.text) __exitused __cold notrace /* Used for MEMORY_HOTPLUG */ -#define __meminit __section(.meminit.text) __cold notrace +#define __meminit __section(.meminit.text) __cold notrace \ + __latent_entropy #define __meminitdata __section(.meminit.data) #define __meminitconst __constsection(.meminit.rodata) #define __memexit __section(.memexit.text) __exitused __cold notrace diff --git a/include/linux/random.h b/include/linux/random.h index a59c74cdb1eb0..d80a4388a4fd7 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -30,8 +30,8 @@ static inline void add_latent_entropy(void) {} #endif extern void add_input_randomness(unsigned int type, unsigned int code, - unsigned int value); -extern void add_interrupt_randomness(int irq, int irq_flags); + unsigned int value) __latent_entropy; +extern void add_interrupt_randomness(int irq, int irq_flags) __latent_entropy; extern void get_random_bytes(void *buf, int nbytes); extern int add_random_ready_callback(struct random_ready_callback *rdy); diff --git a/kernel/fork.c b/kernel/fork.c index 001b18473a07a..05393881ef399 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -404,7 +404,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) } #ifdef CONFIG_MMU -static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) +static __latent_entropy int dup_mmap(struct mm_struct *mm, + struct mm_struct *oldmm) { struct vm_area_struct *mpnt, *tmp, *prev, **pprev; struct rb_node **rb_link, *rb_parent; @@ -1296,7 +1297,8 @@ init_task_pid(struct task_struct *task, enum pid_type type, struct pid *pid) * parts of the process environment (as per the clone * flags). The actual kick-off is left to the caller. */ -static struct task_struct *copy_process(unsigned long clone_flags, +static __latent_entropy struct task_struct *copy_process( + unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size, int __user *child_tidptr, diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index 944b1b491ed84..1898559e6b60d 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -170,7 +170,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) false)); } -static void rcu_process_callbacks(struct softirq_action *unused) +static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused) { __rcu_process_callbacks(&rcu_sched_ctrlblk); __rcu_process_callbacks(&rcu_bh_ctrlblk); diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 5d80925e7fc86..e5164deb51e1e 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -3013,7 +3013,7 @@ __rcu_process_callbacks(struct rcu_state *rsp) /* * Do RCU core processing for the current CPU. */ -static void rcu_process_callbacks(struct softirq_action *unused) +static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused) { struct rcu_state *rsp; diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 039de34f15216..004996df2f10e 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -8283,7 +8283,7 @@ static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle) { } * run_rebalance_domains is triggered when needed from the scheduler tick. * Also triggered for nohz idle balancing (with nohz_balancing_kick set). */ -static void run_rebalance_domains(struct softirq_action *h) +static __latent_entropy void run_rebalance_domains(struct softirq_action *h) { struct rq *this_rq = this_rq(); enum cpu_idle_type idle = this_rq->idle_balance ? diff --git a/kernel/softirq.c b/kernel/softirq.c index 17caf4b63342d..34033fd09c8c6 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -482,7 +482,7 @@ void __tasklet_hi_schedule_first(struct tasklet_struct *t) } EXPORT_SYMBOL(__tasklet_hi_schedule_first); -static void tasklet_action(struct softirq_action *a) +static __latent_entropy void tasklet_action(struct softirq_action *a) { struct tasklet_struct *list; @@ -518,7 +518,7 @@ static void tasklet_action(struct softirq_action *a) } } -static void tasklet_hi_action(struct softirq_action *a) +static __latent_entropy void tasklet_hi_action(struct softirq_action *a) { struct tasklet_struct *list; diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 32bf6f75a8fec..2d47980a1bc42 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1633,7 +1633,7 @@ static inline void __run_timers(struct timer_base *base) /* * This function runs timers and the timer-tq in bottom half context. */ -static void run_timer_softirq(struct softirq_action *h) +static __latent_entropy void run_timer_softirq(struct softirq_action *h) { struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); diff --git a/lib/irq_poll.c b/lib/irq_poll.c index 836f7db4e548e..63be7495dbb25 100644 --- a/lib/irq_poll.c +++ b/lib/irq_poll.c @@ -74,7 +74,7 @@ void irq_poll_complete(struct irq_poll *iop) } EXPORT_SYMBOL(irq_poll_complete); -static void irq_poll_softirq(struct softirq_action *h) +static void __latent_entropy irq_poll_softirq(struct softirq_action *h) { struct list_head *list = this_cpu_ptr(&blk_cpu_iopoll); int rearm = 0, budget = irq_poll_budget; diff --git a/lib/random32.c b/lib/random32.c index 69ed593aab073..a30923573676e 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -47,7 +47,7 @@ static inline void prandom_state_selftest(void) } #endif -static DEFINE_PER_CPU(struct rnd_state, net_rand_state); +static DEFINE_PER_CPU(struct rnd_state, net_rand_state) __latent_entropy; /** * prandom_u32_state - seeded pseudo-random number generator. diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 248851d1fc868..901121af4e546 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -92,7 +92,7 @@ int _node_numa_mem_[MAX_NUMNODES]; #endif #ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY -volatile u64 latent_entropy; +volatile u64 latent_entropy __latent_entropy; EXPORT_SYMBOL(latent_entropy); #endif diff --git a/net/core/dev.c b/net/core/dev.c index ea6312057a713..ee076c2791f95 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3855,7 +3855,7 @@ int netif_rx_ni(struct sk_buff *skb) } EXPORT_SYMBOL(netif_rx_ni); -static void net_tx_action(struct softirq_action *h) +static __latent_entropy void net_tx_action(struct softirq_action *h) { struct softnet_data *sd = this_cpu_ptr(&softnet_data); @@ -5187,7 +5187,7 @@ static int napi_poll(struct napi_struct *n, struct list_head *repoll) return work; } -static void net_rx_action(struct softirq_action *h) +static __latent_entropy void net_rx_action(struct softirq_action *h) { struct softnet_data *sd = this_cpu_ptr(&softnet_data); unsigned long time_limit = jiffies + 2; -- GitLab From 69e67a0626e503676ea2933b448f7aca8dd544f5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 25 Sep 2016 20:13:57 +0800 Subject: [PATCH 0424/1167] PM / devfreq: exynos-nocp: Select REGMAP_MMIO This driver uses devm_regmap_init_mmio(), so select REGMAP_MMIO to avoid build failure. Signed-off-by: Axel Lin Acked-by: Chanwoo Choi Signed-off-by: Rafael J. Wysocki --- drivers/devfreq/event/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig index 0fdae86089613..cd949800eed96 100644 --- a/drivers/devfreq/event/Kconfig +++ b/drivers/devfreq/event/Kconfig @@ -17,6 +17,7 @@ config DEVFREQ_EVENT_EXYNOS_NOCP tristate "EXYNOS NoC (Network On Chip) Probe DEVFREQ event Driver" depends on ARCH_EXYNOS || COMPILE_TEST select PM_OPP + select REGMAP_MMIO help This add the devfreq-event driver for Exynos SoC. It provides NoC (Network on Chip) Probe counters to measure the bandwidth of AXI bus. -- GitLab From 3b91f4b361daad1f3e1c60ca5a7861e8b36f9728 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 25 Sep 2016 20:13:58 +0800 Subject: [PATCH 0425/1167] PM / devfreq: exynos-nocp: Remove redundant code load_count/total_count are reset by devfreq_event_get_event(), so remove the redundant code in exynos_nocp_get_event(). Signed-off-by: Axel Lin Acked-by: Chanwoo Choi [ rjw: Subject/changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/devfreq/event/exynos-nocp.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/devfreq/event/exynos-nocp.c b/drivers/devfreq/event/exynos-nocp.c index a5841403bde8b..49e712aca0c15 100644 --- a/drivers/devfreq/event/exynos-nocp.c +++ b/drivers/devfreq/event/exynos-nocp.c @@ -176,9 +176,6 @@ static int exynos_nocp_get_event(struct devfreq_event_dev *edev, return 0; out: - edata->load_count = 0; - edata->total_count = 0; - dev_err(nocp->dev, "Failed to read the counter of NoC probe device\n"); return ret; -- GitLab From 0f376c9cd86c23f37312d37748b233660ef9d9af Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 29 Sep 2016 10:13:28 +0800 Subject: [PATCH 0426/1167] PM / devfreq: Add proper locking around list_del() Use devfreq_list_lock around list_del() to prevent list corruption. Signed-off-by: Axel Lin Acked-by: MyungJoo Ham Signed-off-by: Rafael J. Wysocki --- drivers/devfreq/devfreq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 478006b7764a5..66d3c7184a0f0 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -594,17 +594,19 @@ struct devfreq *devfreq_add_device(struct device *dev, if (devfreq->governor) err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START, NULL); - mutex_unlock(&devfreq_list_lock); if (err) { dev_err(dev, "%s: Unable to start governor for the device\n", __func__); goto err_init; } + mutex_unlock(&devfreq_list_lock); return devfreq; err_init: list_del(&devfreq->node); + mutex_unlock(&devfreq_list_lock); + device_unregister(&devfreq->dev); err_out: return ERR_PTR(err); -- GitLab From d0563a039c9d35305f4cb2405665130de596d86a Mon Sep 17 00:00:00 2001 From: Tobias Jakobi Date: Thu, 29 Sep 2016 14:36:36 +0200 Subject: [PATCH 0427/1167] PM / devfreq: Skip status update on uninitialized previous_freq In case devfreq->previous_freq is still uninitialized in devfreq_update_status(), i.e. it has value '0', the lookups in that function fail, eventually leading to some error message: [ 3.041292] devfreq bus_dmc: Couldn't update frequency transition information. Just skip the statup update in this situation. Signed-off-by: Tobias Jakobi Acked-by: MyungJoo Ham Signed-off-by: Rafael J. Wysocki --- drivers/devfreq/devfreq.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 66d3c7184a0f0..bf3ea7603a58a 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -137,6 +137,10 @@ static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) cur_time = jiffies; + /* Immediately exit if previous_freq is not initialized yet. */ + if (!devfreq->previous_freq) + goto out; + prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq); if (prev_lev < 0) { ret = prev_lev; -- GitLab From 1e01892e7ad521a96760da0d791b42badf755d3f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 7 Oct 2016 16:06:15 +0200 Subject: [PATCH 0428/1167] scripts/coccicheck: Update reference for the corresponding documentation Use the current name (in a comment at the beginning of this script) for the file which was converted to the documentation format "reStructuredText" in August 2016. Fixes: 4b9033a33494 ("docs: sphinxify coccinelle.txt and add it to dev-tools") Signed-off-by: Markus Elfring Acked-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccicheck | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/coccicheck b/scripts/coccicheck index c92c1528a54dd..ec487b8e7051e 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck @@ -1,7 +1,7 @@ #!/bin/bash # Linux kernel coccicheck # -# Read Documentation/coccinelle.txt +# Read Documentation/dev-tools/coccinelle.rst # # This script requires at least spatch # version 1.0.0-rc11. -- GitLab From c8990359d4b12f14656386526ddf904635076902 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sat, 8 Oct 2016 17:51:45 +0200 Subject: [PATCH 0429/1167] Coccinelle: flag conditions with no effect Report code constructs where the if and else branch are functionally identical. In cases where this is intended it really should be documented - most reported cases probably are bugs. Signed-off-by: Nicholas Mc Guire Signed-off-by: Michal Marek --- scripts/coccinelle/misc/cond_no_effect.cocci | 64 ++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 scripts/coccinelle/misc/cond_no_effect.cocci diff --git a/scripts/coccinelle/misc/cond_no_effect.cocci b/scripts/coccinelle/misc/cond_no_effect.cocci new file mode 100644 index 0000000000000..8467dbd1c465c --- /dev/null +++ b/scripts/coccinelle/misc/cond_no_effect.cocci @@ -0,0 +1,64 @@ +///Find conditions where if and else branch are functionally +// identical. +// +// There can be false positives in cases where the positional +// information is used (as with lockdep) or where the identity +// is a placeholder for not yet handled cases. +// Unfortunately there also seems to be a tendency to use +// the last if else/else as a "default behavior" - which some +// might consider a legitimate coding pattern. From discussion +// on kernelnewbies though it seems that this is not really an +// accepted pattern and if at all it would need to be commented +// +// In the Linux kernel it does not seem to actually report +// false positives except for those that were documented as +// being intentional. +// the two known cases are: +// arch/sh/kernel/traps_64.c:read_opcode() +// } else if ((pc & 1) == 0) { +// /* SHcompact */ +// /* TODO : provide handling for this. We don't really support +// user-mode SHcompact yet, and for a kernel fault, this would +// have to come from a module built for SHcompact. */ +// return -EFAULT; +// } else { +// /* misaligned */ +// return -EFAULT; +// } +// fs/kernfs/file.c:kernfs_fop_open() +// * Both paths of the branch look the same. They're supposed to +// * look that way and give @of->mutex different static lockdep keys. +// */ +// if (has_mmap) +// mutex_init(&of->mutex); +// else +// mutex_init(&of->mutex); +// +// All other cases look like bugs or at least lack of documentation +// +// Confidence: Moderate +// Copyright: (C) 2016 Nicholas Mc Guire, OSADL. GPLv2. +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report + +@cond@ +statement S1; +position p; +@@ + +* if@p (...) S1 else S1 + +@script:python depends on org@ +p << cond.p; +@@ + +cocci.print_main("WARNING: possible condition with no effect (if == else)",p) + +@script:python depends on report@ +p << cond.p; +@@ + +coccilib.report.print_report(p[0],"WARNING: possible condition with no effect (if == else)") -- GitLab From 2cc17fda94c5ee8c64c2fdc2ef981fc277e2e958 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Mon, 10 Oct 2016 15:24:01 -0500 Subject: [PATCH 0430/1167] objtool: Support '-mtune=atom' stack frame setup instruction Arnd reported that enabling CONFIG_MATOM results in a bunch of objtool false positive frame pointer warnings: arch/x86/events/intel/ds.o: warning: objtool: intel_pmu_pebs_del()+0x43: call without frame pointer save/setup security/keys/keyring.o: warning: objtool: keyring_read()+0x59: call without frame pointer save/setup kernel/signal.o: warning: objtool: __dequeue_signal()+0xd8: call without frame pointer save/setup ... objtool gets confused by the fact that the '-mtune=atom' GCC option sometimes uses 'lea (%rsp),%rbp' instead of 'mov %rsp,%rbp'. The instructions are effectively the same, but objtool doesn't know about the 'lea' variant. Fix the false warnings by adding support for 'lea (%rsp),%rbp' in the objtool decoder. Reported-by: Arnd Bergmann Signed-off-by: Josh Poimboeuf Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- tools/objtool/arch/x86/decode.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index c0c0b265e88e5..b63a31be12188 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -98,6 +98,15 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, *type = INSN_FP_SETUP; break; + case 0x8d: + if (insn.rex_prefix.bytes && + insn.rex_prefix.bytes[0] == 0x48 && + insn.modrm.nbytes && insn.modrm.bytes[0] == 0x2c && + insn.sib.nbytes && insn.sib.bytes[0] == 0x24) + /* lea %(rsp), %rbp */ + *type = INSN_FP_SETUP; + break; + case 0x90: *type = INSN_NOP; break; -- GitLab From 9cfb38a7ba5a9c27c1af8093fb1af4b699c0a441 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Sun, 9 Oct 2016 08:04:03 +0800 Subject: [PATCH 0431/1167] sched/fair: Fix sched domains NULL dereference in select_idle_sibling() Commit: 10e2f1acd01 ("sched/core: Rewrite and improve select_idle_siblings()") ... improved select_idle_sibling(), but also triggered a regression (crash) during CPU-hotplug: BUG: unable to handle kernel NULL pointer dereference at 0000000000000078 IP: [] select_idle_sibling+0x1c2/0x4f0 Call Trace: select_task_rq_fair+0x749/0x930 ? select_task_rq_fair+0xb4/0x930 ? __lock_is_held+0x54/0x70 try_to_wake_up+0x19a/0x5b0 default_wake_function+0x12/0x20 autoremove_wake_function+0x12/0x40 __wake_up_common+0x55/0x90 __wake_up+0x39/0x50 wake_up_klogd_work_func+0x40/0x60 irq_work_run_list+0x57/0x80 irq_work_run+0x2c/0x30 smp_irq_work_interrupt+0x2e/0x40 irq_work_interrupt+0x96/0xa0 ? _raw_spin_unlock_irqrestore+0x45/0x80 try_to_wake_up+0x4a/0x5b0 wake_up_state+0x10/0x20 __kthread_unpark+0x67/0x70 kthread_unpark+0x22/0x30 cpuhp_online_idle+0x3e/0x70 cpu_startup_entry+0x6a/0x450 start_secondary+0x154/0x180 This can be reproduced by running the ftrace test case of kselftest, the test case will hot-unplug the CPU and the CPU will attach to the NULL sched-domain during scheduler teardown. The step 2 for the rewrite select_idle_siblings(): | Step 2) tracks the average cost of the scan and compares this to the | average idle time guestimate for the CPU doing the wakeup. If the CPU which doing the wakeup is the going hot-unplug CPU, then NULL sched domain will be dereferenced to acquire the average cost of the scan. This patch fix it by failing the search of an idle CPU in the LLC process if this sched domain is NULL. Tested-by: Catalin Marinas Signed-off-by: Wanpeng Li Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1475971443-3187-1-git-send-email-wanpeng.li@hotmail.com Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 502e95a6e9276..8b03fb5d1b9e2 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5471,13 +5471,18 @@ static inline int select_idle_smt(struct task_struct *p, struct sched_domain *sd */ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int target) { - struct sched_domain *this_sd = rcu_dereference(*this_cpu_ptr(&sd_llc)); - u64 avg_idle = this_rq()->avg_idle; - u64 avg_cost = this_sd->avg_scan_cost; + struct sched_domain *this_sd; + u64 avg_cost, avg_idle = this_rq()->avg_idle; u64 time, cost; s64 delta; int cpu, wrap; + this_sd = rcu_dereference(*this_cpu_ptr(&sd_llc)); + if (!this_sd) + return -1; + + avg_cost = this_sd->avg_scan_cost; + /* * Due to large variance we need a large fuzz factor; hackbench in * particularly is sensitive here. -- GitLab From 05af40e885955065aee8bb7425058eb3e1adca08 Mon Sep 17 00:00:00 2001 From: Laurent Dufour Date: Thu, 6 Oct 2016 15:33:21 +0200 Subject: [PATCH 0432/1167] powerpc/pseries: Fix stack corruption in htpe code This commit fixes a stack corruption in the pseries specific code dealing with the huge pages. In __pSeries_lpar_hugepage_invalidate() the buffer used to pass arguments to the hypervisor is not large enough. This leads to a stack corruption where a previously saved register could be corrupted leading to unexpected result in the caller, like the following panic: Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=2048 NUMA pSeries Modules linked in: virtio_balloon ip_tables x_tables autofs4 virtio_blk 8139too virtio_pci virtio_ring 8139cp virtio CPU: 11 PID: 1916 Comm: mmstress Not tainted 4.8.0 #76 task: c000000005394880 task.stack: c000000005570000 NIP: c00000000027bf6c LR: c00000000027bf64 CTR: 0000000000000000 REGS: c000000005573820 TRAP: 0300 Not tainted (4.8.0) MSR: 8000000000009033 CR: 84822884 XER: 20000000 CFAR: c00000000010a924 DAR: 420000000014e5e0 DSISR: 40000000 SOFTE: 1 GPR00: c00000000027bf64 c000000005573aa0 c000000000e02800 c000000004447964 GPR04: c00000000404de18 c000000004d38810 00000000042100f5 00000000f5002104 GPR08: e0000000f5002104 0000000000000001 042100f5000000e0 00000000042100f5 GPR12: 0000000000002200 c00000000fe02c00 c00000000404de18 0000000000000000 GPR16: c1ffffffffffe7ff 00003fff62000000 420000000014e5e0 00003fff63000000 GPR20: 0008000000000000 c0000000f7014800 0405e600000000e0 0000000000010000 GPR24: c000000004d38810 c000000004447c10 c00000000404de18 c000000004447964 GPR28: c000000005573b10 c000000004d38810 00003fff62000000 420000000014e5e0 NIP [c00000000027bf6c] zap_huge_pmd+0x4c/0x470 LR [c00000000027bf64] zap_huge_pmd+0x44/0x470 Call Trace: [c000000005573aa0] [c00000000027bf64] zap_huge_pmd+0x44/0x470 (unreliable) [c000000005573af0] [c00000000022bbd8] unmap_page_range+0xcf8/0xed0 [c000000005573c30] [c00000000022c2d4] unmap_vmas+0x84/0x120 [c000000005573c80] [c000000000235448] unmap_region+0xd8/0x1b0 [c000000005573d80] [c0000000002378f0] do_munmap+0x2d0/0x4c0 [c000000005573df0] [c000000000237be4] SyS_munmap+0x64/0xb0 [c000000005573e30] [c000000000009560] system_call+0x38/0x108 Instruction dump: fbe1fff8 fb81ffe0 7c7f1b78 7ca32b78 7cbd2b78 f8010010 7c9a2378 f821ffb1 7cde3378 4bfffea9 7c7b1b79 41820298 48000130 7fa5eb78 7fc4f378 Most of the time, the bug is surfacing in a caller up in the stack from __pSeries_lpar_hugepage_invalidate() which is quite confusing. This bug is pending since v3.11 but was hidden if a caller of the caller of __pSeries_lpar_hugepage_invalidate() has pushed the corruped register (r18 in this case) in the stack and is not using it until restoring it. GCC 6.2.0 seems to raise it more frequently. This commit also change the definition of the parameter buffer in pSeries_lpar_flush_hash_range() to rely on the global define PLPAR_HCALL9_BUFSIZE (no functional change here). Fixes: 1a5272866f87 ("powerpc: Optimize hugepage invalidate") Cc: stable@vger.kernel.org # v3.11+ Signed-off-by: Laurent Dufour Reviewed-by: Aneesh Kumar K.V Acked-by: Balbir Singh Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/lpar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 86707e67843f6..aa35245d8d6d3 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -393,7 +393,7 @@ static void __pSeries_lpar_hugepage_invalidate(unsigned long *slot, unsigned long *vpn, int count, int psize, int ssize) { - unsigned long param[8]; + unsigned long param[PLPAR_HCALL9_BUFSIZE]; int i = 0, pix = 0, rc; unsigned long flags = 0; int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); @@ -522,7 +522,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) unsigned long flags = 0; struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); - unsigned long param[9]; + unsigned long param[PLPAR_HCALL9_BUFSIZE]; unsigned long hash, index, shift, hidx, slot; real_pte_t pte; int psize, ssize; -- GitLab From 7c8cb4b50f3cc6f4a8f7bfddad6fb5a845df3261 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 11 Oct 2016 18:47:56 +1100 Subject: [PATCH 0433/1167] powerpc/64s: Fix power4_fixup_nap placement power4_fixup_nap is called from the "common" handlers, not the virt/real handlers, therefore it should itself be a common handler. Placing it down in the trampoline space caused it to go out of reach of its callers, requiring a trampoline inserted at the start of the text section, which breaks the fixed section address calculations. Fixes: da2bc4644c75 ("powerpc/64s: Add new exception vector macros") Reported-by: Guenter Roeck Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/exceptions-64s.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 08992f8f50365..f129408c60229 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1377,7 +1377,7 @@ __end_interrupts: DEFINE_FIXED_SYMBOL(__end_interrupts) #ifdef CONFIG_PPC_970_NAP -TRAMP_REAL_BEGIN(power4_fixup_nap) +EXC_COMMON_BEGIN(power4_fixup_nap) andc r9,r9,r10 std r9,TI_LOCAL_FLAGS(r11) ld r10,_LINK(r1) /* make idle task do the */ -- GitLab From 034827c727f7f3946a18355b63995b402c226c82 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 6 Oct 2016 23:10:41 +0100 Subject: [PATCH 0434/1167] MIPS: Fix -mabi=64 build of vdso.lds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The native ABI vDSO linker script vdso.lds is built by preprocessing vdso.lds.S, with the native -mabi flag passed in to get the correct ABI definitions. Unfortunately however certain toolchains choke on -mabi=64 without a corresponding compatible -march flag, for example: cc1: error: ‘-march=mips32r2’ is not compatible with the selected ABI scripts/Makefile.build:338: recipe for target 'arch/mips/vdso/vdso.lds' failed Fix this by including ccflags-vdso in the KBUILD_CPPFLAGS for vdso.lds, which includes the appropriate -march flag. Fixes: ebb5e78cc634 ("MIPS: Initial implementation of a VDSO") Signed-off-by: James Hogan Reviewed-by: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org # 4.4.x- Patchwork: https://patchwork.linux-mips.org/patch/14368/ Signed-off-by: Ralf Baechle --- arch/mips/vdso/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile index 3b4538ec0102d..de9e8836d2482 100644 --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile @@ -82,7 +82,7 @@ obj-vdso := $(obj-vdso-y:%.o=$(obj)/%.o) $(obj-vdso): KBUILD_CFLAGS := $(cflags-vdso) $(native-abi) $(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi) -$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(native-abi) +$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) $(native-abi) $(obj)/vdso.so.dbg.raw: $(obj)/vdso.lds $(obj-vdso) FORCE $(call if_changed,vdsold) -- GitLab From 9445622cfbc38c980f1755fc1132a3a460b5a529 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 7 Oct 2016 10:23:46 +0100 Subject: [PATCH 0435/1167] MIPS: VDSO: Drop duplicated -I*/-E* aflags The aflags-vdso is based on ccflags-vdso, which already contains the -I* and -EL/-EB flags from KBUILD_CFLAGS, but those flags are needlessly added again to aflags-vdso. Drop the duplication. Signed-off-by: James Hogan Reported-by: Maciej W. Rozycki Reviewed-by: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14369/ Signed-off-by: Ralf Baechle --- arch/mips/vdso/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile index de9e8836d2482..c3dc12a8b7d9d 100644 --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile @@ -13,8 +13,6 @@ cflags-vdso := $(ccflags-vdso) \ -DDISABLE_BRANCH_PROFILING \ $(call cc-option, -fno-stack-protector) aflags-vdso := $(ccflags-vdso) \ - $(filter -I%,$(KBUILD_CFLAGS)) \ - $(filter -E%,$(KBUILD_CFLAGS)) \ -D__ASSEMBLY__ -Wa,-gdwarf-2 # -- GitLab From fecf861e765b2f9ce1a0487c3940afaed80ef7a8 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sun, 2 Oct 2016 11:02:18 +0900 Subject: [PATCH 0436/1167] selftests/futex: Check ANSI terminal color support Because test for color support of the running shell does not aware ANSI type terminals, it does not print colorful messages on some environemnt. This commit modifies the test to aware ANSI type terminal, too. Signed-off-by: SeongJae Park Acked-by: Darren Hart Signed-off-by: Shuah Khan --- tools/testing/selftests/futex/functional/run.sh | 2 +- tools/testing/selftests/futex/run.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh index e87dbe2a0b0d2..7ff002eed6247 100755 --- a/tools/testing/selftests/futex/functional/run.sh +++ b/tools/testing/selftests/futex/functional/run.sh @@ -24,7 +24,7 @@ # Test for a color capable console if [ -z "$USE_COLOR" ]; then - tput setf 7 + tput setf 7 || tput setaf 7 if [ $? -eq 0 ]; then USE_COLOR=1 tput sgr0 diff --git a/tools/testing/selftests/futex/run.sh b/tools/testing/selftests/futex/run.sh index 4126312ad64e6..88bcb1767362d 100755 --- a/tools/testing/selftests/futex/run.sh +++ b/tools/testing/selftests/futex/run.sh @@ -23,7 +23,7 @@ # Test for a color capable shell and pass the result to the subdir scripts USE_COLOR=0 -tput setf 7 +tput setf 7 || tput setaf 7 if [ $? -eq 0 ]; then USE_COLOR=1 tput sgr0 -- GitLab From 5c33677c87cbe44ae04df69c4a29c1750a9ec4e5 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 11 Oct 2016 15:16:57 +0100 Subject: [PATCH 0437/1167] dm raid: fix compat_features validation In ecbfb9f118bce4 ("dm raid: add raid level takeover support") a new compatible feature flag was added. Validation for these compat_features was added but this only passes for new raid mappings with this feature flag. This causes previously created raid mappings to be failed at import. Check compat_features for the only valid combination. Fixes: ecbfb9f118bce4 ("dm raid: add raid level takeover support") Cc: stable@vger.kernel.org # v4.8 Signed-off-by: Andy Whitcroft Signed-off-by: Heinz Mauelshagen Signed-off-by: Mike Snitzer --- drivers/md/dm-raid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 8abde6b8cedc4..2a39700979910 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -2258,7 +2258,8 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev) if (!mddev->events && super_init_validation(rs, rdev)) return -EINVAL; - if (le32_to_cpu(sb->compat_features) != FEATURE_FLAG_SUPPORTS_V190) { + if (le32_to_cpu(sb->compat_features) && + le32_to_cpu(sb->compat_features) != FEATURE_FLAG_SUPPORTS_V190) { rs->ti->error = "Unable to assemble array: Unknown flag(s) in compatible feature flags"; return -EINVAL; } -- GitLab From b60e4ea4a400bde8a4811f94b84a9bb65f81b677 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 29 Sep 2016 16:39:41 +0300 Subject: [PATCH 0438/1167] ACPI / property: Allow holes in reference properties DT allows holes or empty phandles for references. This is used for example in SPI subsystem where some chip selects are native and others are regular GPIOs. In ACPI _DSD we currently do not support this but instead the preceding reference consumes all following integer arguments. For example we would like to support something like the below ASL fragment for SPI: Package () { "cs-gpios", Package () { ^GPIO, 19, 0, 0, // GPIO CS0 0, // Native CS ^GPIO, 20, 0, 0, // GPIO CS1 } } The zero in the middle means "no entry" or NULL reference. To support this we change acpi_data_get_property_reference() to take firmware node and num_args as argument and rename it to __acpi_node_get_property_reference(). The function returns -ENOENT if the given index resolves to "no entry" reference and -ENODATA when there are no more entries in the property. We then add static inline wrapper acpi_node_get_property_reference() that passes MAX_ACPI_REFERENCE_ARGS as num_args to support the existing behaviour which some drivers have been relying on. Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 117 +++++++++++++++++++++++----------------- include/linux/acpi.h | 22 ++++++-- 2 files changed, 87 insertions(+), 52 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index f2fd3fee588a8..03f5ec11ab319 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -468,10 +468,11 @@ static int acpi_data_get_property_array(struct acpi_device_data *data, } /** - * acpi_data_get_property_reference - returns handle to the referenced object - * @data: ACPI device data object containing the property + * __acpi_node_get_property_reference - returns handle to the referenced object + * @fwnode: Firmware node to get the property from * @propname: Name of the property * @index: Index of the reference to return + * @num_args: Maximum number of arguments after each reference * @args: Location to store the returned reference with optional arguments * * Find property with @name, verifify that it is a package containing at least @@ -482,17 +483,40 @@ static int acpi_data_get_property_array(struct acpi_device_data *data, * If there's more than one reference in the property value package, @index is * used to select the one to return. * + * It is possible to leave holes in the property value set like in the + * example below: + * + * Package () { + * "cs-gpios", + * Package () { + * ^GPIO, 19, 0, 0, + * ^GPIO, 20, 0, 0, + * 0, + * ^GPIO, 21, 0, 0, + * } + * } + * + * Calling this function with index %2 return %-ENOENT and with index %3 + * returns the last entry. If the property does not contain any more values + * %-ENODATA is returned. The NULL entry must be single integer and + * preferably contain value %0. + * * Return: %0 on success, negative error code on failure. */ -static int acpi_data_get_property_reference(struct acpi_device_data *data, - const char *propname, size_t index, - struct acpi_reference_args *args) +int __acpi_node_get_property_reference(struct fwnode_handle *fwnode, + const char *propname, size_t index, size_t num_args, + struct acpi_reference_args *args) { const union acpi_object *element, *end; const union acpi_object *obj; + struct acpi_device_data *data; struct acpi_device *device; int ret, idx = 0; + data = acpi_device_data_of_node(fwnode); + if (!data) + return -EINVAL; + ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj); if (ret) return ret; @@ -532,59 +556,54 @@ static int acpi_data_get_property_reference(struct acpi_device_data *data, while (element < end) { u32 nargs, i; - if (element->type != ACPI_TYPE_LOCAL_REFERENCE) - return -EPROTO; - - ret = acpi_bus_get_device(element->reference.handle, &device); - if (ret) - return -ENODEV; - - element++; - nargs = 0; - - /* assume following integer elements are all args */ - for (i = 0; element + i < end; i++) { - int type = element[i].type; + if (element->type == ACPI_TYPE_LOCAL_REFERENCE) { + ret = acpi_bus_get_device(element->reference.handle, + &device); + if (ret) + return -ENODEV; + + nargs = 0; + element++; + + /* assume following integer elements are all args */ + for (i = 0; element + i < end && i < num_args; i++) { + int type = element[i].type; + + if (type == ACPI_TYPE_INTEGER) + nargs++; + else if (type == ACPI_TYPE_LOCAL_REFERENCE) + break; + else + return -EPROTO; + } - if (type == ACPI_TYPE_INTEGER) - nargs++; - else if (type == ACPI_TYPE_LOCAL_REFERENCE) - break; - else + if (nargs > MAX_ACPI_REFERENCE_ARGS) return -EPROTO; - } - if (idx++ == index) { - args->adev = device; - args->nargs = nargs; - for (i = 0; i < nargs; i++) - args->args[i] = element[i].integer.value; + if (idx == index) { + args->adev = device; + args->nargs = nargs; + for (i = 0; i < nargs; i++) + args->args[i] = element[i].integer.value; - return 0; + return 0; + } + + element += nargs; + } else if (element->type == ACPI_TYPE_INTEGER) { + if (idx == index) + return -ENOENT; + element++; + } else { + return -EPROTO; } - element += nargs; + idx++; } - return -EPROTO; -} - -/** - * acpi_node_get_property_reference - get a handle to the referenced object. - * @fwnode: Firmware node to get the property from. - * @propname: Name of the property. - * @index: Index of the reference to return. - * @args: Location to store the returned reference with optional arguments. - */ -int acpi_node_get_property_reference(struct fwnode_handle *fwnode, - const char *name, size_t index, - struct acpi_reference_args *args) -{ - struct acpi_device_data *data = acpi_device_data_of_node(fwnode); - - return data ? acpi_data_get_property_reference(data, name, index, args) : -EINVAL; + return -ENODATA; } -EXPORT_SYMBOL_GPL(acpi_node_get_property_reference); +EXPORT_SYMBOL_GPL(__acpi_node_get_property_reference); static int acpi_data_prop_read_single(struct acpi_device_data *data, const char *propname, diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 4d8452c2384b6..632ec16a855e5 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -927,9 +927,17 @@ struct acpi_reference_args { #ifdef CONFIG_ACPI int acpi_dev_get_property(struct acpi_device *adev, const char *name, acpi_object_type type, const union acpi_object **obj); -int acpi_node_get_property_reference(struct fwnode_handle *fwnode, - const char *name, size_t index, - struct acpi_reference_args *args); +int __acpi_node_get_property_reference(struct fwnode_handle *fwnode, + const char *name, size_t index, size_t num_args, + struct acpi_reference_args *args); + +static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode, + const char *name, size_t index, + struct acpi_reference_args *args) +{ + return __acpi_node_get_property_reference(fwnode, name, index, + MAX_ACPI_REFERENCE_ARGS, args); +} int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname, void **valptr); @@ -1005,6 +1013,14 @@ static inline int acpi_dev_get_property(struct acpi_device *adev, return -ENXIO; } +static inline int +__acpi_node_get_property_reference(struct fwnode_handle *fwnode, + const char *name, size_t index, size_t num_args, + struct acpi_reference_args *args) +{ + return -ENXIO; +} + static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode, const char *name, size_t index, struct acpi_reference_args *args) -- GitLab From 74f47f07e53daeca1d16812fa7c9bf3145bd8216 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 26 Sep 2016 11:54:15 +0200 Subject: [PATCH 0439/1167] gpio: pca953x: add a comment explaining the need for a lockdep subclass This is a follow-up to commit 559b46990e76 ("gpio: pca953x: fix an incorrect lockdep warning"). The reason for calling lockdep_set_subclass() in pca953x_probe() is not explained in the code. Add a comment describing the problem, partial solution and required future extensions. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/gpio/gpio-pca953x.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 45c8817d068c6..e422568e14ad1 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -794,6 +794,22 @@ static int pca953x_probe(struct i2c_client *client, } mutex_init(&chip->i2c_lock); + /* + * In case we have an i2c-mux controlled by a GPIO provided by an + * expander using the same driver higher on the device tree, read the + * i2c adapter nesting depth and use the retrieved value as lockdep + * subclass for chip->i2c_lock. + * + * REVISIT: This solution is not complete. It protects us from lockdep + * false positives when the expander controlling the i2c-mux is on + * a different level on the device tree, but not when it's on the same + * level on a different branch (in which case the subclass number + * would be the same). + * + * TODO: Once a correct solution is developed, a similar fix should be + * applied to all other i2c-controlled GPIO expanders (and potentially + * regmap-i2c). + */ lockdep_set_subclass(&chip->i2c_lock, i2c_adapter_depth(client->adapter)); -- GitLab From 1a34439e5a0b2235e43f96816dbb15ee1154f656 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2016 22:25:47 +1100 Subject: [PATCH 0440/1167] powerpc/64: Fix incorrect return value from __copy_tofrom_user Debugging a data corruption issue with virtio-net/vhost-net led to the observation that __copy_tofrom_user was occasionally returning a value 16 larger than it should. Since the return value from __copy_tofrom_user is the number of bytes not copied, this means that __copy_tofrom_user can occasionally return a value larger than the number of bytes it was asked to copy. In turn this can cause higher-level copy functions such as copy_page_to_iter_iovec to corrupt memory by copying data into the wrong memory locations. It turns out that the failing case involves a fault on the store at label 79, and at that point the first unmodified byte of the destination is at R3 + 16. Consequently the exception handler for that store needs to add 16 to R3 before using it to work out how many bytes were not copied, but in this one case it was not adding the offset to R3. To fix it, this moves the label 179 to the point where we add 16 to R3. I have checked manually all the exception handlers for the loads and stores in this code and the rest of them are correct (it would be excellent to have an automated test of all the exception cases). This bug has been present since this code was initially committed in May 2002 to Linux version 2.5.20. Cc: stable@vger.kernel.org Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/lib/copyuser_64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S index f09899e359917..7b22624f332ce 100644 --- a/arch/powerpc/lib/copyuser_64.S +++ b/arch/powerpc/lib/copyuser_64.S @@ -359,6 +359,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) addi r3,r3,8 171: 177: +179: addi r3,r3,8 370: 372: @@ -373,7 +374,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 173: 174: 175: -179: 181: 184: 186: -- GitLab From 08bf75ba852ef8304a84b6a030466b4b4850382e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 11 Oct 2016 21:15:04 +1100 Subject: [PATCH 0441/1167] powerpc/mm/hash64: Fix might_have_hea() check In commit 2b4e3ad8f579 ("powerpc/mm/hash64: Don't test for machine type to detect HEA special case") we changed the logic in might_have_hea() to check FW_FEATURE_SPLPAR rather than machine_is(pseries). However the check was incorrectly negated, leading to crashes on machines with HEA adapters, such as: mm: Hashing failure ! EA=0xd000080080004040 access=0x800000000000000e current=NetworkManager trap=0x300 vsid=0x13d349c ssize=1 base psize=2 psize 2 pte=0xc0003cc033e701ae Unable to handle kernel paging request for data at address 0xd000080080004040 Call Trace: .ehea_create_cq+0x148/0x340 [ehea] (unreliable) .ehea_up+0x258/0x1200 [ehea] .ehea_open+0x44/0x1a0 [ehea] ... Fix it by removing the negation. Fixes: 2b4e3ad8f579 ("powerpc/mm/hash64: Don't test for machine type to detect HEA special case") Cc: stable@vger.kernel.org # v4.8+ Reported-by: Denis Kirjanov Reported-by: Jan Stancek Signed-off-by: Michael Ellerman --- arch/powerpc/mm/hash_utils_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 4cebc31e53de9..4e83d872872d9 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -526,7 +526,7 @@ static bool might_have_hea(void) */ #ifdef CONFIG_IBMEBUS return !cpu_has_feature(CPU_FTR_ARCH_207S) && - !firmware_has_feature(FW_FEATURE_SPLPAR); + firmware_has_feature(FW_FEATURE_SPLPAR); #else return false; #endif -- GitLab From 0ba43a81ef7b78ddf404f7709a2257be59436411 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Fri, 7 Oct 2016 18:19:57 +0200 Subject: [PATCH 0442/1167] scsi: Replace wrong device handler name for CLARiiON arrays At drivers/scsi/device_handler/scsi_dh_emc.c it was defined as: Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Christophe Varoqui Cc: James E.J. Bottomley Cc: Martin K. Petersen Cc: SCSI ML Cc: device-mapper development Signed-off-by: Xose Vazquez Perez Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_dh.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 54d446c9f56e0..b8d3b97b217ac 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -36,9 +36,9 @@ struct scsi_dh_blist { }; static const struct scsi_dh_blist scsi_dh_blist[] = { - {"DGC", "RAID", "clariion" }, - {"DGC", "DISK", "clariion" }, - {"DGC", "VRAID", "clariion" }, + {"DGC", "RAID", "emc" }, + {"DGC", "DISK", "emc" }, + {"DGC", "VRAID", "emc" }, {"COMPAQ", "MSA1000 VOLUME", "hp_sw" }, {"COMPAQ", "HSV110", "hp_sw" }, -- GitLab From bcd8f2e94808fcddf6ef3af5f060a36820dcc432 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sun, 9 Oct 2016 13:23:27 +0800 Subject: [PATCH 0443/1167] scsi: Fix use-after-free This patch fixes one use-after-free report[1] by KASAN. In __scsi_scan_target(), when a type 31 device is probed, SCSI_SCAN_TARGET_PRESENT is returned and the target will be scanned again. Inside the following scsi_report_lun_scan(), one new scsi_device instance is allocated, and scsi_probe_and_add_lun() is called again to probe the target and still see type 31 device, finally __scsi_remove_device() is called to remove & free the device at the end of scsi_probe_and_add_lun(), so cause use-after-free in scsi_report_lun_scan(). And the following SCSI log can be observed: scsi 0:0:2:0: scsi scan: INQUIRY pass 1 length 36 scsi 0:0:2:0: scsi scan: INQUIRY successful with code 0x0 scsi 0:0:2:0: scsi scan: peripheral device type of 31, no device added scsi 0:0:2:0: scsi scan: Sending REPORT LUNS to (try 0) scsi 0:0:2:0: scsi scan: REPORT LUNS successful (try 0) result 0x0 scsi 0:0:2:0: scsi scan: REPORT LUN scan scsi 0:0:2:0: scsi scan: INQUIRY pass 1 length 36 scsi 0:0:2:0: scsi scan: INQUIRY successful with code 0x0 scsi 0:0:2:0: scsi scan: peripheral device type of 31, no device added BUG: KASAN: use-after-free in __scsi_scan_target+0xbf8/0xe40 at addr ffff88007b44a104 This patch fixes the issue by moving the putting reference at the end of scsi_report_lun_scan(). [1] KASAN report ================================================================== [ 3.274597] PM: Adding info for serio:serio1 [ 3.275127] BUG: KASAN: use-after-free in __scsi_scan_target+0xd87/0xdf0 at addr ffff880254d8c304 [ 3.275653] Read of size 4 by task kworker/u10:0/27 [ 3.275903] CPU: 3 PID: 27 Comm: kworker/u10:0 Not tainted 4.8.0 #2121 [ 3.276258] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 [ 3.276797] Workqueue: events_unbound async_run_entry_fn [ 3.277083] ffff880254d8c380 ffff880259a37870 ffffffff94bbc6c1 ffff880078402d80 [ 3.277532] ffff880254d8bb80 ffff880259a37898 ffffffff9459fec1 ffff880259a37930 [ 3.277989] ffff880254d8bb80 ffff880078402d80 ffff880259a37920 ffffffff945a0165 [ 3.278436] Call Trace: [ 3.278528] [] dump_stack+0x65/0x84 [ 3.278797] [] kasan_object_err+0x21/0x70 [ 3.279063] device: 'psaux': device_add [ 3.279616] [] kasan_report_error+0x205/0x500 [ 3.279651] PM: Adding info for No Bus:psaux [ 3.280202] [] ? kfree_const+0x22/0x30 [ 3.280486] [] ? kobject_release+0x119/0x370 [ 3.280805] [] __asan_report_load4_noabort+0x43/0x50 [ 3.281170] [] ? __scsi_scan_target+0xd87/0xdf0 [ 3.281506] [] __scsi_scan_target+0xd87/0xdf0 [ 3.281848] [] ? scsi_add_device+0x30/0x30 [ 3.282156] [] ? pm_runtime_autosuspend_expiration+0x60/0x60 [ 3.282570] [] ? _raw_spin_lock+0x17/0x40 [ 3.282880] [] scsi_scan_channel+0x105/0x160 [ 3.283200] [] scsi_scan_host_selected+0x212/0x2f0 [ 3.283563] [] do_scsi_scan_host+0x1bc/0x250 [ 3.283882] [] do_scan_async+0x41/0x450 [ 3.284173] [] async_run_entry_fn+0xfe/0x610 [ 3.284492] [] ? pwq_dec_nr_in_flight+0x124/0x2a0 [ 3.284876] [] ? preempt_count_add+0x130/0x160 [ 3.285207] [] process_one_work+0x544/0x12d0 [ 3.285526] [] worker_thread+0xd9/0x12f0 [ 3.285844] [] ? process_one_work+0x12d0/0x12d0 [ 3.286182] [] kthread+0x1c5/0x260 [ 3.286443] [] ? __switch_to+0x88d/0x1430 [ 3.286745] [] ? kthread_worker_fn+0x5a0/0x5a0 [ 3.287085] [] ret_from_fork+0x1f/0x40 [ 3.287368] [] ? kthread_worker_fn+0x5a0/0x5a0 [ 3.287697] Object at ffff880254d8bb80, in cache kmalloc-2048 size: 2048 [ 3.288064] Allocated: [ 3.288147] PID = 27 [ 3.288218] [] save_stack_trace+0x2b/0x50 [ 3.288531] [] save_stack+0x46/0xd0 [ 3.288806] [] kasan_kmalloc+0xad/0xe0 [ 3.289098] [] __kmalloc+0x13e/0x250 [ 3.289378] [] scsi_alloc_sdev+0xea/0xcf0 [ 3.289701] [] __scsi_scan_target+0xa06/0xdf0 [ 3.290034] [] scsi_scan_channel+0x105/0x160 [ 3.290362] [] scsi_scan_host_selected+0x212/0x2f0 [ 3.290724] [] do_scsi_scan_host+0x1bc/0x250 [ 3.291055] [] do_scan_async+0x41/0x450 [ 3.291354] [] async_run_entry_fn+0xfe/0x610 [ 3.291695] [] process_one_work+0x544/0x12d0 [ 3.292022] [] worker_thread+0xd9/0x12f0 [ 3.292325] [] kthread+0x1c5/0x260 [ 3.292594] [] ret_from_fork+0x1f/0x40 [ 3.292886] Freed: [ 3.292945] PID = 27 [ 3.293016] [] save_stack_trace+0x2b/0x50 [ 3.293327] [] save_stack+0x46/0xd0 [ 3.293600] [] kasan_slab_free+0x71/0xb0 [ 3.293916] [] kfree+0xa2/0x1f0 [ 3.294168] [] scsi_device_dev_release_usercontext+0x50a/0x730 [ 3.294598] [] execute_in_process_context+0xda/0x130 [ 3.294974] [] scsi_device_dev_release+0x1c/0x20 [ 3.295322] [] device_release+0x76/0x1e0 [ 3.295626] [] kobject_release+0x107/0x370 [ 3.295942] [] kobject_put+0x4e/0xa0 [ 3.296222] [] put_device+0x17/0x20 [ 3.296497] [] scsi_device_put+0x7c/0xa0 [ 3.296801] [] __scsi_scan_target+0xd4c/0xdf0 [ 3.297132] [] scsi_scan_channel+0x105/0x160 [ 3.297458] [] scsi_scan_host_selected+0x212/0x2f0 [ 3.297829] [] do_scsi_scan_host+0x1bc/0x250 [ 3.298156] [] do_scan_async+0x41/0x450 [ 3.298453] [] async_run_entry_fn+0xfe/0x610 [ 3.298777] [] process_one_work+0x544/0x12d0 [ 3.299105] [] worker_thread+0xd9/0x12f0 [ 3.299408] [] kthread+0x1c5/0x260 [ 3.299676] [] ret_from_fork+0x1f/0x40 [ 3.299967] Memory state around the buggy address: [ 3.300209] ffff880254d8c200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 3.300608] ffff880254d8c280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 3.300986] >ffff880254d8c300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 3.301408] ^ [ 3.301550] ffff880254d8c380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 3.301987] ffff880254d8c400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 3.302396] ================================================================== Cc: Christoph Hellwig Cc: stable@vger.kernel.org Signed-off-by: Ming Lei Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 212e98d940bc2..bb9b58e21d950 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1470,12 +1470,12 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, out_err: kfree(lun_data); out: - scsi_device_put(sdev); if (scsi_device_created(sdev)) /* * the sdev we used didn't appear in the report luns scan */ __scsi_remove_device(sdev); + scsi_device_put(sdev); return ret; } -- GitLab From 03eb6b8d314e89e94d4f79ee3d3e6596a75bc857 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 10 Oct 2016 23:25:33 +0800 Subject: [PATCH 0444/1167] scsi: Remove one useless stack variable The local variable of 'devname' in scsi_report_lun_scan() isn't used any more, so remove it. Cc: Christoph Hellwig Signed-off-by: Ming Lei Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index bb9b58e21d950..6f7128f49c30d 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1307,7 +1307,6 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget, static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, enum scsi_scan_mode rescan) { - char devname[64]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; unsigned int length; u64 lun; @@ -1349,9 +1348,6 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, } } - sprintf(devname, "host %d channel %d id %d", - shost->host_no, sdev->channel, sdev->id); - /* * Allocate enough to hold the header (the same size as one scsi_lun) * plus the number of luns we are requesting. 511 was the default -- GitLab From 819bf593767c0966f320c51c6ed3f3835062abc8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 Oct 2016 14:56:53 +0200 Subject: [PATCH 0445/1167] docs-rst: sphinxify 802.11 documentation This is just a very basic conversion, I've split up the original multi-book template, and also split up the multi-part mac80211 part in the original book; neither of those were handled by the automatic pandoc conversion. Fix errors that showed up, resulting in a much nicer rendering, at least for the interface combinations documentation. Signed-off-by: Johannes Berg Signed-off-by: Jonathan Corbet --- Documentation/80211/cfg80211.rst | 345 +++++++++++++ Documentation/80211/conf.py | 5 + Documentation/80211/index.rst | 17 + Documentation/80211/introduction.rst | 17 + Documentation/80211/mac80211-advanced.rst | 295 +++++++++++ Documentation/80211/mac80211.rst | 216 ++++++++ Documentation/DocBook/80211.tmpl | 584 ---------------------- Documentation/DocBook/Makefile | 2 +- Documentation/index.rst | 1 + include/net/cfg80211.h | 77 +-- 10 files changed, 939 insertions(+), 620 deletions(-) create mode 100644 Documentation/80211/cfg80211.rst create mode 100644 Documentation/80211/conf.py create mode 100644 Documentation/80211/index.rst create mode 100644 Documentation/80211/introduction.rst create mode 100644 Documentation/80211/mac80211-advanced.rst create mode 100644 Documentation/80211/mac80211.rst delete mode 100644 Documentation/DocBook/80211.tmpl diff --git a/Documentation/80211/cfg80211.rst b/Documentation/80211/cfg80211.rst new file mode 100644 index 0000000000000..b1e149ea6feeb --- /dev/null +++ b/Documentation/80211/cfg80211.rst @@ -0,0 +1,345 @@ +================== +cfg80211 subsystem +================== + +Device registration +=================== + +.. kernel-doc:: include/net/cfg80211.h + :doc: Device registration + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_channel_flags + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_channel + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_rate_flags + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_rate + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_sta_ht_cap + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_supported_band + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_signal_type + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_params_flags + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_flags + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy + +.. kernel-doc:: include/net/cfg80211.h + :functions: wireless_dev + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_new + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_register + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_unregister + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_free + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_name + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_dev + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_priv + +.. kernel-doc:: include/net/cfg80211.h + :functions: priv_to_wiphy + +.. kernel-doc:: include/net/cfg80211.h + :functions: set_wiphy_dev + +.. kernel-doc:: include/net/cfg80211.h + :functions: wdev_priv + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_iface_limit + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_iface_combination + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_check_combinations + +Actions and configuration +========================= + +.. kernel-doc:: include/net/cfg80211.h + :doc: Actions and configuration + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_ops + +.. kernel-doc:: include/net/cfg80211.h + :functions: vif_params + +.. kernel-doc:: include/net/cfg80211.h + :functions: key_params + +.. kernel-doc:: include/net/cfg80211.h + :functions: survey_info_flags + +.. kernel-doc:: include/net/cfg80211.h + :functions: survey_info + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_beacon_data + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_ap_settings + +.. kernel-doc:: include/net/cfg80211.h + :functions: station_parameters + +.. kernel-doc:: include/net/cfg80211.h + :functions: rate_info_flags + +.. kernel-doc:: include/net/cfg80211.h + :functions: rate_info + +.. kernel-doc:: include/net/cfg80211.h + :functions: station_info + +.. kernel-doc:: include/net/cfg80211.h + :functions: monitor_flags + +.. kernel-doc:: include/net/cfg80211.h + :functions: mpath_info_flags + +.. kernel-doc:: include/net/cfg80211.h + :functions: mpath_info + +.. kernel-doc:: include/net/cfg80211.h + :functions: bss_parameters + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_txq_params + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_crypto_settings + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_auth_request + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_assoc_request + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_deauth_request + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_disassoc_request + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_ibss_params + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_connect_params + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_pmksa + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_rx_mlme_mgmt + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_auth_timeout + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_rx_assoc_resp + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_assoc_timeout + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_tx_mlme_mgmt + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_ibss_joined + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_connect_result + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_connect_bss + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_connect_timeout + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_roamed + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_disconnected + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_ready_on_channel + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_remain_on_channel_expired + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_new_sta + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_rx_mgmt + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_mgmt_tx_status + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_cqm_rssi_notify + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_cqm_pktloss_notify + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_michael_mic_failure + +Scanning and BSS list handling +============================== + +.. kernel-doc:: include/net/cfg80211.h + :doc: Scanning and BSS list handling + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_ssid + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_scan_request + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_scan_done + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_bss + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_inform_bss + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_inform_bss_frame_data + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_inform_bss_data + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_unlink_bss + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_find_ie + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_bss_get_ie + +Utility functions +================= + +.. kernel-doc:: include/net/cfg80211.h + :doc: Utility functions + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_channel_to_frequency + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_frequency_to_channel + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_get_channel + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_get_response_rate + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_hdrlen + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_get_hdrlen_from_skb + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_radiotap_iterator + +Data path helpers +================= + +.. kernel-doc:: include/net/cfg80211.h + :doc: Data path helpers + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_data_to_8023 + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_data_from_8023 + +.. kernel-doc:: include/net/cfg80211.h + :functions: ieee80211_amsdu_to_8023s + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_classify8021d + +Regulatory enforcement infrastructure +===================================== + +.. kernel-doc:: include/net/cfg80211.h + :doc: Regulatory enforcement infrastructure + +.. kernel-doc:: include/net/cfg80211.h + :functions: regulatory_hint + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_apply_custom_regulatory + +.. kernel-doc:: include/net/cfg80211.h + :functions: freq_reg_info + +RFkill integration +================== + +.. kernel-doc:: include/net/cfg80211.h + :doc: RFkill integration + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_rfkill_set_hw_state + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_rfkill_start_polling + +.. kernel-doc:: include/net/cfg80211.h + :functions: wiphy_rfkill_stop_polling + +Test mode +========= + +.. kernel-doc:: include/net/cfg80211.h + :doc: Test mode + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_testmode_alloc_reply_skb + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_testmode_reply + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_testmode_alloc_event_skb + +.. kernel-doc:: include/net/cfg80211.h + :functions: cfg80211_testmode_event diff --git a/Documentation/80211/conf.py b/Documentation/80211/conf.py new file mode 100644 index 0000000000000..20c7c275ef4a9 --- /dev/null +++ b/Documentation/80211/conf.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8; mode: python -*- + +project = "Linux 802.11 Driver Developer's Guide" + +tags.add("subproject") diff --git a/Documentation/80211/index.rst b/Documentation/80211/index.rst new file mode 100644 index 0000000000000..90bba476f4429 --- /dev/null +++ b/Documentation/80211/index.rst @@ -0,0 +1,17 @@ +===================================== +Linux 802.11 Driver Developer's Guide +===================================== + +.. toctree:: + + introduction + cfg80211 + mac80211 + mac80211-advanced + +.. only:: subproject + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/80211/introduction.rst b/Documentation/80211/introduction.rst new file mode 100644 index 0000000000000..4938fa87691cb --- /dev/null +++ b/Documentation/80211/introduction.rst @@ -0,0 +1,17 @@ +============ +Introduction +============ + +Explaining wireless 802.11 networking in the Linux kernel + +Copyright 2007-2009 Johannes Berg + +These books attempt to give a description of the various subsystems +that play a role in 802.11 wireless networking in Linux. Since these +books are for kernel developers they attempts to document the +structures and functions used in the kernel as well as giving a +higher-level overview. + +The reader is expected to be familiar with the 802.11 standard as +published by the IEEE in 802.11-2007 (or possibly later versions). +References to this standard will be given as "802.11-2007 8.1.5". diff --git a/Documentation/80211/mac80211-advanced.rst b/Documentation/80211/mac80211-advanced.rst new file mode 100644 index 0000000000000..70a89b2163c22 --- /dev/null +++ b/Documentation/80211/mac80211-advanced.rst @@ -0,0 +1,295 @@ +============================= +mac80211 subsystem (advanced) +============================= + +Information contained within this part of the book is of interest only +for advanced interaction of mac80211 with drivers to exploit more +hardware capabilities and improve performance. + +LED support +=========== + +Mac80211 supports various ways of blinking LEDs. Wherever possible, +device LEDs should be exposed as LED class devices and hooked up to the +appropriate trigger, which will then be triggered appropriately by +mac80211. + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_get_tx_led_name + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_get_rx_led_name + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_get_assoc_led_name + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_get_radio_led_name + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_tpt_blink + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_tpt_led_trigger_flags + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_create_tpt_led_trigger + +Hardware crypto acceleration +============================ + +.. kernel-doc:: include/net/mac80211.h + :doc: Hardware crypto acceleration + +.. kernel-doc:: include/net/mac80211.h + :functions: set_key_cmd + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_key_conf + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_key_flags + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_get_tkip_p1k + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_get_tkip_p1k_iv + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_get_tkip_p2k + +Powersave support +================= + +.. kernel-doc:: include/net/mac80211.h + :doc: Powersave support + +Beacon filter support +===================== + +.. kernel-doc:: include/net/mac80211.h + :doc: Beacon filter support + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_beacon_loss + +Multiple queues and QoS support +=============================== + +TBD + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_tx_queue_params + +Access point mode support +========================= + +TBD + +Some parts of the if_conf should be discussed here instead + +Insert notes about VLAN interfaces with hw crypto here or in the hw +crypto chapter. + +support for powersaving clients +------------------------------- + +.. kernel-doc:: include/net/mac80211.h + :doc: AP support for powersaving clients + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_get_buffered_bc + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_beacon_get + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_sta_eosp + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_frame_release_type + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_sta_ps_transition + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_sta_ps_transition_ni + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_sta_set_buffered + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_sta_block_awake + +Supporting multiple virtual interfaces +====================================== + +TBD + +Note: WDS with identical MAC address should almost always be OK + +Insert notes about having multiple virtual interfaces with different MAC +addresses here, note which configurations are supported by mac80211, add +notes about supporting hw crypto with it. + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_iterate_active_interfaces + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_iterate_active_interfaces_atomic + +Station handling +================ + +TODO + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_sta + +.. kernel-doc:: include/net/mac80211.h + :functions: sta_notify_cmd + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_find_sta + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_find_sta_by_ifaddr + +Hardware scan offload +===================== + +TBD + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_scan_completed + +Aggregation +=========== + +TX A-MPDU aggregation +--------------------- + +.. kernel-doc:: net/mac80211/agg-tx.c + :doc: TX A-MPDU aggregation + +.. WARNING: DOCPROC directive not supported: !Cnet/mac80211/agg-tx.c + +RX A-MPDU aggregation +--------------------- + +.. kernel-doc:: net/mac80211/agg-rx.c + :doc: RX A-MPDU aggregation + +.. WARNING: DOCPROC directive not supported: !Cnet/mac80211/agg-rx.c + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_ampdu_mlme_action + +Spatial Multiplexing Powersave (SMPS) +===================================== + +.. kernel-doc:: include/net/mac80211.h + :doc: Spatial multiplexing power save + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_request_smps + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_smps_mode + +TBD + +This part of the book describes the rate control algorithm interface and +how it relates to mac80211 and drivers. + +Rate Control API +================ + +TBD + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_start_tx_ba_session + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_start_tx_ba_cb_irqsafe + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_stop_tx_ba_session + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_stop_tx_ba_cb_irqsafe + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_rate_control_changed + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_tx_rate_control + +.. kernel-doc:: include/net/mac80211.h + :functions: rate_control_send_low + +TBD + +This part of the book describes mac80211 internals. + +Key handling +============ + +Key handling basics +------------------- + +.. kernel-doc:: net/mac80211/key.c + :doc: Key handling basics + +MORE TBD +-------- + +TBD + +Receive processing +================== + +TBD + +Transmit processing +=================== + +TBD + +Station info handling +===================== + +Programming information +----------------------- + +.. kernel-doc:: net/mac80211/sta_info.h + :functions: sta_info + +.. kernel-doc:: net/mac80211/sta_info.h + :functions: ieee80211_sta_info_flags + +STA information lifetime rules +------------------------------ + +.. kernel-doc:: net/mac80211/sta_info.c + :doc: STA information lifetime rules + +Aggregation +=========== + +.. kernel-doc:: net/mac80211/sta_info.h + :functions: sta_ampdu_mlme + +.. kernel-doc:: net/mac80211/sta_info.h + :functions: tid_ampdu_tx + +.. kernel-doc:: net/mac80211/sta_info.h + :functions: tid_ampdu_rx + +Synchronisation +=============== + +TBD + +Locking, lots of RCU diff --git a/Documentation/80211/mac80211.rst b/Documentation/80211/mac80211.rst new file mode 100644 index 0000000000000..85a8335e80b6c --- /dev/null +++ b/Documentation/80211/mac80211.rst @@ -0,0 +1,216 @@ +=========================== +mac80211 subsystem (basics) +=========================== + +You should read and understand the information contained within this +part of the book while implementing a mac80211 driver. In some chapters, +advanced usage is noted, those may be skipped if this isn't needed. + +This part of the book only covers station and monitor mode +functionality, additional information required to implement the other +modes is covered in the second part of the book. + +Basic hardware handling +======================= + +TBD + +This chapter shall contain information on getting a hw struct allocated +and registered with mac80211. + +Since it is required to allocate rates/modes before registering a hw +struct, this chapter shall also contain information on setting up the +rate/mode structs. + +Additionally, some discussion about the callbacks and the general +programming model should be in here, including the definition of +ieee80211_ops which will be referred to a lot. + +Finally, a discussion of hardware capabilities should be done with +references to other parts of the book. + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_hw + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_hw_flags + +.. kernel-doc:: include/net/mac80211.h + :functions: SET_IEEE80211_DEV + +.. kernel-doc:: include/net/mac80211.h + :functions: SET_IEEE80211_PERM_ADDR + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_ops + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_alloc_hw + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_register_hw + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_unregister_hw + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_free_hw + +PHY configuration +================= + +TBD + +This chapter should describe PHY handling including start/stop callbacks +and the various structures used. + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_conf + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_conf_flags + +Virtual interfaces +================== + +TBD + +This chapter should describe virtual interface basics that are relevant +to the driver (VLANs, MGMT etc are not.) It should explain the use of +the add_iface/remove_iface callbacks as well as the interface +configuration callbacks. + +Things related to AP mode should be discussed there. + +Things related to supporting multiple interfaces should be in the +appropriate chapter, a BIG FAT note should be here about this though and +the recommendation to allow only a single interface in STA mode at +first! + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_vif + +Receive and transmit processing +=============================== + +what should be here +------------------- + +TBD + +This should describe the receive and transmit paths in mac80211/the +drivers as well as transmit status handling. + +Frame format +------------ + +.. kernel-doc:: include/net/mac80211.h + :doc: Frame format + +Packet alignment +---------------- + +.. kernel-doc:: net/mac80211/rx.c + :doc: Packet alignment + +Calling into mac80211 from interrupts +------------------------------------- + +.. kernel-doc:: include/net/mac80211.h + :doc: Calling mac80211 from interrupts + +functions/definitions +--------------------- + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_rx_status + +.. kernel-doc:: include/net/mac80211.h + :functions: mac80211_rx_flags + +.. kernel-doc:: include/net/mac80211.h + :functions: mac80211_tx_info_flags + +.. kernel-doc:: include/net/mac80211.h + :functions: mac80211_tx_control_flags + +.. kernel-doc:: include/net/mac80211.h + :functions: mac80211_rate_control_flags + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_tx_rate + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_tx_info + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_tx_info_clear_status + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_rx + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_rx_ni + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_rx_irqsafe + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_tx_status + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_tx_status_ni + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_tx_status_irqsafe + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_rts_get + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_rts_duration + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_ctstoself_get + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_ctstoself_duration + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_generic_frame_duration + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_wake_queue + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_stop_queue + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_wake_queues + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_stop_queues + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_queue_stopped + +Frame filtering +=============== + +.. kernel-doc:: include/net/mac80211.h + :doc: Frame filtering + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_filter_flags + +The mac80211 workqueue +====================== + +.. kernel-doc:: include/net/mac80211.h + :doc: mac80211 workqueue + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_queue_work + +.. kernel-doc:: include/net/mac80211.h + :functions: ieee80211_queue_delayed_work diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl deleted file mode 100644 index 800fe7a9024c1..0000000000000 --- a/Documentation/DocBook/80211.tmpl +++ /dev/null @@ -1,584 +0,0 @@ - - - - - The 802.11 subsystems – for kernel developers - - Explaining wireless 802.11 networking in the Linux kernel - - - - 2007-2009 - Johannes Berg - - - - - Johannes - Berg - -
johannes@sipsolutions.net
-
-
-
- - - - This documentation is free software; you can redistribute - it and/or modify it under the terms of the GNU General Public - License version 2 as published by the Free Software Foundation. - - - This documentation 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 documentation; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, - MA 02111-1307 USA - - - For more details see the file COPYING in the source - distribution of Linux. - - - - - - These books attempt to give a description of the - various subsystems that play a role in 802.11 wireless - networking in Linux. Since these books are for kernel - developers they attempts to document the structures - and functions used in the kernel as well as giving a - higher-level overview. - - - The reader is expected to be familiar with the 802.11 - standard as published by the IEEE in 802.11-2007 (or - possibly later versions). References to this standard - will be given as "802.11-2007 8.1.5". - - -
- - - The cfg80211 subsystem - - -!Pinclude/net/cfg80211.h Introduction - - - - Device registration -!Pinclude/net/cfg80211.h Device registration -!Finclude/net/cfg80211.h ieee80211_channel_flags -!Finclude/net/cfg80211.h ieee80211_channel -!Finclude/net/cfg80211.h ieee80211_rate_flags -!Finclude/net/cfg80211.h ieee80211_rate -!Finclude/net/cfg80211.h ieee80211_sta_ht_cap -!Finclude/net/cfg80211.h ieee80211_supported_band -!Finclude/net/cfg80211.h cfg80211_signal_type -!Finclude/net/cfg80211.h wiphy_params_flags -!Finclude/net/cfg80211.h wiphy_flags -!Finclude/net/cfg80211.h wiphy -!Finclude/net/cfg80211.h wireless_dev -!Finclude/net/cfg80211.h wiphy_new -!Finclude/net/cfg80211.h wiphy_register -!Finclude/net/cfg80211.h wiphy_unregister -!Finclude/net/cfg80211.h wiphy_free - -!Finclude/net/cfg80211.h wiphy_name -!Finclude/net/cfg80211.h wiphy_dev -!Finclude/net/cfg80211.h wiphy_priv -!Finclude/net/cfg80211.h priv_to_wiphy -!Finclude/net/cfg80211.h set_wiphy_dev -!Finclude/net/cfg80211.h wdev_priv -!Finclude/net/cfg80211.h ieee80211_iface_limit -!Finclude/net/cfg80211.h ieee80211_iface_combination -!Finclude/net/cfg80211.h cfg80211_check_combinations - - - Actions and configuration -!Pinclude/net/cfg80211.h Actions and configuration -!Finclude/net/cfg80211.h cfg80211_ops -!Finclude/net/cfg80211.h vif_params -!Finclude/net/cfg80211.h key_params -!Finclude/net/cfg80211.h survey_info_flags -!Finclude/net/cfg80211.h survey_info -!Finclude/net/cfg80211.h cfg80211_beacon_data -!Finclude/net/cfg80211.h cfg80211_ap_settings -!Finclude/net/cfg80211.h station_parameters -!Finclude/net/cfg80211.h rate_info_flags -!Finclude/net/cfg80211.h rate_info -!Finclude/net/cfg80211.h station_info -!Finclude/net/cfg80211.h monitor_flags -!Finclude/net/cfg80211.h mpath_info_flags -!Finclude/net/cfg80211.h mpath_info -!Finclude/net/cfg80211.h bss_parameters -!Finclude/net/cfg80211.h ieee80211_txq_params -!Finclude/net/cfg80211.h cfg80211_crypto_settings -!Finclude/net/cfg80211.h cfg80211_auth_request -!Finclude/net/cfg80211.h cfg80211_assoc_request -!Finclude/net/cfg80211.h cfg80211_deauth_request -!Finclude/net/cfg80211.h cfg80211_disassoc_request -!Finclude/net/cfg80211.h cfg80211_ibss_params -!Finclude/net/cfg80211.h cfg80211_connect_params -!Finclude/net/cfg80211.h cfg80211_pmksa -!Finclude/net/cfg80211.h cfg80211_rx_mlme_mgmt -!Finclude/net/cfg80211.h cfg80211_auth_timeout -!Finclude/net/cfg80211.h cfg80211_rx_assoc_resp -!Finclude/net/cfg80211.h cfg80211_assoc_timeout -!Finclude/net/cfg80211.h cfg80211_tx_mlme_mgmt -!Finclude/net/cfg80211.h cfg80211_ibss_joined -!Finclude/net/cfg80211.h cfg80211_connect_result -!Finclude/net/cfg80211.h cfg80211_connect_bss -!Finclude/net/cfg80211.h cfg80211_connect_timeout -!Finclude/net/cfg80211.h cfg80211_roamed -!Finclude/net/cfg80211.h cfg80211_disconnected -!Finclude/net/cfg80211.h cfg80211_ready_on_channel -!Finclude/net/cfg80211.h cfg80211_remain_on_channel_expired -!Finclude/net/cfg80211.h cfg80211_new_sta -!Finclude/net/cfg80211.h cfg80211_rx_mgmt -!Finclude/net/cfg80211.h cfg80211_mgmt_tx_status -!Finclude/net/cfg80211.h cfg80211_cqm_rssi_notify -!Finclude/net/cfg80211.h cfg80211_cqm_pktloss_notify -!Finclude/net/cfg80211.h cfg80211_michael_mic_failure - - - Scanning and BSS list handling -!Pinclude/net/cfg80211.h Scanning and BSS list handling -!Finclude/net/cfg80211.h cfg80211_ssid -!Finclude/net/cfg80211.h cfg80211_scan_request -!Finclude/net/cfg80211.h cfg80211_scan_done -!Finclude/net/cfg80211.h cfg80211_bss -!Finclude/net/cfg80211.h cfg80211_inform_bss -!Finclude/net/cfg80211.h cfg80211_inform_bss_frame_data -!Finclude/net/cfg80211.h cfg80211_inform_bss_data -!Finclude/net/cfg80211.h cfg80211_unlink_bss -!Finclude/net/cfg80211.h cfg80211_find_ie -!Finclude/net/cfg80211.h ieee80211_bss_get_ie - - - Utility functions -!Pinclude/net/cfg80211.h Utility functions -!Finclude/net/cfg80211.h ieee80211_channel_to_frequency -!Finclude/net/cfg80211.h ieee80211_frequency_to_channel -!Finclude/net/cfg80211.h ieee80211_get_channel -!Finclude/net/cfg80211.h ieee80211_get_response_rate -!Finclude/net/cfg80211.h ieee80211_hdrlen -!Finclude/net/cfg80211.h ieee80211_get_hdrlen_from_skb -!Finclude/net/cfg80211.h ieee80211_radiotap_iterator - - - Data path helpers -!Pinclude/net/cfg80211.h Data path helpers -!Finclude/net/cfg80211.h ieee80211_data_to_8023 -!Finclude/net/cfg80211.h ieee80211_data_from_8023 -!Finclude/net/cfg80211.h ieee80211_amsdu_to_8023s -!Finclude/net/cfg80211.h cfg80211_classify8021d - - - Regulatory enforcement infrastructure -!Pinclude/net/cfg80211.h Regulatory enforcement infrastructure -!Finclude/net/cfg80211.h regulatory_hint -!Finclude/net/cfg80211.h wiphy_apply_custom_regulatory -!Finclude/net/cfg80211.h freq_reg_info - - - RFkill integration -!Pinclude/net/cfg80211.h RFkill integration -!Finclude/net/cfg80211.h wiphy_rfkill_set_hw_state -!Finclude/net/cfg80211.h wiphy_rfkill_start_polling -!Finclude/net/cfg80211.h wiphy_rfkill_stop_polling - - - Test mode -!Pinclude/net/cfg80211.h Test mode -!Finclude/net/cfg80211.h cfg80211_testmode_alloc_reply_skb -!Finclude/net/cfg80211.h cfg80211_testmode_reply -!Finclude/net/cfg80211.h cfg80211_testmode_alloc_event_skb -!Finclude/net/cfg80211.h cfg80211_testmode_event - - - - - The mac80211 subsystem - -!Pinclude/net/mac80211.h Introduction -!Pinclude/net/mac80211.h Warning - - - - - - - - - The basic mac80211 driver interface - - - You should read and understand the information contained - within this part of the book while implementing a driver. - In some chapters, advanced usage is noted, that may be - skipped at first. - - - This part of the book only covers station and monitor mode - functionality, additional information required to implement - the other modes is covered in the second part of the book. - - - - - Basic hardware handling - TBD - - This chapter shall contain information on getting a hw - struct allocated and registered with mac80211. - - - Since it is required to allocate rates/modes before registering - a hw struct, this chapter shall also contain information on setting - up the rate/mode structs. - - - Additionally, some discussion about the callbacks and - the general programming model should be in here, including - the definition of ieee80211_ops which will be referred to - a lot. - - - Finally, a discussion of hardware capabilities should be done - with references to other parts of the book. - - -!Finclude/net/mac80211.h ieee80211_hw -!Finclude/net/mac80211.h ieee80211_hw_flags -!Finclude/net/mac80211.h SET_IEEE80211_DEV -!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR -!Finclude/net/mac80211.h ieee80211_ops -!Finclude/net/mac80211.h ieee80211_alloc_hw -!Finclude/net/mac80211.h ieee80211_register_hw -!Finclude/net/mac80211.h ieee80211_unregister_hw -!Finclude/net/mac80211.h ieee80211_free_hw - - - - PHY configuration - TBD - - This chapter should describe PHY handling including - start/stop callbacks and the various structures used. - -!Finclude/net/mac80211.h ieee80211_conf -!Finclude/net/mac80211.h ieee80211_conf_flags - - - - Virtual interfaces - TBD - - This chapter should describe virtual interface basics - that are relevant to the driver (VLANs, MGMT etc are not.) - It should explain the use of the add_iface/remove_iface - callbacks as well as the interface configuration callbacks. - - Things related to AP mode should be discussed there. - - Things related to supporting multiple interfaces should be - in the appropriate chapter, a BIG FAT note should be here about - this though and the recommendation to allow only a single - interface in STA mode at first! - -!Finclude/net/mac80211.h ieee80211_vif - - - - Receive and transmit processing - - what should be here - TBD - - This should describe the receive and transmit - paths in mac80211/the drivers as well as - transmit status handling. - - - - Frame format -!Pinclude/net/mac80211.h Frame format - - - Packet alignment -!Pnet/mac80211/rx.c Packet alignment - - - Calling into mac80211 from interrupts -!Pinclude/net/mac80211.h Calling mac80211 from interrupts - - - functions/definitions -!Finclude/net/mac80211.h ieee80211_rx_status -!Finclude/net/mac80211.h mac80211_rx_flags -!Finclude/net/mac80211.h mac80211_tx_info_flags -!Finclude/net/mac80211.h mac80211_tx_control_flags -!Finclude/net/mac80211.h mac80211_rate_control_flags -!Finclude/net/mac80211.h ieee80211_tx_rate -!Finclude/net/mac80211.h ieee80211_tx_info -!Finclude/net/mac80211.h ieee80211_tx_info_clear_status -!Finclude/net/mac80211.h ieee80211_rx -!Finclude/net/mac80211.h ieee80211_rx_ni -!Finclude/net/mac80211.h ieee80211_rx_irqsafe -!Finclude/net/mac80211.h ieee80211_tx_status -!Finclude/net/mac80211.h ieee80211_tx_status_ni -!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe -!Finclude/net/mac80211.h ieee80211_rts_get -!Finclude/net/mac80211.h ieee80211_rts_duration -!Finclude/net/mac80211.h ieee80211_ctstoself_get -!Finclude/net/mac80211.h ieee80211_ctstoself_duration -!Finclude/net/mac80211.h ieee80211_generic_frame_duration -!Finclude/net/mac80211.h ieee80211_wake_queue -!Finclude/net/mac80211.h ieee80211_stop_queue -!Finclude/net/mac80211.h ieee80211_wake_queues -!Finclude/net/mac80211.h ieee80211_stop_queues -!Finclude/net/mac80211.h ieee80211_queue_stopped - - - - - Frame filtering -!Pinclude/net/mac80211.h Frame filtering -!Finclude/net/mac80211.h ieee80211_filter_flags - - - - The mac80211 workqueue -!Pinclude/net/mac80211.h mac80211 workqueue -!Finclude/net/mac80211.h ieee80211_queue_work -!Finclude/net/mac80211.h ieee80211_queue_delayed_work - - - - - Advanced driver interface - - - Information contained within this part of the book is - of interest only for advanced interaction of mac80211 - with drivers to exploit more hardware capabilities and - improve performance. - - - - - LED support - - Mac80211 supports various ways of blinking LEDs. Wherever possible, - device LEDs should be exposed as LED class devices and hooked up to - the appropriate trigger, which will then be triggered appropriately - by mac80211. - -!Finclude/net/mac80211.h ieee80211_get_tx_led_name -!Finclude/net/mac80211.h ieee80211_get_rx_led_name -!Finclude/net/mac80211.h ieee80211_get_assoc_led_name -!Finclude/net/mac80211.h ieee80211_get_radio_led_name -!Finclude/net/mac80211.h ieee80211_tpt_blink -!Finclude/net/mac80211.h ieee80211_tpt_led_trigger_flags -!Finclude/net/mac80211.h ieee80211_create_tpt_led_trigger - - - - Hardware crypto acceleration -!Pinclude/net/mac80211.h Hardware crypto acceleration - -!Finclude/net/mac80211.h set_key_cmd -!Finclude/net/mac80211.h ieee80211_key_conf -!Finclude/net/mac80211.h ieee80211_key_flags -!Finclude/net/mac80211.h ieee80211_get_tkip_p1k -!Finclude/net/mac80211.h ieee80211_get_tkip_p1k_iv -!Finclude/net/mac80211.h ieee80211_get_tkip_p2k - - - - Powersave support -!Pinclude/net/mac80211.h Powersave support - - - - Beacon filter support -!Pinclude/net/mac80211.h Beacon filter support -!Finclude/net/mac80211.h ieee80211_beacon_loss - - - - Multiple queues and QoS support - TBD -!Finclude/net/mac80211.h ieee80211_tx_queue_params - - - - Access point mode support - TBD - Some parts of the if_conf should be discussed here instead - - Insert notes about VLAN interfaces with hw crypto here or - in the hw crypto chapter. - -
- support for powersaving clients -!Pinclude/net/mac80211.h AP support for powersaving clients -!Finclude/net/mac80211.h ieee80211_get_buffered_bc -!Finclude/net/mac80211.h ieee80211_beacon_get -!Finclude/net/mac80211.h ieee80211_sta_eosp -!Finclude/net/mac80211.h ieee80211_frame_release_type -!Finclude/net/mac80211.h ieee80211_sta_ps_transition -!Finclude/net/mac80211.h ieee80211_sta_ps_transition_ni -!Finclude/net/mac80211.h ieee80211_sta_set_buffered -!Finclude/net/mac80211.h ieee80211_sta_block_awake -
-
- - - Supporting multiple virtual interfaces - TBD - - Note: WDS with identical MAC address should almost always be OK - - - Insert notes about having multiple virtual interfaces with - different MAC addresses here, note which configurations are - supported by mac80211, add notes about supporting hw crypto - with it. - -!Finclude/net/mac80211.h ieee80211_iterate_active_interfaces -!Finclude/net/mac80211.h ieee80211_iterate_active_interfaces_atomic - - - - Station handling - TODO -!Finclude/net/mac80211.h ieee80211_sta -!Finclude/net/mac80211.h sta_notify_cmd -!Finclude/net/mac80211.h ieee80211_find_sta -!Finclude/net/mac80211.h ieee80211_find_sta_by_ifaddr - - - - Hardware scan offload - TBD -!Finclude/net/mac80211.h ieee80211_scan_completed - - - - Aggregation - - TX A-MPDU aggregation -!Pnet/mac80211/agg-tx.c TX A-MPDU aggregation -!Cnet/mac80211/agg-tx.c - - - RX A-MPDU aggregation -!Pnet/mac80211/agg-rx.c RX A-MPDU aggregation -!Cnet/mac80211/agg-rx.c -!Finclude/net/mac80211.h ieee80211_ampdu_mlme_action - - - - - Spatial Multiplexing Powersave (SMPS) -!Pinclude/net/mac80211.h Spatial multiplexing power save -!Finclude/net/mac80211.h ieee80211_request_smps -!Finclude/net/mac80211.h ieee80211_smps_mode - -
- - - Rate control interface - - TBD - - This part of the book describes the rate control algorithm - interface and how it relates to mac80211 and drivers. - - - - Rate Control API - TBD -!Finclude/net/mac80211.h ieee80211_start_tx_ba_session -!Finclude/net/mac80211.h ieee80211_start_tx_ba_cb_irqsafe -!Finclude/net/mac80211.h ieee80211_stop_tx_ba_session -!Finclude/net/mac80211.h ieee80211_stop_tx_ba_cb_irqsafe -!Finclude/net/mac80211.h ieee80211_rate_control_changed -!Finclude/net/mac80211.h ieee80211_tx_rate_control -!Finclude/net/mac80211.h rate_control_send_low - - - - - Internals - - TBD - - This part of the book describes mac80211 internals. - - - - - Key handling - - Key handling basics -!Pnet/mac80211/key.c Key handling basics - - - MORE TBD - TBD - - - - - Receive processing - TBD - - - - Transmit processing - TBD - - - - Station info handling - - Programming information -!Fnet/mac80211/sta_info.h sta_info -!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags - - - STA information lifetime rules -!Pnet/mac80211/sta_info.c STA information lifetime rules - - - - - Aggregation -!Fnet/mac80211/sta_info.h sta_ampdu_mlme -!Fnet/mac80211/sta_info.h tid_ampdu_tx -!Fnet/mac80211/sta_info.h tid_ampdu_rx - - - - Synchronisation - TBD - Locking, lots of RCU - - -
-
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 736f5916daea1..fdf8232d0eeb2 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -12,7 +12,7 @@ DOCBOOKS := z8530book.xml \ kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ - 80211.xml debugobjects.xml sh.xml regulator.xml \ + debugobjects.xml sh.xml regulator.xml \ alsa-driver-api.xml writing-an-alsa-driver.xml \ tracepoint.xml w1.xml \ writing_musb_glue_layer.xml crypto-API.xml iio.xml diff --git a/Documentation/index.rst b/Documentation/index.rst index d9ccb94fca951..c53d089455a42 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -17,6 +17,7 @@ Contents: driver-api/index media/index gpu/index + 80211/index Indices and tables ================== diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9c23f4d33e06c..02b6690d7162b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -775,9 +775,9 @@ enum station_parameters_apply_mask { * (or NULL for no change) * @supported_rates_len: number of supported rates * @sta_flags_mask: station flags that changed - * (bitmask of BIT(NL80211_STA_FLAG_...)) + * (bitmask of BIT(%NL80211_STA_FLAG_...)) * @sta_flags_set: station flags values - * (bitmask of BIT(NL80211_STA_FLAG_...)) + * (bitmask of BIT(%NL80211_STA_FLAG_...)) * @listen_interval: listen interval or -1 for no change * @aid: AID or zero for no change * @peer_aid: mesh peer AID or zero for no change @@ -2947,47 +2947,54 @@ struct ieee80211_iface_limit { * * 1. Allow #STA <= 1, #AP <= 1, matching BI, channels = 1, 2 total: * - * struct ieee80211_iface_limit limits1[] = { - * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, - * { .max = 1, .types = BIT(NL80211_IFTYPE_AP}, }, - * }; - * struct ieee80211_iface_combination combination1 = { - * .limits = limits1, - * .n_limits = ARRAY_SIZE(limits1), - * .max_interfaces = 2, - * .beacon_int_infra_match = true, - * }; + * .. code-block:: c + * + * struct ieee80211_iface_limit limits1[] = { + * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, + * { .max = 1, .types = BIT(NL80211_IFTYPE_AP}, }, + * }; + * struct ieee80211_iface_combination combination1 = { + * .limits = limits1, + * .n_limits = ARRAY_SIZE(limits1), + * .max_interfaces = 2, + * .beacon_int_infra_match = true, + * }; * * * 2. Allow #{AP, P2P-GO} <= 8, channels = 1, 8 total: * - * struct ieee80211_iface_limit limits2[] = { - * { .max = 8, .types = BIT(NL80211_IFTYPE_AP) | - * BIT(NL80211_IFTYPE_P2P_GO), }, - * }; - * struct ieee80211_iface_combination combination2 = { - * .limits = limits2, - * .n_limits = ARRAY_SIZE(limits2), - * .max_interfaces = 8, - * .num_different_channels = 1, - * }; + * .. code-block:: c + * + * struct ieee80211_iface_limit limits2[] = { + * { .max = 8, .types = BIT(NL80211_IFTYPE_AP) | + * BIT(NL80211_IFTYPE_P2P_GO), }, + * }; + * struct ieee80211_iface_combination combination2 = { + * .limits = limits2, + * .n_limits = ARRAY_SIZE(limits2), + * .max_interfaces = 8, + * .num_different_channels = 1, + * }; * * * 3. Allow #STA <= 1, #{P2P-client,P2P-GO} <= 3 on two channels, 4 total. * - * This allows for an infrastructure connection and three P2P connections. - * - * struct ieee80211_iface_limit limits3[] = { - * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, - * { .max = 3, .types = BIT(NL80211_IFTYPE_P2P_GO) | - * BIT(NL80211_IFTYPE_P2P_CLIENT), }, - * }; - * struct ieee80211_iface_combination combination3 = { - * .limits = limits3, - * .n_limits = ARRAY_SIZE(limits3), - * .max_interfaces = 4, - * .num_different_channels = 2, - * }; + * This allows for an infrastructure connection and three P2P connections. + * + * .. code-block:: c + * + * struct ieee80211_iface_limit limits3[] = { + * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, + * { .max = 3, .types = BIT(NL80211_IFTYPE_P2P_GO) | + * BIT(NL80211_IFTYPE_P2P_CLIENT), }, + * }; + * struct ieee80211_iface_combination combination3 = { + * .limits = limits3, + * .n_limits = ARRAY_SIZE(limits3), + * .max_interfaces = 4, + * .num_different_channels = 2, + * }; + * */ struct ieee80211_iface_combination { const struct ieee80211_iface_limit *limits; -- GitLab From 4e1bff07d7e7bc9fc3fc62100dcb8f708e1e96d2 Mon Sep 17 00:00:00 2001 From: Sangwon Jee Date: Fri, 30 Sep 2016 15:38:47 -0700 Subject: [PATCH 0446/1167] Input: melfas_mip4 - add ic_name sysfs attribute Add ic_name sysfs attribute for retrieving IC model name. Signed-off-by: Sangwon Jee Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/melfas_mip4.c | 38 +++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index fb5fb9140ca95..552a3773f79d0 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -157,6 +157,7 @@ struct mip4_ts { char phys[32]; char product_name[16]; + char ic_name[4]; unsigned int max_x; unsigned int max_y; @@ -263,6 +264,18 @@ static int mip4_query_device(struct mip4_ts *ts) dev_dbg(&ts->client->dev, "product name: %.*s\n", (int)sizeof(ts->product_name), ts->product_name); + /* IC name */ + cmd[0] = MIP4_R0_INFO; + cmd[1] = MIP4_R1_INFO_IC_NAME; + error = mip4_i2c_xfer(ts, cmd, sizeof(cmd), + ts->ic_name, sizeof(ts->ic_name)); + if (error) + dev_warn(&ts->client->dev, + "Failed to retrieve IC name: %d\n", error); + else + dev_dbg(&ts->client->dev, "IC name: %.*s\n", + (int)sizeof(ts->ic_name), ts->ic_name); + /* Firmware version */ error = mip4_get_fw_version(ts); if (error) @@ -1326,7 +1339,7 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev, * paired with current firmware in the chip. */ count = snprintf(buf, PAGE_SIZE, "%.*s\n", - (int)sizeof(ts->product_name), ts->product_name); + (int)sizeof(ts->product_name), ts->product_name); mutex_unlock(&ts->input->mutex); @@ -1335,9 +1348,30 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev, static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL); +static ssize_t mip4_sysfs_read_ic_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mip4_ts *ts = i2c_get_clientdata(client); + size_t count; + + mutex_lock(&ts->input->mutex); + + count = snprintf(buf, PAGE_SIZE, "%.*s\n", + (int)sizeof(ts->ic_name), ts->ic_name); + + mutex_unlock(&ts->input->mutex); + + return count; +} + +static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL); + static struct attribute *mip4_attrs[] = { &dev_attr_fw_version.attr, &dev_attr_hw_version.attr, + &dev_attr_ic_name.attr, &dev_attr_update_fw.attr, NULL, }; @@ -1538,6 +1572,6 @@ static struct i2c_driver mip4_driver = { module_i2c_driver(mip4_driver); MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen"); -MODULE_VERSION("2016.03.12"); +MODULE_VERSION("2016.09.28"); MODULE_AUTHOR("Sangwon Jee "); MODULE_LICENSE("GPL"); -- GitLab From 930e19248e9b61da36c967687ca79c4d5f977919 Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Sat, 1 Oct 2016 12:07:35 -0700 Subject: [PATCH 0447/1167] Input: i8042 - skip selftest on ASUS laptops On suspend/resume cycle, selftest is executed to reset i8042 controller. But when this is done in Asus devices, subsequent calls to detect/init functions to elantech driver fails. Skipping selftest fixes this problem. An easier step to reproduce this problem is adding i8042.reset=1 as a kernel parameter. On Asus laptops, it'll make the system to start with the touchpad already stuck, since psmouse_probe forcibly calls the selftest function. This patch was inspired by John Hiesey's change[1], but, since this problem affects a lot of models of Asus, let's avoid running selftests on them. All models affected by this problem: A455LD K401LB K501LB K501LX R409L V502LX X302LA X450LCP X450LD X455LAB X455LDB X455LF Z450LA [1]: https://marc.info/?l=linux-input&m=144312209020616&w=2 Fixes: "ETPS/2 Elantech Touchpad dies after resume from suspend" (https://bugzilla.kernel.org/show_bug.cgi?id=107971) Signed-off-by: Marcos Paulo de Souza Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- Documentation/kernel-parameters.txt | 9 ++- drivers/input/serio/i8042-io.h | 2 +- drivers/input/serio/i8042-ip22io.h | 2 +- drivers/input/serio/i8042-ppcio.h | 2 +- drivers/input/serio/i8042-sparcio.h | 2 +- drivers/input/serio/i8042-unicore32io.h | 2 +- drivers/input/serio/i8042-x86ia64io.h | 96 ++++++++++++++++++++++++- drivers/input/serio/i8042.c | 55 +++++++++++--- 8 files changed, 150 insertions(+), 20 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 0b3de80ec8f69..3475b3297064c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1409,7 +1409,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX controllers i8042.notimeout [HW] Ignore timeout condition signalled by controller - i8042.reset [HW] Reset the controller during init and cleanup + i8042.reset [HW] Reset the controller during init, cleanup and + suspend-to-ram transitions, only during s2r + transitions, or never reset + Format: { 1 | Y | y | 0 | N | n } + 1, Y, y: always reset controller + 0, N, n: don't ever reset controller + Default: only on s2r transitions on x86; most other + architectures force reset to be always executed i8042.unlock [HW] Unlock (ignore) the keylock i8042.kbdreset [HW] Reset device connected to KBD port diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index a5eed2ade53de..34da81c006b6d 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -81,7 +81,7 @@ static inline int i8042_platform_init(void) return -EBUSY; #endif - i8042_reset = 1; + i8042_reset = I8042_RESET_ALWAYS; return 0; } diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h index ee1ad27d6ed06..08a1c10a1448d 100644 --- a/drivers/input/serio/i8042-ip22io.h +++ b/drivers/input/serio/i8042-ip22io.h @@ -61,7 +61,7 @@ static inline int i8042_platform_init(void) return -EBUSY; #endif - i8042_reset = 1; + i8042_reset = I8042_RESET_ALWAYS; return 0; } diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h index f708c75d16f1d..1aabea43329ed 100644 --- a/drivers/input/serio/i8042-ppcio.h +++ b/drivers/input/serio/i8042-ppcio.h @@ -44,7 +44,7 @@ static inline void i8042_write_command(int val) static inline int i8042_platform_init(void) { - i8042_reset = 1; + i8042_reset = I8042_RESET_ALWAYS; return 0; } diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index afcd1c1a05b27..6231d63860ee3 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -130,7 +130,7 @@ static int __init i8042_platform_init(void) } } - i8042_reset = 1; + i8042_reset = I8042_RESET_ALWAYS; return 0; } diff --git a/drivers/input/serio/i8042-unicore32io.h b/drivers/input/serio/i8042-unicore32io.h index 73f5cc124a360..455747552f858 100644 --- a/drivers/input/serio/i8042-unicore32io.h +++ b/drivers/input/serio/i8042-unicore32io.h @@ -61,7 +61,7 @@ static inline int i8042_platform_init(void) if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042")) return -EBUSY; - i8042_reset = 1; + i8042_reset = I8042_RESET_ALWAYS; return 0; } diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 68f5f4a0f1e72..f4bfb4b2d50a3 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -510,6 +510,90 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { { } }; +/* + * On some Asus laptops, just running self tests cause problems. + */ +static const struct dmi_system_id i8042_dmi_noselftest_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "R409L"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"), + }, + }, + { } +}; static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { { /* MSI Wind U-100 */ @@ -1072,12 +1156,18 @@ static int __init i8042_platform_init(void) return retval; #if defined(__ia64__) - i8042_reset = true; + i8042_reset = I8042_RESET_ALWAYS; #endif #ifdef CONFIG_X86 - if (dmi_check_system(i8042_dmi_reset_table)) - i8042_reset = true; + /* Honor module parameter when value is not default */ + if (i8042_reset == I8042_RESET_DEFAULT) { + if (dmi_check_system(i8042_dmi_reset_table)) + i8042_reset = I8042_RESET_ALWAYS; + + if (dmi_check_system(i8042_dmi_noselftest_table)) + i8042_reset = I8042_RESET_NEVER; + } if (dmi_check_system(i8042_dmi_noloop_table)) i8042_noloop = true; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index b4d34086e73f5..674a760f5221c 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -48,9 +48,39 @@ static bool i8042_unlock; module_param_named(unlock, i8042_unlock, bool, 0); MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); -static bool i8042_reset; -module_param_named(reset, i8042_reset, bool, 0); -MODULE_PARM_DESC(reset, "Reset controller during init and cleanup."); +enum i8042_controller_reset_mode { + I8042_RESET_NEVER, + I8042_RESET_ALWAYS, + I8042_RESET_ON_S2RAM, +#define I8042_RESET_DEFAULT I8042_RESET_ON_S2RAM +}; +static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT; +static int i8042_set_reset(const char *val, const struct kernel_param *kp) +{ + enum i8042_controller_reset_mode *arg = kp->arg; + int error; + bool reset; + + if (val) { + error = kstrtobool(val, &reset); + if (error) + return error; + } else { + reset = true; + } + + *arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER; + return 0; +} + +static const struct kernel_param_ops param_ops_reset_param = { + .flags = KERNEL_PARAM_OPS_FL_NOARG, + .set = i8042_set_reset, +}; +#define param_check_reset_param(name, p) \ + __param_check(name, p, enum i8042_controller_reset_mode) +module_param_named(reset, i8042_reset, reset_param, 0); +MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both"); static bool i8042_direct; module_param_named(direct, i8042_direct, bool, 0); @@ -1019,7 +1049,7 @@ static int i8042_controller_init(void) * Reset the controller and reset CRT to the original value set by BIOS. */ -static void i8042_controller_reset(bool force_reset) +static void i8042_controller_reset(bool s2r_wants_reset) { i8042_flush(); @@ -1044,8 +1074,10 @@ static void i8042_controller_reset(bool force_reset) * Reset the controller if requested. */ - if (i8042_reset || force_reset) + if (i8042_reset == I8042_RESET_ALWAYS || + (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) { i8042_controller_selftest(); + } /* * Restore the original control register setting. @@ -1110,7 +1142,7 @@ static void i8042_dritek_enable(void) * before suspending. */ -static int i8042_controller_resume(bool force_reset) +static int i8042_controller_resume(bool s2r_wants_reset) { int error; @@ -1118,7 +1150,8 @@ static int i8042_controller_resume(bool force_reset) if (error) return error; - if (i8042_reset || force_reset) { + if (i8042_reset == I8042_RESET_ALWAYS || + (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) { error = i8042_controller_selftest(); if (error) return error; @@ -1195,7 +1228,7 @@ static int i8042_pm_resume_noirq(struct device *dev) static int i8042_pm_resume(struct device *dev) { - bool force_reset; + bool want_reset; int i; for (i = 0; i < I8042_NUM_PORTS; i++) { @@ -1218,9 +1251,9 @@ static int i8042_pm_resume(struct device *dev) * off control to the platform firmware, otherwise we can simply restore * the mode. */ - force_reset = pm_resume_via_firmware(); + want_reset = pm_resume_via_firmware(); - return i8042_controller_resume(force_reset); + return i8042_controller_resume(want_reset); } static int i8042_pm_thaw(struct device *dev) @@ -1481,7 +1514,7 @@ static int __init i8042_probe(struct platform_device *dev) i8042_platform_device = dev; - if (i8042_reset) { + if (i8042_reset == I8042_RESET_ALWAYS) { error = i8042_controller_selftest(); if (error) return error; -- GitLab From ea720935cf6686f72def9d322298bf7e9bd53377 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 5 Oct 2016 10:14:42 +0200 Subject: [PATCH 0448/1167] mac80211: discard multicast and 4-addr A-MSDUs In mac80211, multicast A-MSDUs are accepted in many cases that they shouldn't be accepted in: * drop A-MSDUs with a multicast A1 (RA), as required by the spec in 9.11 (802.11-2012 version) * drop A-MSDUs with a 4-addr header, since the fourth address can't actually be useful for them; unless 4-address frame format is actually requested, even though the fourth address is still not useful in this case, but ignored Accepting the first case, in particular, is very problematic since it allows anyone else with possession of a GTK to send unicast frames encapsulated in a multicast A-MSDU, even when the AP has client isolation enabled. Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6175db385ba7d..3ac2f1cba3179 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2308,16 +2308,22 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) if (!(status->rx_flags & IEEE80211_RX_AMSDU)) return RX_CONTINUE; - if (ieee80211_has_a4(hdr->frame_control) && - rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && - !rx->sdata->u.vlan.sta) - return RX_DROP_UNUSABLE; + if (unlikely(ieee80211_has_a4(hdr->frame_control))) { + switch (rx->sdata->vif.type) { + case NL80211_IFTYPE_AP_VLAN: + if (!rx->sdata->u.vlan.sta) + return RX_DROP_UNUSABLE; + break; + case NL80211_IFTYPE_STATION: + if (!rx->sdata->u.mgd.use_4addr) + return RX_DROP_UNUSABLE; + break; + default: + return RX_DROP_UNUSABLE; + } + } - if (is_multicast_ether_addr(hdr->addr1) && - ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && - rx->sdata->u.vlan.sta) || - (rx->sdata->vif.type == NL80211_IFTYPE_STATION && - rx->sdata->u.mgd.use_4addr))) + if (is_multicast_ether_addr(hdr->addr1)) return RX_DROP_UNUSABLE; skb->dev = dev; -- GitLab From 7f6990c830f3e8d703f13d7963acf51936c52ad2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 5 Oct 2016 15:29:49 +0200 Subject: [PATCH 0449/1167] cfg80211: let ieee80211_amsdu_to_8023s() take only header-less SKB There's only a single case where has_80211_header is passed as true, which is in mac80211. Given that there's only simple code that needs to be done before calling it, export that function from cfg80211 instead and let mac80211 call it itself. Signed-off-by: Johannes Berg --- .../wireless/marvell/mwifiex/11n_rxreorder.c | 2 +- include/net/cfg80211.h | 31 +++++++++++++------ net/mac80211/rx.c | 8 ++++- net/wireless/util.c | 24 +++----------- 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index 94480123efa3d..e9f462e3730b4 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv, skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length)); ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, - priv->wdev.iftype, 0, false); + priv->wdev.iftype, 0); while (!skb_queue_empty(&list)) { struct rx_packet_hdr *rx_hdr; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fe78f02a242e7..f372eadd1963a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4039,6 +4039,18 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); * that do not do the 802.11/802.3 conversion on the device. */ +/** + * ieee80211_data_to_8023_exthdr - convert an 802.11 data frame to 802.3 + * @skb: the 802.11 data frame + * @ehdr: pointer to a &struct ethhdr that will get the header, instead + * of it being pushed into the SKB + * @addr: the device MAC address + * @iftype: the virtual interface type + * Return: 0 on success. Non-zero on error. + */ +int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, + const u8 *addr, enum nl80211_iftype iftype); + /** * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3 * @skb: the 802.11 data frame @@ -4046,8 +4058,11 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); * @iftype: the virtual interface type * Return: 0 on success. Non-zero on error. */ -int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, - enum nl80211_iftype iftype); +static inline int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, + enum nl80211_iftype iftype) +{ + return ieee80211_data_to_8023_exthdr(skb, NULL, addr, iftype); +} /** * ieee80211_data_from_8023 - convert an 802.3 frame to 802.11 @@ -4065,22 +4080,20 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, /** * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame * - * Decode an IEEE 802.11n A-MSDU frame and convert it to a list of - * 802.3 frames. The @list will be empty if the decode fails. The - * @skb is consumed after the function returns. + * Decode an IEEE 802.11 A-MSDU and convert it to a list of 802.3 frames. + * The @list will be empty if the decode fails. The @skb must be fully + * header-less before being passed in here; it is freed in this function. * - * @skb: The input IEEE 802.11n A-MSDU frame. + * @skb: The input A-MSDU frame without any headers. * @list: The output list of 802.3 frames. It must be allocated and * initialized by by the caller. * @addr: The device MAC address. * @iftype: The device interface type. * @extra_headroom: The hardware extra headroom for SKBs in the @list. - * @has_80211_header: Set it true if SKB is with IEEE 802.11 header. */ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, const u8 *addr, enum nl80211_iftype iftype, - const unsigned int extra_headroom, - bool has_80211_header); + const unsigned int extra_headroom); /** * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3ac2f1cba3179..de2d75fa5c514 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2298,6 +2298,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) __le16 fc = hdr->frame_control; struct sk_buff_head frame_list; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); + struct ethhdr ethhdr; if (unlikely(!ieee80211_is_data(fc))) return RX_CONTINUE; @@ -2329,9 +2330,14 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) skb->dev = dev; __skb_queue_head_init(&frame_list); + if (ieee80211_data_to_8023_exthdr(skb, ðhdr, + rx->sdata->vif.addr, + rx->sdata->vif.type)) + return RX_DROP_UNUSABLE; + ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, rx->sdata->vif.type, - rx->local->hw.extra_tx_headroom, true); + rx->local->hw.extra_tx_headroom); while (!skb_queue_empty(&frame_list)) { rx->skb = __skb_dequeue(&frame_list); diff --git a/net/wireless/util.c b/net/wireless/util.c index 8edce22d1b931..e36ede840b888 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -420,8 +420,8 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) } EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); -static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr, - const u8 *addr, enum nl80211_iftype iftype) +int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, + const u8 *addr, enum nl80211_iftype iftype) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct { @@ -525,13 +525,7 @@ static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr, return 0; } - -int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, - enum nl80211_iftype iftype) -{ - return __ieee80211_data_to_8023(skb, NULL, addr, iftype); -} -EXPORT_SYMBOL(ieee80211_data_to_8023); +EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr); int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, enum nl80211_iftype iftype, @@ -745,25 +739,18 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, const u8 *addr, enum nl80211_iftype iftype, - const unsigned int extra_headroom, - bool has_80211_header) + const unsigned int extra_headroom) { unsigned int hlen = ALIGN(extra_headroom, 4); struct sk_buff *frame = NULL; u16 ethertype; u8 *payload; - int offset = 0, remaining, err; + int offset = 0, remaining; struct ethhdr eth; bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb); bool reuse_skb = false; bool last = false; - if (has_80211_header) { - err = __ieee80211_data_to_8023(skb, ð, addr, iftype); - if (err) - goto out; - } - while (!last) { unsigned int subframe_len; int len; @@ -819,7 +806,6 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, purge: __skb_queue_purge(list); - out: dev_kfree_skb(skb); } EXPORT_SYMBOL(ieee80211_amsdu_to_8023s); -- GitLab From 8b935ee2ea17db720d70f6420f77f594c0c93f75 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 5 Oct 2016 16:17:01 +0200 Subject: [PATCH 0450/1167] cfg80211: add ability to check DA/SA in A-MSDU decapsulation We should not accept arbitrary DA/SA inside A-MSDUs, it could be used to circumvent protections, like allowing a station to send frames and make them seem to come from somewhere else. Add the necessary infrastructure in cfg80211 to allow such checks, in further patches we'll start using them. Signed-off-by: Johannes Berg --- .../net/wireless/marvell/mwifiex/11n_rxreorder.c | 2 +- include/net/cfg80211.h | 5 ++++- net/mac80211/rx.c | 3 ++- net/wireless/util.c | 14 ++++++++++++-- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index e9f462e3730b4..274dd5a1574a3 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv, skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length)); ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, - priv->wdev.iftype, 0); + priv->wdev.iftype, 0, NULL, NULL); while (!skb_queue_empty(&list)) { struct rx_packet_hdr *rx_hdr; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f372eadd1963a..7df600c463ebb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4090,10 +4090,13 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, * @addr: The device MAC address. * @iftype: The device interface type. * @extra_headroom: The hardware extra headroom for SKBs in the @list. + * @check_da: DA to check in the inner ethernet header, or NULL + * @check_sa: SA to check in the inner ethernet header, or NULL */ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, const u8 *addr, enum nl80211_iftype iftype, - const unsigned int extra_headroom); + const unsigned int extra_headroom, + const u8 *check_da, const u8 *check_sa); /** * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index de2d75fa5c514..cf53fe1a0aa29 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2337,7 +2337,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, rx->sdata->vif.type, - rx->local->hw.extra_tx_headroom); + rx->local->hw.extra_tx_headroom, + NULL, NULL); while (!skb_queue_empty(&frame_list)) { rx->skb = __skb_dequeue(&frame_list); diff --git a/net/wireless/util.c b/net/wireless/util.c index e36ede840b888..5ea12afc77061 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -739,7 +739,8 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, const u8 *addr, enum nl80211_iftype iftype, - const unsigned int extra_headroom) + const unsigned int extra_headroom, + const u8 *check_da, const u8 *check_sa) { unsigned int hlen = ALIGN(extra_headroom, 4); struct sk_buff *frame = NULL; @@ -767,8 +768,17 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, goto purge; offset += sizeof(struct ethhdr); - /* reuse skb for the last subframe */ last = remaining <= subframe_len + padding; + + /* FIXME: should we really accept multicast DA? */ + if ((check_da && !is_multicast_ether_addr(eth.h_dest) && + !ether_addr_equal(check_da, eth.h_dest)) || + (check_sa && !ether_addr_equal(check_sa, eth.h_source))) { + offset += len + padding; + continue; + } + + /* reuse skb for the last subframe */ if (!skb_is_nonlinear(skb) && !reuse_frag && last) { skb_pull(skb, offset); frame = skb; -- GitLab From e2b5227faaf33109d9d00f8a99f7b4f45a9d9c9f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 5 Oct 2016 16:42:06 +0200 Subject: [PATCH 0451/1167] mac80211: validate DA/SA during A-MSDU decapsulation As pointed out by Michael Braun, we don't check inner L2 addresses during A-MSDU decapsulation, leading to the possibility that, for example, a station associated to an AP sends frames as though they came from somewhere else. Fix this problem by letting cfg80211 validate the addresses, as indicated by passing in the ones that need to be validated. Reported-by: Michael Braun Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index cf53fe1a0aa29..a47bbc973f2db 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2299,6 +2299,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) struct sk_buff_head frame_list; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); struct ethhdr ethhdr; + const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source; if (unlikely(!ieee80211_is_data(fc))) return RX_CONTINUE; @@ -2322,6 +2323,23 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) default: return RX_DROP_UNUSABLE; } + check_da = NULL; + check_sa = NULL; + } else switch (rx->sdata->vif.type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + check_da = NULL; + break; + case NL80211_IFTYPE_STATION: + if (!rx->sta || + !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER)) + check_sa = NULL; + break; + case NL80211_IFTYPE_MESH_POINT: + check_sa = NULL; + break; + default: + break; } if (is_multicast_ether_addr(hdr->addr1)) @@ -2338,7 +2356,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, rx->sdata->vif.type, rx->local->hw.extra_tx_headroom, - NULL, NULL); + check_da, check_sa); while (!skb_queue_empty(&frame_list)) { rx->skb = __skb_dequeue(&frame_list); -- GitLab From 1d4de2e222b41006007d7dbfce2abfe448217e49 Mon Sep 17 00:00:00 2001 From: Michael Braun Date: Mon, 3 Oct 2016 13:14:15 +0200 Subject: [PATCH 0452/1167] mac80211: fix CMD_FRAME for AP_VLAN When using IEEE 802.11r FT OVER-DS roaming with AP_VLAN, hostapd needs to send out a frame using CMD_FRAME for a station assigned to an AP_VLAN interface. Right now, the userspace needs to give the exact AP_VLAN interface index for CMD_FRAME; hostapd does not do this. Additionally, userspace cannot use GET_STATION to query the AP_VLAN ifidx, as while GET_STATION finds stations assigned to AP_VLAN even if the AP iface is queried, it does not return AP_VLAN ifidx (it returns the queried one). This breaks IEEE 802.11r over_ds with vlans, as the reply frame does not get out. This patch fixes this by using get_sta_bss for CMD_FRAME. Signed-off-by: Michael Braun Signed-off-by: Johannes Berg --- net/mac80211/offchannel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index c3f610bba3fe9..eede5c6db8d5a 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -820,7 +820,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) break; rcu_read_lock(); - sta = sta_info_get(sdata, mgmt->da); + sta = sta_info_get_bss(sdata, mgmt->da); rcu_read_unlock(); if (!sta) return -ENOLINK; -- GitLab From 40c30bbf3377babc4d6bb16b699184236a8bfa27 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Tue, 11 Oct 2016 19:28:02 -0400 Subject: [PATCH 0453/1167] platform/x86: ideapad-laptop: Add Lenovo Yoga 910-13IKB to no_hw_rfkill dmi list The Lenovo Yoga 910-13IKB does not have a hw rfkill switch, and trying to read the hw rfkill switch through the ideapad module causes it to always report as blocked. This commit adds the Lenovo Yoga 910-13IKB to the no_hw_rfkill dmi list, fixing the WiFI breakage. Signed-off-by: Brian Masney Signed-off-by: Darren Hart --- drivers/platform/x86/ideapad-laptop.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index d1a091b93192c..a2323941e6770 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -933,6 +933,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 900"), }, }, + { + .ident = "Lenovo YOGA 910-13IKB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 910-13IKB"), + }, + }, {} }; -- GitLab From d5e84fd8d0634d056248b67463b42f6c85896a19 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 19 Sep 2016 10:57:40 +0100 Subject: [PATCH 0454/1167] Btrfs: fix incremental send failure caused by balance Commit 951555856b88 ("Btrfs: send, don't bug on inconsistent snapshots") removed some BUG_ON() statements (replacing them with returning errors to user space and logging error messages) when a snapshot is in an inconsistent state due to failures to update a delayed inode item (ENOMEM or ENOSPC) after adding/updating/deleting references, xattrs or file extent items. However there is a case, when no errors happen, where a file extent item can be modified without having the corresponding inode item updated. This case happens during balance under very specific timings, when relocation is in the stage where it updates data pointers and a leaf that contains file extent items is COWed. When that happens file extent items get their disk_bytenr field updated to a new value that reflects the post relocation logical address of the extent, without updating their respective inode items (as there is nothing that needs to be updated on them). This is performed at relocation.c:replace_file_extents() through relocation.c:btrfs_reloc_cow_block(). So make an incremental send deal with this case and don't do any processing for a file extent item that got its disk_bytenr field updated by relocation, since the extent's data is the same as the one pointed by the file extent item in the parent snapshot. After the recent commit mentioned above this case resulted in EIO errors returned to user space (and an error message logged to dmesg/syslog) when doing an incremental send, while before it, it resulted in hitting a BUG_ON leading to the following trace: [ 952.206705] ------------[ cut here ]------------ [ 952.206714] kernel BUG at ../fs/btrfs/send.c:5653! [ 952.206719] Internal error: Oops - BUG: 0 [#1] SMP [ 952.209854] Modules linked in: st dm_mod nls_utf8 isofs fuse nf_log_ipv6 xt_pkttype xt_physdev br_netfilter nf_log_ipv4 nf_log_common xt_LOG xt_limit ebtable_filter ebtables af_packet bridge stp llc ip6t_REJECT xt_tcpudp nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_raw ipt_REJECT iptable_raw xt_CT iptable_filter ip6table_mangle nf_conntrack_netbios_ns nf_conntrack_broadcast nf_conntrack_ipv4 nf_defrag_ipv4 ip_tables xt_conntrack nf_conntrack ip6table_filter ip6_tables x_tables xfs libcrc32c nls_iso8859_1 nls_cp437 vfat fat joydev aes_ce_blk ablk_helper cryptd snd_intel8x0 aes_ce_cipher snd_ac97_codec ac97_bus snd_pcm ghash_ce sha2_ce sha1_ce snd_timer snd virtio_net soundcore btrfs xor sr_mod cdrom hid_generic usbhid raid6_pq virtio_blk virtio_scsi bochs_drm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm virtio_mmio xhci_pci xhci_hcd usbcore usb_common virtio_pci virtio_ring virtio drm sg efivarfs [ 952.228333] Supported: Yes [ 952.228908] CPU: 0 PID: 12779 Comm: snapperd Not tainted 4.4.14-50-default #1 [ 952.230329] Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 [ 952.231683] task: ffff800058e94100 ti: ffff8000d866c000 task.ti: ffff8000d866c000 [ 952.233279] PC is at changed_cb+0x9f4/0xa48 [btrfs] [ 952.234375] LR is at changed_cb+0x58/0xa48 [btrfs] [ 952.236552] pc : [] lr : [] pstate: 80000145 [ 952.238049] sp : ffff8000d866fa20 [ 952.238732] x29: ffff8000d866fa20 x28: 0000000000000019 [ 952.239840] x27: 00000000000028d5 x26: 00000000000024a2 [ 952.241008] x25: 0000000000000002 x24: ffff8000e66e92f0 [ 952.242131] x23: ffff8000b8c76800 x22: ffff800092879140 [ 952.243238] x21: 0000000000000002 x20: ffff8000d866fb78 [ 952.244348] x19: ffff8000b8f8c200 x18: 0000000000002710 [ 952.245607] x17: 0000ffff90d42480 x16: ffff800000237dc0 [ 952.246719] x15: 0000ffff90de7510 x14: ab000c000a2faf08 [ 952.247835] x13: 0000000000577c2b x12: ab000c000b696665 [ 952.248981] x11: 2e65726f632f6966 x10: 652d34366d72612f [ 952.250101] x9 : 32627572672f746f x8 : ab000c00092f1671 [ 952.251352] x7 : 8000000000577c2b x6 : ffff800053eadf45 [ 952.252468] x5 : 0000000000000000 x4 : ffff80005e169494 [ 952.253582] x3 : 0000000000000004 x2 : ffff8000d866fb78 [ 952.254695] x1 : 000000000003e2a3 x0 : 000000000003e2a4 [ 952.255803] [ 952.256150] Process snapperd (pid: 12779, stack limit = 0xffff8000d866c020) [ 952.257516] Stack: (0xffff8000d866fa20 to 0xffff8000d8670000) [ 952.258654] fa20: ffff8000d866fae0 ffff7ffffc308fc0 ffff800092879140 ffff8000e66e92f0 [ 952.260219] fa40: 0000000000000035 ffff800055de6000 ffff8000b8c76800 ffff8000d866fb78 [ 952.261745] fa60: 0000000000000002 00000000000024a2 00000000000028d5 0000000000000019 [ 952.263269] fa80: ffff8000d866fae0 ffff7ffffc3090f0 ffff8000d866fae0 ffff7ffffc309128 [ 952.264797] faa0: ffff800092879140 ffff8000e66e92f0 0000000000000035 ffff800055de6000 [ 952.268261] fac0: ffff8000b8c76800 ffff8000d866fb78 0000000000000002 0000000000001000 [ 952.269822] fae0: ffff8000d866fbc0 ffff7ffffc39ecfc ffff8000b8f8c200 ffff8000b8f8c368 [ 952.271368] fb00: ffff8000b8f8c378 ffff800055de6000 0000000000000001 ffff8000ecb17500 [ 952.272893] fb20: ffff8000b8c76800 ffff800092879140 ffff800062b6d000 ffff80007a9e2470 [ 952.274420] fb40: ffff8000b8f8c208 0000000005784000 ffff8000580a8000 ffff8000b8f8c200 [ 952.276088] fb60: ffff7ffffc39d488 00000002b8f8c368 0000000000000000 000000000003e2a4 [ 952.280275] fb80: 000000000000006c ffff7ffffc39ec00 000000000003e2a4 000000000000006c [ 952.283219] fba0: ffff8000b8f8c300 0000000000000100 0000000000000001 ffff8000ecb17500 [ 952.286166] fbc0: ffff8000d866fcd0 ffff7ffffc3643c0 ffff8000f8842700 0000ffff8ffe9278 [ 952.289136] fbe0: 0000000040489426 ffff800055de6000 0000ffff8ffe9278 0000000040489426 [ 952.292083] fc00: 000000000000011d 000000000000001d ffff80007a9e4598 ffff80007a9e43e8 [ 952.294959] fc20: ffff8000b8c7693f 0000000000003b24 0000000000000019 ffff8000b8f8c218 [ 952.301161] fc40: 00000001d866fc70 ffff8000b8c76800 0000000000000128 ffffffffffffff84 [ 952.305749] fc60: ffff800058e941ff 0000000000003a58 ffff8000d866fcb0 ffff8000000f7390 [ 952.308875] fc80: 000000000000012a 0000000000010290 ffff8000d866fc00 000000000000007b [ 952.311915] fca0: 0000000000010290 ffff800046c1b100 74732d7366727462 000001006d616572 [ 952.314937] fcc0: ffff8000fffc4100 cb88537fdc8ba60e ffff8000d866fe10 ffff8000002499e8 [ 952.318008] fce0: 0000000040489426 ffff8000f8842700 0000ffff8ffe9278 ffff80007a9e4598 [ 952.321321] fd00: 0000ffff8ffe9278 0000000040489426 000000000000011d 000000000000001d [ 952.324280] fd20: ffff80000072c000 ffff8000d866c000 ffff8000d866fda0 ffff8000000e997c [ 952.327156] fd40: ffff8000fffc4180 00000000000031ed ffff8000fffc4180 ffff800046c1b7d4 [ 952.329895] fd60: 0000000000000140 0000ffff907ea170 000000000000011d 00000000000000dc [ 952.334641] fd80: ffff80000072c000 ffff8000d866c000 0000000000000000 0000000000000002 [ 952.338002] fda0: ffff8000d866fdd0 ffff8000000ebacc ffff800046c1b080 ffff800046c1b7d4 [ 952.340724] fdc0: ffff8000d866fdf0 ffff8000000db67c 0000000000000040 ffff800000e69198 [ 952.343415] fde0: 0000ffff8ffea790 00000000000031ed ffff8000d866fe20 ffff800000254000 [ 952.346101] fe00: 000000000000001d 0000000000000004 ffff8000d866fe90 ffff800000249d3c [ 952.348980] fe20: ffff8000f8842700 0000000000000000 ffff8000f8842701 0000000000000008 [ 952.351696] fe40: ffff8000d866fe70 0000000000000008 ffff8000d866fe90 ffff800000249cf8 [ 952.354387] fe60: ffff8000f8842700 0000ffff8ffe9170 ffff8000f8842701 0000000000000008 [ 952.357083] fe80: 0000ffff8ffe9278 ffff80008ff85500 0000ffff8ffe90c0 ffff800000085c84 [ 952.359800] fea0: 0000000000000000 0000ffff8ffe9170 ffffffffffffffff 0000ffff90d473bc [ 952.365351] fec0: 0000000000000000 0000000000000015 0000000000000008 0000000040489426 [ 952.369550] fee0: 0000ffff8ffe9278 0000ffff907ea790 0000ffff907ea170 0000ffff907ea790 [ 952.372416] ff00: 0000ffff907ea170 0000000000000000 000000000000001d 0000000000000004 [ 952.375223] ff20: 0000ffff90a32220 00000000003d0f00 0000ffff907ea0a0 0000ffff8ffe8f30 [ 952.378099] ff40: 0000ffff9100f554 0000ffff91147000 0000ffff91117bc0 0000ffff90d473b0 [ 952.381115] ff60: 0000ffff9100f620 0000ffff880069b0 0000ffff8ffe9170 0000ffff8ffe91a0 [ 952.384003] ff80: 0000ffff8ffe9160 0000ffff8ffe9140 0000ffff88006990 0000ffff8ffe9278 [ 952.386860] ffa0: 0000ffff88008a60 0000ffff8ffe9480 0000ffff88014ca0 0000ffff8ffe90c0 [ 952.389654] ffc0: 0000ffff910be8e8 0000ffff8ffe90c0 0000ffff90d473bc 0000000000000000 [ 952.410986] ffe0: 0000000000000008 000000000000001d 6e2079747265706f 72616d223d656d61 [ 952.415497] Call trace: [ 952.417403] [] changed_cb+0x9f4/0xa48 [btrfs] [ 952.420023] [] btrfs_compare_trees+0x500/0x6b0 [btrfs] [ 952.422759] [] btrfs_ioctl_send+0xb4c/0xe10 [btrfs] [ 952.425601] [] btrfs_ioctl+0x374/0x29a4 [btrfs] [ 952.428031] [] do_vfs_ioctl+0x33c/0x600 [ 952.430360] [] SyS_ioctl+0x90/0xa4 [ 952.432552] [] el0_svc_naked+0x38/0x3c [ 952.434803] Code: 2a1503e0 17fffdac b9404282 17ffff28 (d4210000) [ 952.437457] ---[ end trace 9afd7090c466cf15 ]--- Signed-off-by: Filipe Manana --- fs/btrfs/send.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 978796865bfc8..0b4628999b77a 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -5805,6 +5805,64 @@ static int changed_extent(struct send_ctx *sctx, int ret = 0; if (sctx->cur_ino != sctx->cmp_key->objectid) { + + if (result == BTRFS_COMPARE_TREE_CHANGED) { + struct extent_buffer *leaf_l; + struct extent_buffer *leaf_r; + struct btrfs_file_extent_item *ei_l; + struct btrfs_file_extent_item *ei_r; + + leaf_l = sctx->left_path->nodes[0]; + leaf_r = sctx->right_path->nodes[0]; + ei_l = btrfs_item_ptr(leaf_l, + sctx->left_path->slots[0], + struct btrfs_file_extent_item); + ei_r = btrfs_item_ptr(leaf_r, + sctx->right_path->slots[0], + struct btrfs_file_extent_item); + + /* + * We may have found an extent item that has changed + * only its disk_bytenr field and the corresponding + * inode item was not updated. This case happens due to + * very specific timings during relocation when a leaf + * that contains file extent items is COWed while + * relocation is ongoing and its in the stage where it + * updates data pointers. So when this happens we can + * safely ignore it since we know it's the same extent, + * but just at different logical and physical locations + * (when an extent is fully replaced with a new one, we + * know the generation number must have changed too, + * since snapshot creation implies committing the current + * transaction, and the inode item must have been updated + * as well). + * This replacement of the disk_bytenr happens at + * relocation.c:replace_file_extents() through + * relocation.c:btrfs_reloc_cow_block(). + */ + if (btrfs_file_extent_generation(leaf_l, ei_l) == + btrfs_file_extent_generation(leaf_r, ei_r) && + btrfs_file_extent_ram_bytes(leaf_l, ei_l) == + btrfs_file_extent_ram_bytes(leaf_r, ei_r) && + btrfs_file_extent_compression(leaf_l, ei_l) == + btrfs_file_extent_compression(leaf_r, ei_r) && + btrfs_file_extent_encryption(leaf_l, ei_l) == + btrfs_file_extent_encryption(leaf_r, ei_r) && + btrfs_file_extent_other_encoding(leaf_l, ei_l) == + btrfs_file_extent_other_encoding(leaf_r, ei_r) && + btrfs_file_extent_type(leaf_l, ei_l) == + btrfs_file_extent_type(leaf_r, ei_r) && + btrfs_file_extent_disk_bytenr(leaf_l, ei_l) != + btrfs_file_extent_disk_bytenr(leaf_r, ei_r) && + btrfs_file_extent_disk_num_bytes(leaf_l, ei_l) == + btrfs_file_extent_disk_num_bytes(leaf_r, ei_r) && + btrfs_file_extent_offset(leaf_l, ei_l) == + btrfs_file_extent_offset(leaf_r, ei_r) && + btrfs_file_extent_num_bytes(leaf_l, ei_l) == + btrfs_file_extent_num_bytes(leaf_r, ei_r)) + return 0; + } + inconsistent_snapshot_error(sctx, result, "extent"); return -EIO; } -- GitLab From 0f2065177ba994dfdf0d83d9ec1bd8d90ea7b7bb Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 29 Jun 2016 16:39:59 +0200 Subject: [PATCH 0455/1167] devicetree: Add Micro Crystal AG vendor id Add Micro Crystal AG vendor id Signed-off-by: Oleksij Rempel Acked-by: Rob Herring Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 1992aa97d45ac..a8c65f84d4bbc 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -159,6 +159,7 @@ melexis Melexis N.V. merrii Merrii Technology Co., Ltd. micrel Micrel Inc. microchip Microchip Technology Inc. +microcrystal Micro Crystal AG micron Micron Technology Inc. minix MINIX Technology Ltd. mitsubishi Mitsubishi Electric Corporation -- GitLab From eff6675b5cc191308c0144dcd5dd2b49257e83d7 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 29 Jun 2016 16:40:00 +0200 Subject: [PATCH 0456/1167] dt/bindings: Add bindings for Micro Crystal rv8803 ... and Epson RX8900 real time clock Signed-off-by: Oleksij Rempel Acked-by: Rob Herring Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/epson,rx8900.txt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/epson,rx8900.txt diff --git a/Documentation/devicetree/bindings/rtc/epson,rx8900.txt b/Documentation/devicetree/bindings/rtc/epson,rx8900.txt new file mode 100644 index 0000000000000..3f61e516ecf68 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/epson,rx8900.txt @@ -0,0 +1,22 @@ +Real Time Clock driver for: + - Epson RX8900 + - Micro Crystal rv8803 + +Required properties: +- compatible: should be: "microcrystal,rv8803" or "epson,rx8900" +- reg : the I2C address of the device for I2C + +Optional properties: +- epson,vdet-disable : boolean, if present will disable voltage detector. + Should be set if no backup battery is used. +- trickle-diode-disable : boolean, if present will disable internal trickle + charger diode + +Example: + + rtc: rtc@32 { + compatible = "epson,rx8900" + reg = <0x32>; + epson,vdet-disable; + trickle-diode-disable; + }; -- GitLab From 1cd713762e4cd5378a488fd6eaa7507bf030a832 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 29 Jun 2016 16:40:01 +0200 Subject: [PATCH 0457/1167] rtc: rv8803: set VDETOFF and SWOFF via device tree There might be designs where the power supply circuit is designed in a way that VDETOFF and SWOFF is required to be set. Otherwise the RTC detects a power loss. Add a device tree interface for this. Signed-off-by: Carsten Resch Signed-off-by: Dirk Behme Signed-off-by: Oleksij Rempel Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv8803.c | 50 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 9a2f6a95d5a7c..f9277e536f7e8 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -52,11 +52,21 @@ #define RV8803_CTRL_TIE BIT(4) #define RV8803_CTRL_UIE BIT(5) +#define RX8900_BACKUP_CTRL 0x18 +#define RX8900_FLAG_SWOFF BIT(2) +#define RX8900_FLAG_VDETOFF BIT(3) + +enum rv8803_type { + rv_8803, + rx_8900 +}; + struct rv8803_data { struct i2c_client *client; struct rtc_device *rtc; struct mutex flags_lock; u8 ctrl; + enum rv8803_type type; }; static int rv8803_read_reg(const struct i2c_client *client, u8 reg) @@ -497,6 +507,35 @@ static struct rtc_class_ops rv8803_rtc_ops = { .ioctl = rv8803_ioctl, }; +static int rx8900_trickle_charger_init(struct rv8803_data *rv8803) +{ + struct i2c_client *client = rv8803->client; + struct device_node *node = client->dev.of_node; + int err; + u8 flags; + + if (!node) + return 0; + + if (rv8803->type != rx_8900) + return 0; + + err = i2c_smbus_read_byte_data(rv8803->client, RX8900_BACKUP_CTRL); + if (err < 0) + return err; + + flags = ~(RX8900_FLAG_VDETOFF | RX8900_FLAG_SWOFF) & (u8)err; + + if (of_property_read_bool(node, "epson,vdet-disable")) + flags |= RX8900_FLAG_VDETOFF; + + if (of_property_read_bool(node, "trickle-diode-disable")) + flags |= RX8900_FLAG_SWOFF; + + return i2c_smbus_write_byte_data(rv8803->client, RX8900_BACKUP_CTRL, + flags); +} + static int rv8803_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -517,6 +556,7 @@ static int rv8803_probe(struct i2c_client *client, mutex_init(&rv8803->flags_lock); rv8803->client = client; + rv8803->type = id->driver_data; i2c_set_clientdata(client, rv8803); flags = rv8803_read_reg(client, RV8803_FLAG); @@ -558,6 +598,12 @@ static int rv8803_probe(struct i2c_client *client, if (err) return err; + err = rx8900_trickle_charger_init(rv8803); + if (err) { + dev_err(&client->dev, "failed to init charger\n"); + return err; + } + err = device_create_bin_file(&client->dev, &rv8803_nvram_attr); if (err) return err; @@ -575,8 +621,8 @@ static int rv8803_remove(struct i2c_client *client) } static const struct i2c_device_id rv8803_id[] = { - { "rv8803", 0 }, - { "rx8900", 0 }, + { "rv8803", rv_8803 }, + { "rx8900", rx_8900 }, { } }; MODULE_DEVICE_TABLE(i2c, rv8803_id); -- GitLab From 74f1077b5b783e7bf4fa3007cefdc8dbd6c07518 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 12 Oct 2016 09:32:56 +0200 Subject: [PATCH 0458/1167] MIPS: ptrace: Fix regs_return_value for kernel context Currently regs_return_value always negates reg[2] if it determines the syscall has failed, but when called in kernel context this check is invalid and may result in returning a wrong value. This fixes errors reported by CONFIG_KPROBES_SANITY_TEST Fixes: d7e7528bcd45 ("Audit: push audit success and retcode into arch ptrace.h") Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org # 3.3+ Patchwork: https://patchwork.linux-mips.org/patch/14381/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/ptrace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index f6fc6aac54963..b6578611dddbf 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -152,7 +152,7 @@ static inline int is_syscall_success(struct pt_regs *regs) static inline long regs_return_value(struct pt_regs *regs) { - if (is_syscall_success(regs)) + if (is_syscall_success(regs) || !user_mode(regs)) return regs->regs[2]; else return -regs->regs[2]; -- GitLab From 1fa9ce8d0e903449842943a77e8ba100169964be Mon Sep 17 00:00:00 2001 From: Tomasz Majchrzak Date: Wed, 12 Oct 2016 12:23:08 +0200 Subject: [PATCH 0459/1167] badblocks: fix overlapping check for clearing Current bad block clear implementation assumes the range to clear overlaps with at least one bad block already stored. If given range to clear precedes first bad block in a list, the first entry is incorrectly updated. Check not only if stored block end is past clear block end but also if stored block start is before clear block end. Signed-off-by: Tomasz Majchrzak Acked-by: NeilBrown Signed-off-by: Jens Axboe --- block/badblocks.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/block/badblocks.c b/block/badblocks.c index 7be53cb1cc3ce..6610e282a03e0 100644 --- a/block/badblocks.c +++ b/block/badblocks.c @@ -354,7 +354,8 @@ int badblocks_clear(struct badblocks *bb, sector_t s, int sectors) * current range. Earlier ranges could also overlap, * but only this one can overlap the end of the range. */ - if (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) { + if ((BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) && + (BB_OFFSET(p[lo]) < target)) { /* Partial overlap, leave the tail of this range */ int ack = BB_ACK(p[lo]); sector_t a = BB_OFFSET(p[lo]); @@ -377,7 +378,8 @@ int badblocks_clear(struct badblocks *bb, sector_t s, int sectors) lo--; } while (lo >= 0 && - BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) { + (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) && + (BB_OFFSET(p[lo]) < target)) { /* This range does overlap */ if (BB_OFFSET(p[lo]) < s) { /* Keep the early parts of this range. */ -- GitLab From 0df1e4f5e0e831670f43bd198623b303ba09cbc0 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 11 Oct 2016 13:31:58 -0400 Subject: [PATCH 0460/1167] nvme: Stop probing a removed device There is no reason the nvme controller can ever return all 1's from reading the CSTS register. This patch returns an error if we observe that status. Without this, we may incorrectly proceed with controller initialization and unnecessarilly rely on error handling to clean this. Signed-off-by: Keith Busch Signed-off-by: Jens Axboe --- drivers/nvme/host/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 329381a28edf8..2a57f5ede386c 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1086,6 +1086,8 @@ static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled) int ret; while ((ret = ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &csts)) == 0) { + if (csts == ~0) + return -ENODEV; if ((csts & NVME_CSTS_RDY) == bit) break; -- GitLab From 7065906096273b39b90a512a7170a6697ed94b23 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 12 Oct 2016 09:22:16 -0600 Subject: [PATCH 0461/1167] nvme: Delete created IO queues on reset The driver was decrementing the online_queues prior to attempting to delete those IO queues, so the driver ended up not requesting the controller delete any. This patch saves the online_queues prior to suspending them, and adds that parameter for deleting io queues. Fixes: c21377f8 ("nvme: Suspend all queues before deletion") Signed-off-by: Keith Busch Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/nvme/host/pci.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 68ef1875e8a88..94da3a47775c6 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1510,9 +1510,9 @@ static int nvme_delete_queue(struct nvme_queue *nvmeq, u8 opcode) return 0; } -static void nvme_disable_io_queues(struct nvme_dev *dev) +static void nvme_disable_io_queues(struct nvme_dev *dev, int queues) { - int pass, queues = dev->online_queues - 1; + int pass; unsigned long timeout; u8 opcode = nvme_admin_delete_sq; @@ -1648,7 +1648,7 @@ static void nvme_pci_disable(struct nvme_dev *dev) static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) { - int i; + int i, queues; u32 csts = -1; del_timer_sync(&dev->watchdog_timer); @@ -1659,6 +1659,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) csts = readl(dev->bar + NVME_REG_CSTS); } + queues = dev->online_queues - 1; for (i = dev->queue_count - 1; i > 0; i--) nvme_suspend_queue(dev->queues[i]); @@ -1670,7 +1671,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) if (dev->queue_count) nvme_suspend_queue(dev->queues[0]); } else { - nvme_disable_io_queues(dev); + nvme_disable_io_queues(dev, queues); nvme_disable_admin_queue(dev, shutdown); } nvme_pci_disable(dev); -- GitLab From c5f6ce97c12104668784ee17fb927c52a944d3d8 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 5 Oct 2016 16:32:45 -0400 Subject: [PATCH 0462/1167] nvme: don't schedule multiple resets The queue_work only fails if the work is pending, but not yet running. If the work is running, the work item would get requeued, triggering a double reset. If the first reset fails for any reason, the second reset triggers: WARN_ON(dev->ctrl.state == NVME_CTRL_RESETTING) Hitting that schedules controller deletion for a second time, which potentially takes a reference on the device that is being deleted. If the reset occurs at the same time as a hot removal event, this causes a double-free. This patch has the reset helper function check if the work is busy prior to queueing, and changes all places that schedule resets to use this function. Since most users don't want to sync with that work, the "flush_work" is moved to the only caller that wants to sync. Signed-off-by: Keith Busch Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/nvme/host/pci.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 94da3a47775c6..12357d616eebb 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -892,7 +892,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) "I/O %d QID %d timeout, reset controller\n", req->tag, nvmeq->qid); nvme_dev_disable(dev, false); - queue_work(nvme_workq, &dev->reset_work); + nvme_reset(dev); /* * Mark the request as handled, since the inline shutdown @@ -1290,7 +1290,7 @@ static void nvme_watchdog_timer(unsigned long data) /* Skip controllers under certain specific conditions. */ if (nvme_should_reset(dev, csts)) { - if (queue_work(nvme_workq, &dev->reset_work)) + if (!nvme_reset(dev)) dev_warn(dev->dev, "Failed status: 0x%x, reset controller.\n", csts); @@ -1818,11 +1818,10 @@ static int nvme_reset(struct nvme_dev *dev) { if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q)) return -ENODEV; - + if (work_busy(&dev->reset_work)) + return -ENODEV; if (!queue_work(nvme_workq, &dev->reset_work)) return -EBUSY; - - flush_work(&dev->reset_work); return 0; } @@ -1846,7 +1845,12 @@ static int nvme_pci_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val) static int nvme_pci_reset_ctrl(struct nvme_ctrl *ctrl) { - return nvme_reset(to_nvme_dev(ctrl)); + struct nvme_dev *dev = to_nvme_dev(ctrl); + int ret = nvme_reset(dev); + + if (!ret) + flush_work(&dev->reset_work); + return ret; } static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = { @@ -1940,7 +1944,7 @@ static void nvme_reset_notify(struct pci_dev *pdev, bool prepare) if (prepare) nvme_dev_disable(dev, false); else - queue_work(nvme_workq, &dev->reset_work); + nvme_reset(dev); } static void nvme_shutdown(struct pci_dev *pdev) @@ -2009,7 +2013,7 @@ static int nvme_resume(struct device *dev) struct pci_dev *pdev = to_pci_dev(dev); struct nvme_dev *ndev = pci_get_drvdata(pdev); - queue_work(nvme_workq, &ndev->reset_work); + nvme_reset(ndev); return 0; } #endif @@ -2048,7 +2052,7 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev) dev_info(dev->ctrl.device, "restart after slot reset\n"); pci_restore_state(pdev); - queue_work(nvme_workq, &dev->reset_work); + nvme_reset(dev); return PCI_ERS_RESULT_RECOVERED; } -- GitLab From a958fff2429525692c571bb6421b606fb0fef50a Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 19 Sep 2016 11:14:06 -0500 Subject: [PATCH 0463/1167] Add way to query file attributes via cifs xattr Add parsing for new pseudo-xattr user.cifs.dosattrib file attribute so tools can recognize what kind of file it is, and verify if common SMB3 attributes (system, hidden, archive, sparse, indexed etc.) are set. Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/xattr.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 5e23f64c0804b..c4237b8ad9c6a 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -33,6 +33,7 @@ #define MAX_EA_VALUE_SIZE 65535 #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" +#define CIFS_XATTR_ATTRIB "cifs.dosattrib" /* full name: user.cifs.dosattrib */ /* BB need to add server (Samba e.g) support for security and trusted prefix */ @@ -144,6 +145,31 @@ static int cifs_xattr_set(const struct xattr_handler *handler, return rc; } +static int cifs_attrib_get(struct dentry *dentry, + struct inode *inode, void *value, + size_t size) +{ + ssize_t rc; + __u32 *pattribute; + + rc = cifs_revalidate_dentry_attr(dentry); + + if (rc) + return rc; + + if ((value == NULL) || (size == 0)) + return sizeof(__u32); + else if (size < sizeof(__u32)) + return -ERANGE; + + /* return dos attributes as pseudo xattr */ + pattribute = (__u32 *)value; + *pattribute = CIFS_I(inode)->cifsAttrs; + + return sizeof(__u32); +} + + static int cifs_xattr_get(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, const char *name, void *value, size_t size) @@ -168,10 +194,16 @@ static int cifs_xattr_get(const struct xattr_handler *handler, rc = -ENOMEM; goto out; } - /* return dos attributes as pseudo xattr */ + /* return alt name if available as pseudo attr */ switch (handler->flags) { case XATTR_USER: + cifs_dbg(FYI, "%s:querying user xattr %s\n", __func__, name); + if (strcmp(name, CIFS_XATTR_ATTRIB) == 0) { + rc = cifs_attrib_get(dentry, inode, value, size); + break; + } + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) goto out; -- GitLab From 6609804413ae5b84830e35fdd3a7b7fe4149cf71 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 20 Sep 2016 03:05:57 -0500 Subject: [PATCH 0464/1167] Add way to query creation time of file via cifs xattr Add parsing for new pseudo-xattr user.cifs.creationtime file attribute to allow backup and test applications to view birth time of file on cifs/smb3 mounts. Signed-off-by: Steve French --- fs/cifs/xattr.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index c4237b8ad9c6a..20af5187ba63c 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -34,7 +34,7 @@ #define MAX_EA_VALUE_SIZE 65535 #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" #define CIFS_XATTR_ATTRIB "cifs.dosattrib" /* full name: user.cifs.dosattrib */ - +#define CIFS_XATTR_CREATETIME "cifs.creationtime" /* user.cifs.creationtime */ /* BB need to add server (Samba e.g) support for security and trusted prefix */ enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT }; @@ -169,6 +169,29 @@ static int cifs_attrib_get(struct dentry *dentry, return sizeof(__u32); } +static int cifs_creation_time_get(struct dentry *dentry, struct inode *inode, + void *value, size_t size) +{ + ssize_t rc; + __u64 * pcreatetime; + + rc = cifs_revalidate_dentry_attr(dentry); + if (rc) + return rc; + + if ((value == NULL) || (size == 0)) + return sizeof(__u64); + else if (size < sizeof(__u64)) + return -ERANGE; + + /* return dos attributes as pseudo xattr */ + pcreatetime = (__u64 *)value; + *pcreatetime = CIFS_I(inode)->createtime; + return sizeof(__u64); + + return rc; +} + static int cifs_xattr_get(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, @@ -202,6 +225,9 @@ static int cifs_xattr_get(const struct xattr_handler *handler, if (strcmp(name, CIFS_XATTR_ATTRIB) == 0) { rc = cifs_attrib_get(dentry, inode, value, size); break; + } else if (strcmp(name, CIFS_XATTR_CREATETIME) == 0) { + rc = cifs_creation_time_get(dentry, inode, value, size); + break; } if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) -- GitLab From 9742805d6b1bfb45d7f267648c34fb5bcd347397 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 19 Sep 2016 22:06:35 -0500 Subject: [PATCH 0465/1167] Display number of credits available In debugging smb3, it is useful to display the number of credits available, so we can see when the server has not granted sufficient operations for the client to make progress, or alternatively the client has requested too many credits (as we saw in a recent bug) so we can compare with the number of credits the server thinks we have. Add a /proc/fs/cifs/DebugData line to display the client view on how many credits are available. Signed-off-by: Steve French Reported-by: Germano Percossi CC: Stable --- fs/cifs/cifs_debug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 6c58e13fed2f1..3d03e48a92139 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -152,6 +152,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) list_for_each(tmp1, &cifs_tcp_ses_list) { server = list_entry(tmp1, struct TCP_Server_Info, tcp_ses_list); + seq_printf(m, "\nNumber of credits: %d", server->credits); i++; list_for_each(tmp2, &server->smb_ses_list) { ses = list_entry(tmp2, struct cifs_ses, -- GitLab From 7d414f396c91a3382e51cf628c1cf0709ad0188b Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Tue, 20 Sep 2016 13:37:13 +0100 Subject: [PATCH 0466/1167] cifs: Limit the overall credit acquired The kernel client requests 2 credits for many operations even though they only use 1 credit (presumably to build up a buffer of credit). Some servers seem to give the client as much credit as is requested. In this case, the amount of credit the client has continues increasing to the point where (server->credits * MAX_BUFFER_SIZE) overflows in smb2_wait_mtu_credits(). Fix this by throttling the credit requests if an set limit is reached. For async requests where the credit charge may be > 1, request as much credit as what is charged. The limit is chosen somewhat arbitrarily. The Windows client defaults to 128 credits, the Windows server allows clients up to 512 credits (or 8192 for Windows 2016), and the NetApp server (and at least one other) does not limit clients at all. Choose a high enough value such that the client shouldn't limit performance. This behavior was seen with a NetApp filer (NetApp Release 9.0RC2). Signed-off-by: Ross Lagerwall CC: Stable Signed-off-by: Steve French --- fs/cifs/smb2glob.h | 10 ++++++++++ fs/cifs/smb2pdu.c | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index 0ffa180943357..238759c146bad 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h @@ -61,4 +61,14 @@ /* Maximum buffer size value we can send with 1 credit */ #define SMB2_MAX_BUFFER_SIZE 65536 +/* + * Maximum number of credits to keep available. + * This value is chosen somewhat arbitrarily. The Windows client + * defaults to 128 credits, the Windows server allows clients up to + * 512 credits, and the NetApp server does not limit clients at all. + * Choose a high enough value such that the client shouldn't limit + * performance. + */ +#define SMB2_MAX_CREDITS_AVAILABLE 32000 + #endif /* _SMB2_GLOB_H */ diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 29e06db5f187b..967a7904fb8fe 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -100,7 +100,21 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , hdr->ProtocolId = SMB2_PROTO_NUMBER; hdr->StructureSize = cpu_to_le16(64); hdr->Command = smb2_cmd; - hdr->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */ + if (tcon && tcon->ses && tcon->ses->server) { + struct TCP_Server_Info *server = tcon->ses->server; + + spin_lock(&server->req_lock); + /* Request up to 2 credits but don't go over the limit. */ + if (server->credits >= SMB2_MAX_CREDITS_AVAILABLE) + hdr->CreditRequest = cpu_to_le16(0); + else + hdr->CreditRequest = cpu_to_le16( + min_t(int, SMB2_MAX_CREDITS_AVAILABLE - + server->credits, 2)); + spin_unlock(&server->req_lock); + } else { + hdr->CreditRequest = cpu_to_le16(2); + } hdr->ProcessId = cpu_to_le32((__u16)current->tgid); if (!tcon) @@ -2057,6 +2071,7 @@ smb2_async_readv(struct cifs_readdata *rdata) if (rdata->credits) { buf->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, SMB2_MAX_BUFFER_SIZE)); + buf->CreditRequest = buf->CreditCharge; spin_lock(&server->req_lock); server->credits += rdata->credits - le16_to_cpu(buf->CreditCharge); @@ -2243,6 +2258,7 @@ smb2_async_writev(struct cifs_writedata *wdata, if (wdata->credits) { req->hdr.CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, SMB2_MAX_BUFFER_SIZE)); + req->hdr.CreditRequest = req->hdr.CreditCharge; spin_lock(&server->req_lock); server->credits += wdata->credits - le16_to_cpu(req->hdr.CreditCharge); -- GitLab From c2afb8147e69819885493edf3a7c1ce03aaf2d4e Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 20 Sep 2016 22:56:13 -0500 Subject: [PATCH 0467/1167] Set previous session id correctly on SMB3 reconnect Signed-off-by: Steve French CC: Stable Reported-by: David Goebel --- fs/cifs/smb2pdu.c | 5 +++++ fs/cifs/smb2pdu.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 967a7904fb8fe..e8638432a2335 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -604,6 +604,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, char *security_blob = NULL; unsigned char *ntlmssp_blob = NULL; bool use_spnego = false; /* else use raw ntlmssp */ + u64 previous_session = ses->Suid; cifs_dbg(FYI, "Session Setup\n"); @@ -641,6 +642,10 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, return rc; req->hdr.SessionId = 0; /* First session, not a reauthenticate */ + + /* if reconnect, we need to send previous sess id, otherwise it is 0 */ + req->PreviousSessionId = previous_session; + req->Flags = 0; /* MBZ */ /* to enable echos and oplocks */ req->hdr.CreditRequest = cpu_to_le16(3); diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index ff88d9feb01e7..fd3709e8de33e 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -276,7 +276,7 @@ struct smb2_sess_setup_req { __le32 Channel; __le16 SecurityBufferOffset; __le16 SecurityBufferLength; - __le64 PreviousSessionId; + __u64 PreviousSessionId; __u8 Buffer[1]; /* variable length GSS security buffer */ } __packed; -- GitLab From fa70b87cc6641978b20e12cc5d517e9ffc0086d4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 22 Sep 2016 00:39:34 -0500 Subject: [PATCH 0468/1167] SMB3: GUIDs should be constructed as random but valid uuids GUIDs although random, and 16 bytes, need to be generated as proper uuids. Signed-off-by: Steve French Reviewed-by: Aurelien Aptel Reported-by: David Goebels CC: Stable --- fs/cifs/cifsfs.c | 2 +- fs/cifs/connect.c | 2 +- fs/cifs/smb2ops.c | 2 +- fs/cifs/smb2pdu.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index cca04e710421d..978dbf049a778 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -271,7 +271,7 @@ cifs_alloc_inode(struct super_block *sb) cifs_inode->createtime = 0; cifs_inode->epoch = 0; #ifdef CONFIG_CIFS_SMB2 - get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE); + generate_random_uuid(cifs_inode->lease_key); #endif /* * Can not set i_flags here - they get immediately overwritten to zero diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2e4f4bad8b1e9..c841244a954d5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2163,7 +2163,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, sizeof(tcp_ses->dstaddr)); #ifdef CONFIG_CIFS_SMB2 - get_random_bytes(tcp_ses->client_guid, SMB2_CLIENT_GUID_SIZE); + generate_random_uuid(tcp_ses->client_guid); #endif /* * at this point we are the only ones with the pointer diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index d203c0329626c..5ed591d7fff33 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1041,7 +1041,7 @@ smb2_set_lease_key(struct inode *inode, struct cifs_fid *fid) static void smb2_new_lease_key(struct cifs_fid *fid) { - get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE); + generate_random_uuid(fid->lease_key); } #define SMB2_SYMLINK_STRUCT_SIZE \ diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index e8638432a2335..3eec96ca87d99 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1183,7 +1183,7 @@ create_durable_v2_buf(struct cifs_fid *pfid) buf->dcontext.Timeout = 0; /* Should this be configurable by workload */ buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); - get_random_bytes(buf->dcontext.CreateGuid, 16); + generate_random_uuid(buf->dcontext.CreateGuid); memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16); /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */ -- GitLab From 94f873717571c759b7928399cbbddfa3d569bd01 Mon Sep 17 00:00:00 2001 From: Aurelien Aptel Date: Thu, 22 Sep 2016 07:38:50 +0200 Subject: [PATCH 0469/1167] fs/cifs: keep guid when assigning fid to fileinfo When we open a durable handle we give a Globally Unique Identifier (GUID) to the server which we must keep for later reference e.g. when reopening persistent handles on reconnection. Without this the GUID generated for a new persistent handle was lost and 16 zero bytes were used instead on re-opening. Signed-off-by: Aurelien Aptel CC: Stable Signed-off-by: Steve French --- fs/cifs/smb2ops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 5ed591d7fff33..91e53df4e420e 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -541,6 +541,7 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) server->ops->set_oplock_level(cinode, oplock, fid->epoch, &fid->purge_cache); cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); + memcpy(cfile->fid.create_guid, fid->create_guid, 16); } static void -- GitLab From d171356ff11ab1825e456dfb979755e01b3c54a1 Mon Sep 17 00:00:00 2001 From: Sachin Prabhu Date: Tue, 6 Sep 2016 13:22:34 +0100 Subject: [PATCH 0470/1167] Fix regression which breaks DFS mounting Patch a6b5058 results in -EREMOTE returned by is_path_accessible() in cifs_mount() to be ignored which breaks DFS mounting. Signed-off-by: Sachin Prabhu Reviewed-by: Aurelien Aptel CC: Stable Signed-off-by: Steve French --- fs/cifs/connect.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c841244a954d5..7b67179521cfc 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3688,14 +3688,16 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) goto mount_fail_check; } - rc = cifs_are_all_path_components_accessible(server, + if (rc != -EREMOTE) { + rc = cifs_are_all_path_components_accessible(server, xid, tcon, cifs_sb, full_path); - if (rc != 0) { - cifs_dbg(VFS, "cannot query dirs between root and final path, " - "enabling CIFS_MOUNT_USE_PREFIX_PATH\n"); - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; - rc = 0; + if (rc != 0) { + cifs_dbg(VFS, "cannot query dirs between root and final path, " + "enabling CIFS_MOUNT_USE_PREFIX_PATH\n"); + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; + rc = 0; + } } kfree(full_path); } -- GitLab From 3afca265b5f53a0b15b79531c13858049505582d Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 22 Sep 2016 18:58:16 -0500 Subject: [PATCH 0471/1167] Clarify locking of cifs file and tcon structures and make more granular Remove the global file_list_lock to simplify cifs/smb3 locking and have spinlocks that more closely match the information they are protecting. Add new tcon->open_file_lock and file->file_info_lock spinlocks. Locks continue to follow a heirachy, cifs_socket --> cifs_ses --> cifs_tcon --> cifs_file where global tcp_ses_lock still protects socket and cifs_ses, while the the newer locks protect the lower level structure's information (tcon and cifs_file respectively). CC: Stable Signed-off-by: Steve French Signed-off-by: Pavel Shilovsky Reviewed-by: Aurelien Aptel Reviewed-by: Germano Percossi --- fs/cifs/cifsfs.c | 1 - fs/cifs/cifsglob.h | 30 ++++++++++----------- fs/cifs/cifssmb.c | 4 +-- fs/cifs/file.c | 66 +++++++++++++++++++++++++++------------------- fs/cifs/misc.c | 15 ++++++----- fs/cifs/readdir.c | 6 ++--- fs/cifs/smb2misc.c | 16 +++++------ 7 files changed, 75 insertions(+), 63 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 978dbf049a778..d2b2703fed7dd 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1262,7 +1262,6 @@ init_cifs(void) GlobalTotalActiveXid = 0; GlobalMaxActiveXid = 0; spin_lock_init(&cifs_tcp_ses_lock); - spin_lock_init(&cifs_file_list_lock); spin_lock_init(&GlobalMid_Lock); get_random_bytes(&cifs_lock_secret, sizeof(cifs_lock_secret)); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 8f1d8c1e72bec..65f78b7a90620 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -833,6 +833,7 @@ struct cifs_tcon { struct list_head tcon_list; int tc_count; struct list_head openFileList; + spinlock_t open_file_lock; /* protects list above */ struct cifs_ses *ses; /* pointer to session associated with */ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ char *nativeFileSystem; @@ -889,7 +890,7 @@ struct cifs_tcon { #endif /* CONFIG_CIFS_STATS2 */ __u64 bytes_read; __u64 bytes_written; - spinlock_t stat_lock; + spinlock_t stat_lock; /* protects the two fields above */ #endif /* CONFIG_CIFS_STATS */ FILE_SYSTEM_DEVICE_INFO fsDevInfo; FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ @@ -1040,8 +1041,10 @@ struct cifs_fid_locks { }; struct cifsFileInfo { + /* following two lists are protected by tcon->open_file_lock */ struct list_head tlist; /* pointer to next fid owned by tcon */ struct list_head flist; /* next fid (file instance) for this inode */ + /* lock list below protected by cifsi->lock_sem */ struct cifs_fid_locks *llist; /* brlocks held by this fid */ kuid_t uid; /* allows finding which FileInfo structure */ __u32 pid; /* process id who opened file */ @@ -1049,11 +1052,12 @@ struct cifsFileInfo { /* BB add lock scope info here if needed */ ; /* lock scope id (0 if none) */ struct dentry *dentry; - unsigned int f_flags; struct tcon_link *tlink; + unsigned int f_flags; bool invalidHandle:1; /* file closed via session abend */ bool oplock_break_cancelled:1; - int count; /* refcount protected by cifs_file_list_lock */ + int count; + spinlock_t file_info_lock; /* protects four flag/count fields above */ struct mutex fh_mutex; /* prevents reopen race after dead ses*/ struct cifs_search_info srch_inf; struct work_struct oplock_break; /* work for oplock breaks */ @@ -1120,7 +1124,7 @@ struct cifs_writedata { /* * Take a reference on the file private data. Must be called with - * cifs_file_list_lock held. + * cfile->file_info_lock held. */ static inline void cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file) @@ -1514,8 +1518,10 @@ require use of the stronger protocol */ * GlobalMid_Lock protects: * list operations on pending_mid_q and oplockQ * updates to XID counters, multiplex id and SMB sequence numbers - * cifs_file_list_lock protects: - * list operations on tcp and SMB session lists and tCon lists + * tcp_ses_lock protects: + * list operations on tcp and SMB session lists + * tcon->open_file_lock protects the list of open files hanging off the tcon + * cfile->file_info_lock protects counters and fields in cifs file struct * f_owner.lock protects certain per file struct operations * mapping->page_lock protects certain per page operations * @@ -1547,18 +1553,12 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; * tcp session, and the list of tcon's per smb session. It also protects * the reference counters for the server, smb session, and tcon. Finally, * changes to the tcon->tidStatus should be done while holding this lock. + * generally the locks should be taken in order tcp_ses_lock before + * tcon->open_file_lock and that before file->file_info_lock since the + * structure order is cifs_socket-->cifs_ses-->cifs_tcon-->cifs_file */ GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock; -/* - * This lock protects the cifs_file->llist and cifs_file->flist - * list operations, and updates to some flags (cifs_file->invalidHandle) - * It will be moved to either use the tcon->stat_lock or equivalent later. - * If cifs_tcp_ses_lock and the lock below are both needed to be held, then - * the cifs_tcp_ses_lock must be grabbed first and released last. - */ -GLOBAL_EXTERN spinlock_t cifs_file_list_lock; - #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ /* Outstanding dir notify requests */ GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f82d2823622f3..3f3185febc585 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -98,13 +98,13 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon) struct list_head *tmp1; /* list all files open on tree connection and mark them invalid */ - spin_lock(&cifs_file_list_lock); + spin_lock(&tcon->open_file_lock); list_for_each_safe(tmp, tmp1, &tcon->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, tlist); open_file->invalidHandle = true; open_file->oplock_break_cancelled = true; } - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); /* * BB Add call to invalidate_inodes(sb) for all superblocks mounted * to this tcon. diff --git a/fs/cifs/file.c b/fs/cifs/file.c index a95fe8b1afe93..ee5ceae224118 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -305,6 +305,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, cfile->tlink = cifs_get_tlink(tlink); INIT_WORK(&cfile->oplock_break, cifs_oplock_break); mutex_init(&cfile->fh_mutex); + spin_lock_init(&cfile->file_info_lock); cifs_sb_active(inode->i_sb); @@ -317,7 +318,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, oplock = 0; } - spin_lock(&cifs_file_list_lock); + spin_lock(&tcon->open_file_lock); if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock) oplock = fid->pending_open->oplock; list_del(&fid->pending_open->olist); @@ -326,12 +327,13 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, server->ops->set_fid(cfile, fid, oplock); list_add(&cfile->tlist, &tcon->openFileList); + /* if readable file instance put first in list*/ if (file->f_mode & FMODE_READ) list_add(&cfile->flist, &cinode->openFileList); else list_add_tail(&cfile->flist, &cinode->openFileList); - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); if (fid->purge_cache) cifs_zap_mapping(inode); @@ -343,16 +345,16 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, struct cifsFileInfo * cifsFileInfo_get(struct cifsFileInfo *cifs_file) { - spin_lock(&cifs_file_list_lock); + spin_lock(&cifs_file->file_info_lock); cifsFileInfo_get_locked(cifs_file); - spin_unlock(&cifs_file_list_lock); + spin_unlock(&cifs_file->file_info_lock); return cifs_file; } /* * Release a reference on the file private data. This may involve closing * the filehandle out on the server. Must be called without holding - * cifs_file_list_lock. + * tcon->open_file_lock and cifs_file->file_info_lock. */ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) { @@ -367,11 +369,15 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) struct cifs_pending_open open; bool oplock_break_cancelled; - spin_lock(&cifs_file_list_lock); + spin_lock(&tcon->open_file_lock); + + spin_lock(&cifs_file->file_info_lock); if (--cifs_file->count > 0) { - spin_unlock(&cifs_file_list_lock); + spin_unlock(&cifs_file->file_info_lock); + spin_unlock(&tcon->open_file_lock); return; } + spin_unlock(&cifs_file->file_info_lock); if (server->ops->get_lease_key) server->ops->get_lease_key(inode, &fid); @@ -395,7 +401,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags); cifs_set_oplock_level(cifsi, 0); } - spin_unlock(&cifs_file_list_lock); + + spin_unlock(&tcon->open_file_lock); oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break); @@ -772,10 +779,10 @@ int cifs_closedir(struct inode *inode, struct file *file) server = tcon->ses->server; cifs_dbg(FYI, "Freeing private data in close dir\n"); - spin_lock(&cifs_file_list_lock); + spin_lock(&cfile->file_info_lock); if (server->ops->dir_needs_close(cfile)) { cfile->invalidHandle = true; - spin_unlock(&cifs_file_list_lock); + spin_unlock(&cfile->file_info_lock); if (server->ops->close_dir) rc = server->ops->close_dir(xid, tcon, &cfile->fid); else @@ -784,7 +791,7 @@ int cifs_closedir(struct inode *inode, struct file *file) /* not much we can do if it fails anyway, ignore rc */ rc = 0; } else - spin_unlock(&cifs_file_list_lock); + spin_unlock(&cfile->file_info_lock); buf = cfile->srch_inf.ntwrk_buf_start; if (buf) { @@ -1728,12 +1735,13 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, { struct cifsFileInfo *open_file = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); /* only filter by fsuid on multiuser mounts */ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) fsuid_only = false; - spin_lock(&cifs_file_list_lock); + spin_lock(&tcon->open_file_lock); /* we could simply get the first_list_entry since write-only entries are always at the end of the list but since the first entry might have a close pending, we go through the whole list */ @@ -1744,8 +1752,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, if (!open_file->invalidHandle) { /* found a good file */ /* lock it so it will not be closed on us */ - cifsFileInfo_get_locked(open_file); - spin_unlock(&cifs_file_list_lock); + cifsFileInfo_get(open_file); + spin_unlock(&tcon->open_file_lock); return open_file; } /* else might as well continue, and look for another, or simply have the caller reopen it @@ -1753,7 +1761,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, } else /* write only file */ break; /* write only files are last so must be done */ } - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); return NULL; } @@ -1762,6 +1770,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, { struct cifsFileInfo *open_file, *inv_file = NULL; struct cifs_sb_info *cifs_sb; + struct cifs_tcon *tcon; bool any_available = false; int rc; unsigned int refind = 0; @@ -1777,15 +1786,16 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, } cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); + tcon = cifs_sb_master_tcon(cifs_sb); /* only filter by fsuid on multiuser mounts */ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) fsuid_only = false; - spin_lock(&cifs_file_list_lock); + spin_lock(&tcon->open_file_lock); refind_writable: if (refind > MAX_REOPEN_ATT) { - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); return NULL; } list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { @@ -1796,8 +1806,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { if (!open_file->invalidHandle) { /* found a good writable file */ - cifsFileInfo_get_locked(open_file); - spin_unlock(&cifs_file_list_lock); + cifsFileInfo_get(open_file); + spin_unlock(&tcon->open_file_lock); return open_file; } else { if (!inv_file) @@ -1813,24 +1823,24 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, if (inv_file) { any_available = false; - cifsFileInfo_get_locked(inv_file); + cifsFileInfo_get(inv_file); } - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); if (inv_file) { rc = cifs_reopen_file(inv_file, false); if (!rc) return inv_file; else { - spin_lock(&cifs_file_list_lock); + spin_lock(&tcon->open_file_lock); list_move_tail(&inv_file->flist, &cifs_inode->openFileList); - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); cifsFileInfo_put(inv_file); - spin_lock(&cifs_file_list_lock); ++refind; inv_file = NULL; + spin_lock(&tcon->open_file_lock); goto refind_writable; } } @@ -3612,15 +3622,17 @@ static int cifs_readpage(struct file *file, struct page *page) static int is_inode_writable(struct cifsInodeInfo *cifs_inode) { struct cifsFileInfo *open_file; + struct cifs_tcon *tcon = + cifs_sb_master_tcon(CIFS_SB(cifs_inode->vfs_inode.i_sb)); - spin_lock(&cifs_file_list_lock); + spin_lock(&tcon->open_file_lock); list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); return 1; } } - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); return 0; } diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 813fe13c2ae17..c6729156f9a00 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -120,6 +120,7 @@ tconInfoAlloc(void) ++ret_buf->tc_count; INIT_LIST_HEAD(&ret_buf->openFileList); INIT_LIST_HEAD(&ret_buf->tcon_list); + spin_lock_init(&ret_buf->open_file_lock); #ifdef CONFIG_CIFS_STATS spin_lock_init(&ret_buf->stat_lock); #endif @@ -465,7 +466,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) continue; cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); - spin_lock(&cifs_file_list_lock); + spin_lock(&tcon->open_file_lock); list_for_each(tmp2, &tcon->openFileList) { netfile = list_entry(tmp2, struct cifsFileInfo, tlist); @@ -495,11 +496,11 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) &netfile->oplock_break); netfile->oplock_break_cancelled = false; - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_tcp_ses_lock); return true; } - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_tcp_ses_lock); cifs_dbg(FYI, "No matching file for oplock break\n"); return true; @@ -613,9 +614,9 @@ backup_cred(struct cifs_sb_info *cifs_sb) void cifs_del_pending_open(struct cifs_pending_open *open) { - spin_lock(&cifs_file_list_lock); + spin_lock(&tlink_tcon(open->tlink)->open_file_lock); list_del(&open->olist); - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tlink_tcon(open->tlink)->open_file_lock); } void @@ -635,7 +636,7 @@ void cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink, struct cifs_pending_open *open) { - spin_lock(&cifs_file_list_lock); + spin_lock(&tlink_tcon(tlink)->open_file_lock); cifs_add_pending_open_locked(fid, tlink, open); - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tlink_tcon(open->tlink)->open_file_lock); } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 65cf85dcda09b..8f6a2a5863b9d 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -597,14 +597,14 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) { /* close and restart search */ cifs_dbg(FYI, "search backing up - close and restart search\n"); - spin_lock(&cifs_file_list_lock); + spin_lock(&cfile->file_info_lock); if (server->ops->dir_needs_close(cfile)) { cfile->invalidHandle = true; - spin_unlock(&cifs_file_list_lock); + spin_unlock(&cfile->file_info_lock); if (server->ops->close_dir) server->ops->close_dir(xid, tcon, &cfile->fid); } else - spin_unlock(&cifs_file_list_lock); + spin_unlock(&cfile->file_info_lock); if (cfile->srch_inf.ntwrk_buf_start) { cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind\n"); if (cfile->srch_inf.smallBuf) diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 389fb9f8c84e2..3d383489b9cf3 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -549,19 +549,19 @@ smb2_is_valid_lease_break(char *buffer) list_for_each(tmp1, &server->smb_ses_list) { ses = list_entry(tmp1, struct cifs_ses, smb_ses_list); - spin_lock(&cifs_file_list_lock); list_for_each(tmp2, &ses->tcon_list) { tcon = list_entry(tmp2, struct cifs_tcon, tcon_list); + spin_lock(&tcon->open_file_lock); cifs_stats_inc( &tcon->stats.cifs_stats.num_oplock_brks); if (smb2_tcon_has_lease(tcon, rsp, lw)) { - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_tcp_ses_lock); return true; } + spin_unlock(&tcon->open_file_lock); } - spin_unlock(&cifs_file_list_lock); } } spin_unlock(&cifs_tcp_ses_lock); @@ -603,7 +603,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) tcon = list_entry(tmp1, struct cifs_tcon, tcon_list); cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); - spin_lock(&cifs_file_list_lock); + spin_lock(&tcon->open_file_lock); list_for_each(tmp2, &tcon->openFileList) { cfile = list_entry(tmp2, struct cifsFileInfo, tlist); @@ -615,7 +615,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) cifs_dbg(FYI, "file id match, oplock break\n"); cinode = CIFS_I(d_inode(cfile->dentry)); - + spin_lock(&cfile->file_info_lock); if (!CIFS_CACHE_WRITE(cinode) && rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE) cfile->oplock_break_cancelled = true; @@ -637,14 +637,14 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) clear_bit( CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, &cinode->flags); - + spin_unlock(&cfile->file_info_lock); queue_work(cifsiod_wq, &cfile->oplock_break); - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_tcp_ses_lock); return true; } - spin_unlock(&cifs_file_list_lock); + spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_tcp_ses_lock); cifs_dbg(FYI, "No matching file for oplock break\n"); return true; -- GitLab From 52ace1ef1259e119a24a34b45cb800c4e7529090 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 22 Sep 2016 19:23:56 -0500 Subject: [PATCH 0472/1167] fs/cifs: reopen persistent handles on reconnect Continuous Availability features like persistent handles require that clients reconnect their open files, not just the sessions, soon after the network connection comes back up, otherwise the server will throw away the state (byte range locks, leases, deny modes) on those handles after a timeout. Add code to reconnect handles when use_persistent set (e.g. Continuous Availability shares) after tree reconnect. Signed-off-by: Aurelien Aptel Reviewed-by: Germano Percossi Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 2 ++ fs/cifs/file.c | 18 ++++++++++++++++++ fs/cifs/smb2pdu.c | 5 +++++ 3 files changed, 25 insertions(+) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 4ead72a001f97..ced0e42ce4609 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -193,6 +193,8 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data, extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); extern void cifs_umount(struct cifs_sb_info *); extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); +extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon); + extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, __u8 type, struct cifsLockInfo **conf_lock, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index ee5ceae224118..8f27c8a74384b 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -760,6 +760,24 @@ int cifs_close(struct inode *inode, struct file *file) return 0; } +void +cifs_reopen_persistent_handles(struct cifs_tcon *tcon) +{ + struct cifsFileInfo *open_file = NULL; + struct list_head *tmp; + struct list_head *tmp1; + + /* list all files open on tree connection, reopen resilient handles */ + spin_lock(&tcon->open_file_lock); + list_for_each_safe(tmp, tmp1, &tcon->openFileList) { + open_file = list_entry(tmp, struct cifsFileInfo, tlist); + spin_unlock(&tcon->open_file_lock); + cifs_reopen_file(open_file, false /* do not flush */); + spin_lock(&tcon->open_file_lock); + } + spin_unlock(&tcon->open_file_lock); +} + int cifs_closedir(struct inode *inode, struct file *file) { int rc = 0; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 3eec96ca87d99..4d944c4c55a82 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -250,8 +250,13 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) } cifs_mark_open_files_invalid(tcon); + rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); mutex_unlock(&tcon->ses->session_mutex); + + if (tcon->use_persistent) + cifs_reopen_persistent_handles(tcon); + cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); if (rc) goto out; -- GitLab From 141891f4727c08829755be6c785e125d2e96c899 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 Sep 2016 00:44:16 -0500 Subject: [PATCH 0473/1167] SMB3: Add mount parameter to allow user to override max credits Add mount option "max_credits" to allow setting maximum SMB3 credits to any value from 10 to 64000 (default is 32000). This can be useful to workaround servers with problems allocating credits, or to throttle the client to use smaller amount of simultaneous i/o or to workaround server performance issues. Also adds a cap, so that even if the server granted us more than 65000 credits due to a server bug, we would not use that many. Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 16 +++++++++++++++- fs/cifs/connect.c | 19 ++++++++++++++++--- fs/cifs/smb2glob.h | 10 ---------- fs/cifs/smb2ops.c | 4 ++++ fs/cifs/smb2pdu.c | 4 ++-- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 65f78b7a90620..cd80594f14d0e 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -75,6 +75,18 @@ #define SMB_ECHO_INTERVAL_MAX 600 #define SMB_ECHO_INTERVAL_DEFAULT 60 +/* + * Default number of credits to keep available for SMB3. + * This value is chosen somewhat arbitrarily. The Windows client + * defaults to 128 credits, the Windows server allows clients up to + * 512 credits (or 8K for later versions), and the NetApp server + * does not limit clients at all. Choose a high enough default value + * such that the client shouldn't limit performance, but allow mount + * to override (until you approach 64K, where we limit credits to 65000 + * to reduce possibility of seeing more server credit overflow bugs. + */ +#define SMB2_MAX_CREDITS_AVAILABLE 32000 + #include "cifspdu.h" #ifndef XATTR_DOS_ATTRIB @@ -510,6 +522,7 @@ struct smb_vol { struct sockaddr_storage srcaddr; /* allow binding to a local IP */ struct nls_table *local_nls; unsigned int echo_interval; /* echo interval in secs */ + unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */ }; #define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \ @@ -567,7 +580,8 @@ struct TCP_Server_Info { bool noblocksnd; /* use blocking sendmsg */ bool noautotune; /* do not autotune send buf sizes */ bool tcp_nodelay; - int credits; /* send no more requests at once */ + unsigned int credits; /* send no more requests at once */ + unsigned int max_credits; /* can override large 32000 default at mnt */ unsigned int in_flight; /* number of requests on the wire to server */ spinlock_t req_lock; /* protect the two values above */ struct mutex srv_mutex; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 7b67179521cfc..657369db76dfe 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -63,7 +63,6 @@ extern mempool_t *cifs_req_poolp; #define TLINK_IDLE_EXPIRE (600 * HZ) enum { - /* Mount options that take no arguments */ Opt_user_xattr, Opt_nouser_xattr, Opt_forceuid, Opt_noforceuid, @@ -95,7 +94,7 @@ enum { Opt_cruid, Opt_gid, Opt_file_mode, Opt_dirmode, Opt_port, Opt_rsize, Opt_wsize, Opt_actimeo, - Opt_echo_interval, + Opt_echo_interval, Opt_max_credits, /* Mount options which take string value */ Opt_user, Opt_pass, Opt_ip, @@ -190,6 +189,7 @@ static const match_table_t cifs_mount_option_tokens = { { Opt_wsize, "wsize=%s" }, { Opt_actimeo, "actimeo=%s" }, { Opt_echo_interval, "echo_interval=%s" }, + { Opt_max_credits, "max_credits=%s" }, { Opt_blank_user, "user=" }, { Opt_blank_user, "username=" }, @@ -1586,6 +1586,15 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, } vol->echo_interval = option; break; + case Opt_max_credits: + if (get_option_ul(args, &option) || (option < 20) || + (option > 60000)) { + cifs_dbg(VFS, "%s: Invalid max_credits value\n", + __func__); + goto cifs_parse_mount_err; + } + vol->max_credits = option; + break; /* String Arguments */ @@ -3598,7 +3607,11 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) bdi_destroy(&cifs_sb->bdi); goto out; } - + if ((volume_info->max_credits < 20) || + (volume_info->max_credits > 60000)) + server->max_credits = SMB2_MAX_CREDITS_AVAILABLE; + else + server->max_credits = volume_info->max_credits; /* get a reference to a SMB session */ ses = cifs_get_smb_ses(server, volume_info); if (IS_ERR(ses)) { diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index 238759c146bad..0ffa180943357 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h @@ -61,14 +61,4 @@ /* Maximum buffer size value we can send with 1 credit */ #define SMB2_MAX_BUFFER_SIZE 65536 -/* - * Maximum number of credits to keep available. - * This value is chosen somewhat arbitrarily. The Windows client - * defaults to 128 credits, the Windows server allows clients up to - * 512 credits, and the NetApp server does not limit clients at all. - * Choose a high enough value such that the client shouldn't limit - * performance. - */ -#define SMB2_MAX_CREDITS_AVAILABLE 32000 - #endif /* _SMB2_GLOB_H */ diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 91e53df4e420e..378260cd25a62 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -70,6 +70,10 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, spin_lock(&server->req_lock); val = server->ops->get_credits_field(server, optype); *val += add; + if (*val > 65000) { + *val = 65000; /* Don't get near 64K credits, avoid srv bugs */ + printk_once(KERN_WARNING "server overflowed SMB3 credits\n"); + } server->in_flight--; if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP) rc = change_conf(server); diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 4d944c4c55a82..d6a0456902660 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -105,11 +105,11 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , spin_lock(&server->req_lock); /* Request up to 2 credits but don't go over the limit. */ - if (server->credits >= SMB2_MAX_CREDITS_AVAILABLE) + if (server->credits >= server->max_credits) hdr->CreditRequest = cpu_to_le16(0); else hdr->CreditRequest = cpu_to_le16( - min_t(int, SMB2_MAX_CREDITS_AVAILABLE - + min_t(int, server->max_credits - server->credits, 2)); spin_unlock(&server->req_lock); } else { -- GitLab From 202021c1a63c6ed69b3260e0fe10530c51f1e53e Mon Sep 17 00:00:00 2001 From: Stephen Bates Date: Wed, 5 Oct 2016 20:01:12 -0600 Subject: [PATCH 0474/1167] nvme : Add sysfs entry for NVMe CMBs when appropriate Add a sysfs attribute that contains salient information about the NVMe Controller Memory Buffer when one is present. For now, just display the information about the CMB available from the control registers. We attach the CMB attribute file to the existing nvme_ctrl sysfs group so it can handle the sysfs teardown. Reviewed-by: Sagi Grimberg Reviewed-by: Jay Freyensee Signed-off-by: Stephen Bates Acked-by Jon Derrick: Signed-off-by: Jens Axboe --- drivers/nvme/host/pci.c | 44 ++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 12357d616eebb..a7c6e9d749434 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -99,6 +99,7 @@ struct nvme_dev { dma_addr_t cmb_dma_addr; u64 cmb_size; u32 cmbsz; + u32 cmbloc; struct nvme_ctrl ctrl; struct completion ioq_wait; }; @@ -1330,28 +1331,37 @@ static int nvme_create_io_queues(struct nvme_dev *dev) return ret >= 0 ? 0 : ret; } +static ssize_t nvme_cmb_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct nvme_dev *ndev = to_nvme_dev(dev_get_drvdata(dev)); + + return snprintf(buf, PAGE_SIZE, "cmbloc : x%08x\ncmbsz : x%08x\n", + ndev->cmbloc, ndev->cmbsz); +} +static DEVICE_ATTR(cmb, S_IRUGO, nvme_cmb_show, NULL); + static void __iomem *nvme_map_cmb(struct nvme_dev *dev) { u64 szu, size, offset; - u32 cmbloc; resource_size_t bar_size; struct pci_dev *pdev = to_pci_dev(dev->dev); void __iomem *cmb; dma_addr_t dma_addr; - if (!use_cmb_sqes) - return NULL; - dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ); if (!(NVME_CMB_SZ(dev->cmbsz))) return NULL; + dev->cmbloc = readl(dev->bar + NVME_REG_CMBLOC); - cmbloc = readl(dev->bar + NVME_REG_CMBLOC); + if (!use_cmb_sqes) + return NULL; szu = (u64)1 << (12 + 4 * NVME_CMB_SZU(dev->cmbsz)); size = szu * NVME_CMB_SZ(dev->cmbsz); - offset = szu * NVME_CMB_OFST(cmbloc); - bar_size = pci_resource_len(pdev, NVME_CMB_BIR(cmbloc)); + offset = szu * NVME_CMB_OFST(dev->cmbloc); + bar_size = pci_resource_len(pdev, NVME_CMB_BIR(dev->cmbloc)); if (offset > bar_size) return NULL; @@ -1364,7 +1374,7 @@ static void __iomem *nvme_map_cmb(struct nvme_dev *dev) if (size > bar_size - offset) size = bar_size - offset; - dma_addr = pci_resource_start(pdev, NVME_CMB_BIR(cmbloc)) + offset; + dma_addr = pci_resource_start(pdev, NVME_CMB_BIR(dev->cmbloc)) + offset; cmb = ioremap_wc(dma_addr, size); if (!cmb) return NULL; @@ -1615,9 +1625,25 @@ static int nvme_pci_enable(struct nvme_dev *dev) dev->q_depth); } - if (readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 2)) + /* + * CMBs can currently only exist on >=1.2 PCIe devices. We only + * populate sysfs if a CMB is implemented. Note that we add the + * CMB attribute to the nvme_ctrl kobj which removes the need to remove + * it on exit. Since nvme_dev_attrs_group has no name we can pass + * NULL as final argument to sysfs_add_file_to_group. + */ + + if (readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 2)) { dev->cmb = nvme_map_cmb(dev); + if (dev->cmbsz) { + if (sysfs_add_file_to_group(&dev->ctrl.device->kobj, + &dev_attr_cmb.attr, NULL)) + dev_warn(dev->dev, + "failed to add sysfs attribute for CMB\n"); + } + } + pci_enable_pcie_error_reporting(pdev); pci_save_state(pdev); return 0; -- GitLab From 4875a5f7218068cdeea5f998330dfa3d118b2fea Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Tue, 11 Oct 2016 10:48:58 +0800 Subject: [PATCH 0475/1167] ALSA: hda - Fix a failure of micmute led when having multi adcs On a Dell laptop, there is no global adcs for all input devices, so the input devices use the different adc, as a result, dyn_adc_switch is set to true. In this situation, it is safe to control the micmute led according to user's choice of muting/unmuting the current input device, since only current input device path is active, while other input device paths are inactive and powered down. Fixes: 00ef99408b6c ('ALSA: hda - add mic mute led hook for dell machines') Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/dell_wmi_helper.c | 2 +- sound/pci/hda/thinkpad_helper.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/dell_wmi_helper.c b/sound/pci/hda/dell_wmi_helper.c index 9c22f95838efb..19d41da79f93c 100644 --- a/sound/pci/hda/dell_wmi_helper.c +++ b/sound/pci/hda/dell_wmi_helper.c @@ -49,7 +49,7 @@ static void alc_fixup_dell_wmi(struct hda_codec *codec, removefunc = true; if (dell_led_set_func(DELL_LED_MICMUTE, false) >= 0) { dell_led_value = 0; - if (spec->gen.num_adc_nids > 1) + if (spec->gen.num_adc_nids > 1 && !spec->gen.dyn_adc_switch) codec_dbg(codec, "Skipping micmute LED control due to several ADCs"); else { dell_old_cap_hook = spec->gen.cap_sync_hook; diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c index f0955fd7a2e73..6a23302297c9c 100644 --- a/sound/pci/hda/thinkpad_helper.c +++ b/sound/pci/hda/thinkpad_helper.c @@ -62,7 +62,7 @@ static void hda_fixup_thinkpad_acpi(struct hda_codec *codec, removefunc = false; } if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) { - if (spec->num_adc_nids > 1) + if (spec->num_adc_nids > 1 && !spec->dyn_adc_switch) codec_dbg(codec, "Skipping micmute LED control due to several ADCs"); else { -- GitLab From 30c0702246ac1ba955aa97d698610169242f59f1 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 12 Oct 2016 09:05:50 +0900 Subject: [PATCH 0476/1167] ALSA: seq: fix passing wrong pointer in function call of compatibility layer This commit is a fix for Linux 4.9-rc1. In former commit, a function call of compatibility layer for ALSA sequencer core was obsoleted by an alternative. Although, the alternative gets a pointer to kernel stack due to mis-programming. As a result, ALSA sequencer core unexpectedly refers over kernel stack. Reported-by: Dan Carpenter Fixes: 8ce8eb601c71 ("ALSA: seq: add an alternative way to handle ioctl requests") Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/seq/seq_compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c index fce5697e42614..8c35072166769 100644 --- a/sound/core/seq/seq_compat.c +++ b/sound/core/seq/seq_compat.c @@ -58,7 +58,7 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned goto error; data->kernel = NULL; - err = snd_seq_kernel_client_ctl(client->number, cmd, &data); + err = snd_seq_kernel_client_ctl(client->number, cmd, data); if (err < 0) goto error; -- GitLab From fdd8218d7d1bd0ccb9a3f4c58bf77773691a56cc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2016 09:21:40 +0300 Subject: [PATCH 0477/1167] ALSA: line6: fix a crash in line6_hwdep_write() The error checking here is messed up so we could end up dereferencing -EFAULT. Fixes: a16039cbf1a1 ('ALSA: line6: Add hwdep interface to access the POD control messages') Signed-off-by: Dan Carpenter Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index 14e587e706554..90009c0b3a92e 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -604,8 +604,8 @@ line6_hwdep_write(struct snd_hwdep *hwdep, const char __user *data, long count, } data_copy = memdup_user(data, count); - if (IS_ERR(ERR_PTR)) - return -ENOMEM; + if (IS_ERR(data_copy)) + return PTR_ERR(data_copy); rv = line6_send_raw_message(line6, data_copy, count); -- GitLab From 0843e83c1a4aa67e08f424430526c948d591d5f1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Oct 2016 14:07:51 +0200 Subject: [PATCH 0478/1167] cpufreq: intel_pstate: Proportional algorithm for Atom The PID algorithm used by the intel_pstate driver tends to drive performance to the minimum for workloads with utilization below the setpoint, which is undesirable, so replace it with a modified "proportional" algorithm on Atom. The new algorithm will set the new P-state to be 1.25 times the available maximum times the (frequency-invariant) utilization during the previous sampling period except when the target P-state computed this way is lower than the average P-state during the previous sampling period. In the latter case, it will increase the target by 50% of the difference between it and the average P-state to prevent performance from dropping down too fast in some cases. Signed-off-by: Rafael J. Wysocki Tested-by: Srinivas Pandruvada --- drivers/cpufreq/intel_pstate.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 1c7b91c5805bd..6c8c897d0a2dc 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1232,6 +1232,7 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu) { struct sample *sample = &cpu->sample; int32_t busy_frac, boost; + int target, avg_pstate; busy_frac = div_fp(sample->mperf, sample->tsc); @@ -1242,7 +1243,26 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu) busy_frac = boost; sample->busy_scaled = busy_frac * 100; - return get_avg_pstate(cpu) - pid_calc(&cpu->pid, sample->busy_scaled); + + target = limits->no_turbo || limits->turbo_disabled ? + cpu->pstate.max_pstate : cpu->pstate.turbo_pstate; + target += target >> 2; + target = mul_fp(target, busy_frac); + if (target < cpu->pstate.min_pstate) + target = cpu->pstate.min_pstate; + + /* + * If the average P-state during the previous cycle was higher than the + * current target, add 50% of the difference to the target to reduce + * possible performance oscillations and offset possible performance + * loss related to moving the workload from one CPU to another within + * a package/module. + */ + avg_pstate = get_avg_pstate(cpu); + if (avg_pstate > target) + target += (avg_pstate - target) >> 1; + + return target; } static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu) -- GitLab From 3954517e2f083c8aeb52bfd467b7b2c164232ffc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 11 Oct 2016 23:07:38 +0200 Subject: [PATCH 0479/1167] cpufreq: intel_pstate: Fix struct pstate_adjust_policy kerneldoc It looks like the name of struct pstate_adjust_policy was updated without updating its kerneldoc comment accordingly, so fix that mistake. Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 6c8c897d0a2dc..f535f81232584 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -225,7 +225,7 @@ struct cpudata { static struct cpudata **all_cpu_data; /** - * struct pid_adjust_policy - Stores static PID configuration data + * struct pstate_adjust_policy - Stores static PID configuration data * @sample_rate_ms: PID calculation sample rate in ms * @sample_rate_ns: Sample rate calculation in ns * @deadband: PID deadband -- GitLab From 899bb6642f2a2f2cd3f77abd6c5a14550e3b37e6 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 12 Oct 2016 08:45:05 +0530 Subject: [PATCH 0480/1167] cpufreq: skip invalid entries when searching the frequency Skip invalid entries when searching the frequency. This fixes cpufreq at least on loongson2 MIPS board. Fixes: da0c6dc00c69 (cpufreq: Handle sorted frequency tables more efficiently) Signed-off-by: Aaro Koskinen Signed-off-by: Viresh Kumar Cc: 4.8+ # 4.8+ Signed-off-by: Rafael J. Wysocki --- include/linux/cpufreq.h | 104 ++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 631ba33bbe9fd..5fa55fc56e18d 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -639,19 +639,19 @@ static inline int cpufreq_table_find_index_al(struct cpufreq_policy *policy, unsigned int target_freq) { struct cpufreq_frequency_table *table = policy->freq_table; + struct cpufreq_frequency_table *pos, *best = table - 1; unsigned int freq; - int i, best = -1; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - freq = table[i].frequency; + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; if (freq >= target_freq) - return i; + return pos - table; - best = i; + best = pos; } - return best; + return best - table; } /* Find lowest freq at or above target in a table in descending order */ @@ -659,28 +659,28 @@ static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy, unsigned int target_freq) { struct cpufreq_frequency_table *table = policy->freq_table; + struct cpufreq_frequency_table *pos, *best = table - 1; unsigned int freq; - int i, best = -1; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - freq = table[i].frequency; + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; if (freq == target_freq) - return i; + return pos - table; if (freq > target_freq) { - best = i; + best = pos; continue; } /* No freq found above target_freq */ - if (best == -1) - return i; + if (best == table - 1) + return pos - table; - return best; + return best - pos; } - return best; + return best - pos; } /* Works only on sorted freq-tables */ @@ -700,28 +700,28 @@ static inline int cpufreq_table_find_index_ah(struct cpufreq_policy *policy, unsigned int target_freq) { struct cpufreq_frequency_table *table = policy->freq_table; + struct cpufreq_frequency_table *pos, *best = table - 1; unsigned int freq; - int i, best = -1; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - freq = table[i].frequency; + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; if (freq == target_freq) - return i; + return pos - table; if (freq < target_freq) { - best = i; + best = pos; continue; } /* No freq found below target_freq */ - if (best == -1) - return i; + if (best == table - 1) + return pos - table; - return best; + return best - table; } - return best; + return best - table; } /* Find highest freq at or below target in a table in descending order */ @@ -729,19 +729,19 @@ static inline int cpufreq_table_find_index_dh(struct cpufreq_policy *policy, unsigned int target_freq) { struct cpufreq_frequency_table *table = policy->freq_table; + struct cpufreq_frequency_table *pos, *best = table - 1; unsigned int freq; - int i, best = -1; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - freq = table[i].frequency; + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; if (freq <= target_freq) - return i; + return pos - table; - best = i; + best = pos; } - return best; + return best - table; } /* Works only on sorted freq-tables */ @@ -761,32 +761,32 @@ static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy, unsigned int target_freq) { struct cpufreq_frequency_table *table = policy->freq_table; + struct cpufreq_frequency_table *pos, *best = table - 1; unsigned int freq; - int i, best = -1; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - freq = table[i].frequency; + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; if (freq == target_freq) - return i; + return pos - table; if (freq < target_freq) { - best = i; + best = pos; continue; } /* No freq found below target_freq */ - if (best == -1) - return i; + if (best == table - 1) + return pos - table; /* Choose the closest freq */ - if (target_freq - table[best].frequency > freq - target_freq) - return i; + if (target_freq - best->frequency > freq - target_freq) + return pos - table; - return best; + return best - table; } - return best; + return best - table; } /* Find closest freq to target in a table in descending order */ @@ -794,32 +794,32 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy, unsigned int target_freq) { struct cpufreq_frequency_table *table = policy->freq_table; + struct cpufreq_frequency_table *pos, *best = table - 1; unsigned int freq; - int i, best = -1; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - freq = table[i].frequency; + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; if (freq == target_freq) - return i; + return pos - table; if (freq > target_freq) { - best = i; + best = pos; continue; } /* No freq found above target_freq */ - if (best == -1) - return i; + if (best == table - 1) + return pos - table; /* Choose the closest freq */ - if (table[best].frequency - target_freq > target_freq - freq) - return i; + if (best->frequency - target_freq > target_freq - freq) + return pos - table; - return best; + return best - table; } - return best; + return best - table; } /* Works only on sorted freq-tables */ -- GitLab From e311404f7925f6879817ebf471651c0bb5935604 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 12 Oct 2016 13:11:45 +0200 Subject: [PATCH 0481/1167] ACPI / PAD: don't register acpi_pad driver if running as Xen dom0 When running as Xen dom0 a special processor_aggregator driver is needed. Don't register the standard driver in this case. Without that check an error message: "Error: Driver 'processor_aggregator' is already registered, aborting..." will be displayed. Signed-off-by: Juergen Gross [ rjw: Minor fixups ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_pad.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 8ea8211b2d589..eb76a4c10dbfb 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -26,6 +26,7 @@ #include #include #include +#include #define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad" #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator" @@ -477,6 +478,10 @@ static struct acpi_driver acpi_pad_driver = { static int __init acpi_pad_init(void) { + /* Xen ACPI PAD is used when running as Xen Dom0. */ + if (xen_initial_domain()) + return -ENODEV; + power_saving_mwait_init(); if (power_saving_mwait_eax == 0) return -EINVAL; -- GitLab From 40492f60794aaf32576cb42d9af86eed785a6e63 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Sun, 9 Oct 2016 20:28:19 +0300 Subject: [PATCH 0482/1167] drm/amdgpu: use .early_unregister hook to remove DP AUX i2c When DisplayPort AUX channel i2c adapter is registered, drm_connector's kdev member is used as a parent, so we get sysfs structure like: /drm/card1/card1-DP-2/i2c-12 Because of that, there is a problem when drm core (and not the driver) calls drm_connector_unregister(), it removes parent sysfs entries ('card1-DP-2' in our example) while the i2c adapter is still registered. Later we get a WARN when we try to unregister the i2c adapter: WARNING: CPU: 3 PID: 1374 at fs/sysfs/group.c:243 sysfs_remove_group+0x14c/0x150 sysfs group ffffffff82911e40 not found for kobject 'i2c-12' To fix it, we can use the .early_unregister hook to unregister the i2c adapter before drm_connector's sysfs is torn down. Signed-off-by: Grazvydas Ignotas Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 2e3a0543760d0..e3281d4e3e414 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -765,7 +765,7 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) return ret; } -static void amdgpu_connector_destroy(struct drm_connector *connector) +static void amdgpu_connector_unregister(struct drm_connector *connector) { struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); @@ -773,6 +773,12 @@ static void amdgpu_connector_destroy(struct drm_connector *connector) drm_dp_aux_unregister(&amdgpu_connector->ddc_bus->aux); amdgpu_connector->ddc_bus->has_aux = false; } +} + +static void amdgpu_connector_destroy(struct drm_connector *connector) +{ + struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); + amdgpu_connector_free_edid(connector); kfree(amdgpu_connector->con_priv); drm_connector_unregister(connector); @@ -826,6 +832,7 @@ static const struct drm_connector_funcs amdgpu_connector_lvds_funcs = { .dpms = drm_helper_connector_dpms, .detect = amdgpu_connector_lvds_detect, .fill_modes = drm_helper_probe_single_connector_modes, + .early_unregister = amdgpu_connector_unregister, .destroy = amdgpu_connector_destroy, .set_property = amdgpu_connector_set_lcd_property, }; @@ -936,6 +943,7 @@ static const struct drm_connector_funcs amdgpu_connector_vga_funcs = { .dpms = drm_helper_connector_dpms, .detect = amdgpu_connector_vga_detect, .fill_modes = drm_helper_probe_single_connector_modes, + .early_unregister = amdgpu_connector_unregister, .destroy = amdgpu_connector_destroy, .set_property = amdgpu_connector_set_property, }; @@ -1203,6 +1211,7 @@ static const struct drm_connector_funcs amdgpu_connector_dvi_funcs = { .detect = amdgpu_connector_dvi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = amdgpu_connector_set_property, + .early_unregister = amdgpu_connector_unregister, .destroy = amdgpu_connector_destroy, .force = amdgpu_connector_dvi_force, }; @@ -1493,6 +1502,7 @@ static const struct drm_connector_funcs amdgpu_connector_dp_funcs = { .detect = amdgpu_connector_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = amdgpu_connector_set_property, + .early_unregister = amdgpu_connector_unregister, .destroy = amdgpu_connector_destroy, .force = amdgpu_connector_dvi_force, }; @@ -1502,6 +1512,7 @@ static const struct drm_connector_funcs amdgpu_connector_edp_funcs = { .detect = amdgpu_connector_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = amdgpu_connector_set_lcd_property, + .early_unregister = amdgpu_connector_unregister, .destroy = amdgpu_connector_destroy, .force = amdgpu_connector_dvi_force, }; -- GitLab From b0c80bd5d2e317f7596fe2badc1a3379fb3211e5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 11 Oct 2016 10:44:24 -0400 Subject: [PATCH 0483/1167] drm/radeon: fix up dp aux tear down (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port the amdgpu fixes from Grazvydas to radeon. v2: drop unrelated whitespace change. bug: https://bugs.freedesktop.org/show_bug.cgi?id=98200 Reviewed-and-Tested-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_connectors.c | 17 +++++++++++++++++ drivers/gpu/drm/radeon/radeon_i2c.c | 3 +-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 50e96d2c593da..e18839d52e3e9 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -927,6 +927,16 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) return ret; } +static void radeon_connector_unregister(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (radeon_connector->ddc_bus->has_aux) { + drm_dp_aux_unregister(&radeon_connector->ddc_bus->aux); + radeon_connector->ddc_bus->has_aux = false; + } +} + static void radeon_connector_destroy(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -984,6 +994,7 @@ static const struct drm_connector_funcs radeon_lvds_connector_funcs = { .dpms = drm_helper_connector_dpms, .detect = radeon_lvds_detect, .fill_modes = drm_helper_probe_single_connector_modes, + .early_unregister = radeon_connector_unregister, .destroy = radeon_connector_destroy, .set_property = radeon_lvds_set_property, }; @@ -1111,6 +1122,7 @@ static const struct drm_connector_funcs radeon_vga_connector_funcs = { .dpms = drm_helper_connector_dpms, .detect = radeon_vga_detect, .fill_modes = drm_helper_probe_single_connector_modes, + .early_unregister = radeon_connector_unregister, .destroy = radeon_connector_destroy, .set_property = radeon_connector_set_property, }; @@ -1188,6 +1200,7 @@ static const struct drm_connector_funcs radeon_tv_connector_funcs = { .dpms = drm_helper_connector_dpms, .detect = radeon_tv_detect, .fill_modes = drm_helper_probe_single_connector_modes, + .early_unregister = radeon_connector_unregister, .destroy = radeon_connector_destroy, .set_property = radeon_connector_set_property, }; @@ -1519,6 +1532,7 @@ static const struct drm_connector_funcs radeon_dvi_connector_funcs = { .detect = radeon_dvi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_connector_set_property, + .early_unregister = radeon_connector_unregister, .destroy = radeon_connector_destroy, .force = radeon_dvi_force, }; @@ -1832,6 +1846,7 @@ static const struct drm_connector_funcs radeon_dp_connector_funcs = { .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_connector_set_property, + .early_unregister = radeon_connector_unregister, .destroy = radeon_connector_destroy, .force = radeon_dvi_force, }; @@ -1841,6 +1856,7 @@ static const struct drm_connector_funcs radeon_edp_connector_funcs = { .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_lvds_set_property, + .early_unregister = radeon_connector_unregister, .destroy = radeon_connector_destroy, .force = radeon_dvi_force, }; @@ -1850,6 +1866,7 @@ static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = { .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_lvds_set_property, + .early_unregister = radeon_connector_unregister, .destroy = radeon_connector_destroy, .force = radeon_dvi_force, }; diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 021aa005623f8..29f7817af821b 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -982,9 +982,8 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) { if (!i2c) return; + WARN_ON(i2c->has_aux); i2c_del_adapter(&i2c->adapter); - if (i2c->has_aux) - drm_dp_aux_unregister(&i2c->aux); kfree(i2c); } -- GitLab From 9305ee6fe52035f63d70d023235b792ba22107f0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 11 Oct 2016 10:57:39 -0400 Subject: [PATCH 0484/1167] drm/radeon: fix modeset tear down code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ordering caused problems. bug: https://bugs.freedesktop.org/show_bug.cgi?id=98200 Reviewed-and-Tested-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_display.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index b8ab30a7dd6d2..cdb8cb568c153 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1675,20 +1675,20 @@ int radeon_modeset_init(struct radeon_device *rdev) void radeon_modeset_fini(struct radeon_device *rdev) { - radeon_fbdev_fini(rdev); - kfree(rdev->mode_info.bios_hardcoded_edid); - - /* free i2c buses */ - radeon_i2c_fini(rdev); - if (rdev->mode_info.mode_config_initialized) { - radeon_afmt_fini(rdev); drm_kms_helper_poll_fini(rdev->ddev); radeon_hpd_fini(rdev); drm_crtc_force_disable_all(rdev->ddev); + radeon_fbdev_fini(rdev); + radeon_afmt_fini(rdev); drm_mode_config_cleanup(rdev->ddev); rdev->mode_info.mode_config_initialized = false; } + + kfree(rdev->mode_info.bios_hardcoded_edid); + + /* free i2c buses */ + radeon_i2c_fini(rdev); } static bool is_hdtv_mode(const struct drm_display_mode *mode) -- GitLab From 6ae81452f9278ba1accdd4152d75061a8349a0f3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 7 Oct 2016 16:00:47 -0400 Subject: [PATCH 0485/1167] drm/amdgpu/gfx8: fix CGCG_CGLS handling When setting up the RLC, only disable the CGCG and CGLS bits rather than clearing the entire register to avoid losing the golden settings. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 6c6ff57b1c95f..5b289186dc92f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -4087,14 +4087,21 @@ static int gfx_v8_0_rlc_load_microcode(struct amdgpu_device *adev) static int gfx_v8_0_rlc_resume(struct amdgpu_device *adev) { int r; + u32 tmp; gfx_v8_0_rlc_stop(adev); /* disable CG */ - WREG32(mmRLC_CGCG_CGLS_CTRL, 0); + tmp = RREG32(mmRLC_CGCG_CGLS_CTRL); + tmp &= ~(RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK | + RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK); + WREG32(mmRLC_CGCG_CGLS_CTRL, tmp); if (adev->asic_type == CHIP_POLARIS11 || - adev->asic_type == CHIP_POLARIS10) - WREG32(mmRLC_CGCG_CGLS_CTRL_3D, 0); + adev->asic_type == CHIP_POLARIS10) { + tmp = RREG32(mmRLC_CGCG_CGLS_CTRL_3D); + tmp &= ~0x3; + WREG32(mmRLC_CGCG_CGLS_CTRL_3D, tmp); + } /* disable PG */ WREG32(mmRLC_PG_CNTL, 0); -- GitLab From ce199ad690bd0a6ac6bf9e4df2c87b59d76f84da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolai=20H=C3=A4hnle?= Date: Tue, 4 Oct 2016 09:43:30 +0200 Subject: [PATCH 0486/1167] drm/amdgpu: initialize the context reset_counter in amdgpu_ctx_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure that we really only report a GPU reset if one has happened since the creation of the context. Signed-off-by: Nicolai Hähnle Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index e203e55611071..a5e2fcbef0f0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -43,6 +43,9 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev, struct amdgpu_ctx *ctx) ctx->rings[i].sequence = 1; ctx->rings[i].fences = &ctx->fences[amdgpu_sched_jobs * i]; } + + ctx->reset_counter = atomic_read(&adev->gpu_reset_counter); + /* create context entity for each ring */ for (i = 0; i < adev->num_rings; i++) { struct amdgpu_ring *ring = adev->rings[i]; -- GitLab From 113d0f9db7be5a3038d9800ea1dddfb373c2b5a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Mon, 10 Oct 2016 13:23:25 +0200 Subject: [PATCH 0487/1167] drm/radeon: allow TA_CS_BC_BASE_ADDR on SI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Required for border colors in compute shaders. Reviewed-by: Edward O'Callaghan Reviewed-by: Alex Deucher Reviewed-by: Christian König Signed-off-by: Marek Olšák Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_drv.c | 3 ++- drivers/gpu/drm/radeon/si.c | 1 + drivers/gpu/drm/radeon/sid.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 91c8f43395660..00ea0002b539b 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -96,9 +96,10 @@ * 2.45.0 - Allow setting shader registers using DMA/COPY packet3 on SI * 2.46.0 - Add PFP_SYNC_ME support on evergreen * 2.47.0 - Add UVD_NO_OP register support + * 2.48.0 - TA_CS_BC_BASE_ADDR allowed on SI */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 47 +#define KMS_DRIVER_MINOR 48 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 7ee9aafbdf744..e402be8821c45 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -4431,6 +4431,7 @@ static bool si_vm_reg_valid(u32 reg) case SPI_CONFIG_CNTL: case SPI_CONFIG_CNTL_1: case TA_CNTL_AUX: + case TA_CS_BC_BASE_ADDR: return true; default: DRM_ERROR("Invalid register 0x%x in CS\n", reg); diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index eb220eecba789..65a911ddd509d 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -1145,6 +1145,7 @@ #define SPI_LB_CU_MASK 0x9354 #define TA_CNTL_AUX 0x9508 +#define TA_CS_BC_BASE_ADDR 0x950C #define CC_RB_BACKEND_DISABLE 0x98F4 #define BACKEND_DISABLE(x) ((x) << 16) -- GitLab From b0b00ff16f2715562b7ea0dfa3a9c5b33328c8cb Mon Sep 17 00:00:00 2001 From: Arindam Nath Date: Fri, 7 Oct 2016 19:01:37 +0530 Subject: [PATCH 0488/1167] drm/amd/amdgpu: enable clockgating only after late init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes during multiple reboots, the system hangs during bootup. The issue is very random and happens once in around 50 reboots or so. It seems if clockgating is enabled before late init, the GFX engine sometimes does not respond. This patch changes the ordering a little so that both powergating and clockgating are enabled only after late init calls. Reviewed-by: Christian König Signed-off-by: Arindam Nath Tested-by: Sunil Uttarwar Reviewed-by: Tom St Denis Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index a58513f271e3f..928774f5a7e0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1411,13 +1411,6 @@ static int amdgpu_late_init(struct amdgpu_device *adev) if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_UVD || adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_VCE) continue; - /* enable clockgating to save power */ - r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev, - AMD_CG_STATE_GATE); - if (r) { - DRM_ERROR("set_clockgating_state(gate) of IP block <%s> failed %d\n", adev->ip_blocks[i].funcs->name, r); - return r; - } if (adev->ip_blocks[i].funcs->late_init) { r = adev->ip_blocks[i].funcs->late_init((void *)adev); if (r) { @@ -1426,6 +1419,13 @@ static int amdgpu_late_init(struct amdgpu_device *adev) } adev->ip_block_status[i].late_initialized = true; } + /* enable clockgating to save power */ + r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev, + AMD_CG_STATE_GATE); + if (r) { + DRM_ERROR("set_clockgating_state(gate) of IP block <%s> failed %d\n", adev->ip_blocks[i].funcs->name, r); + return r; + } } return 0; -- GitLab From 4a446d55843fb82fc5bc6c72d27bfc20b6c294c3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 7 Oct 2016 14:48:18 -0400 Subject: [PATCH 0489/1167] drm/amdgpu: clarify UVD/VCE special handling for CG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UVD and VCE CG are handled specially, however the previous fix for this skipped late init for those blocks rather than just CG. Just protect the CG function call. No functional change since UVD and VCE don't currently utilize a late_init function. Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 928774f5a7e0f..15afe22ca8909 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1408,9 +1408,6 @@ static int amdgpu_late_init(struct amdgpu_device *adev) for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_block_status[i].valid) continue; - if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_UVD || - adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_VCE) - continue; if (adev->ip_blocks[i].funcs->late_init) { r = adev->ip_blocks[i].funcs->late_init((void *)adev); if (r) { @@ -1419,12 +1416,17 @@ static int amdgpu_late_init(struct amdgpu_device *adev) } adev->ip_block_status[i].late_initialized = true; } - /* enable clockgating to save power */ - r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev, - AMD_CG_STATE_GATE); - if (r) { - DRM_ERROR("set_clockgating_state(gate) of IP block <%s> failed %d\n", adev->ip_blocks[i].funcs->name, r); - return r; + /* skip CG for VCE/UVD, it's handled specially */ + if (adev->ip_blocks[i].type != AMD_IP_BLOCK_TYPE_UVD && + adev->ip_blocks[i].type != AMD_IP_BLOCK_TYPE_VCE) { + /* enable clockgating to save power */ + r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev, + AMD_CG_STATE_GATE); + if (r) { + DRM_ERROR("set_clockgating_state(gate) of IP block <%s> failed %d\n", + adev->ip_blocks[i].funcs->name, r); + return r; + } } } -- GitLab From abc4b9a53ea8153e0e028762b22cb213685c52e3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Oct 2016 11:50:34 -0700 Subject: [PATCH 0490/1167] acpi_os_vprintf: Use printk_get_level() to avoid unnecessary KERN_CONT acpi_os_vprintf currently always uses a KERN_CONT prefix which may be followed immediately by a proper KERN_. Check if the buffer already has a KERN_ at the start of the buffer and avoid the unnecessary KERN_CONT. Signed-off-by: Joe Perches Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 4305ee9db4b2d..416953a425109 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -162,11 +162,18 @@ void acpi_os_vprintf(const char *fmt, va_list args) if (acpi_in_debugger) { kdb_printf("%s", buffer); } else { - printk(KERN_CONT "%s", buffer); + if (printk_get_level(buffer)) + printk("%s", buffer); + else + printk(KERN_CONT "%s", buffer); } #else - if (acpi_debugger_write_log(buffer) < 0) - printk(KERN_CONT "%s", buffer); + if (acpi_debugger_write_log(buffer) < 0) { + if (printk_get_level(buffer)) + printk("%s", buffer); + else + printk(KERN_CONT "%s", buffer); + } #endif } -- GitLab From ea893695ec1131a5fed0523ff8094bc6e8723bbe Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 12 Oct 2016 21:31:40 +0200 Subject: [PATCH 0491/1167] platform/x86: asus-wmi: add SERIO_I8042 dependency A recent bugfix added a call to i8042_install_filter but did not add the dependency, leading to possible link errors: drivers/platform/built-in.o: In function `asus_nb_wmi_quirks': asus-nb-wmi.c:(.text+0x23af): undefined reference to `i8042_install_filter' This adds a dependency on SERIO_I8042||SERIO_I8042=n to indicate that we can build the driver when the i8042 driver is disabled, but it cannot be built-in when that is a loadable module. Fixes: b5643539b825 ("platform/x86: asus-wmi: Filter buggy scan codes on ASUS Q500A") Signed-off-by: Arnd Bergmann Signed-off-by: Darren Hart --- drivers/platform/x86/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 81b8dcca8891d..b8a21d7b25d4c 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -576,6 +576,7 @@ config ASUS_WMI config ASUS_NB_WMI tristate "Asus Notebook WMI Driver" depends on ASUS_WMI + depends on SERIO_I8042 || SERIO_I8042 = n ---help--- This is a driver for newer Asus notebooks. It adds extra features like wireless radio and bluetooth control, leds, hotkeys, backlight... -- GitLab From de0dcc40f6e24d6bac6b60e36eac4659bbbd3f00 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 12 Oct 2016 13:38:41 -0700 Subject: [PATCH 0492/1167] f2fs: fix wrong sum_page pointer in f2fs_gc This patch fixes using a wrong pointer for sum_page in f2fs_gc. Signed-off-by: Jaegeuk Kim --- fs/f2fs/gc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 93985c64d8a8b..6f14ee923acd2 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -852,16 +852,16 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, for (segno = start_segno; segno < end_segno; segno++) { - if (get_valid_blocks(sbi, segno, 1) == 0 || - unlikely(f2fs_cp_error(sbi))) - goto next; - /* find segment summary of victim */ sum_page = find_get_page(META_MAPPING(sbi), GET_SUM_BLOCK(sbi, segno)); - f2fs_bug_on(sbi, !PageUptodate(sum_page)); f2fs_put_page(sum_page, 0); + if (get_valid_blocks(sbi, segno, 1) == 0 || + !PageUptodate(sum_page) || + unlikely(f2fs_cp_error(sbi))) + goto next; + sum = page_address(sum_page); f2fs_bug_on(sbi, type != GET_SUM_TYPE((&sum->footer))); -- GitLab From 651e1c3b1576c5ffda6df01db1ef535eeb8b1a37 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Oct 2016 23:12:53 -0400 Subject: [PATCH 0493/1167] ext4: super.c: Update logging style using KERN_CONT Recent commit require line continuing printks to use PR_CONT. Update super.c to use KERN_CONT and use vsprintf extension %pV to avoid a printk/vprintk/printk("\n") sequence as well. Signed-off-by: Joe Perches Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara --- fs/ext4/super.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 6db81fbcbaa6c..20da99da0a343 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -597,14 +597,15 @@ void __ext4_std_error(struct super_block *sb, const char *function, void __ext4_abort(struct super_block *sb, const char *function, unsigned int line, const char *fmt, ...) { + struct va_format vaf; va_list args; save_error_info(sb, function, line); va_start(args, fmt); - printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: ", sb->s_id, - function, line); - vprintk(fmt, args); - printk("\n"); + vaf.fmt = fmt; + vaf.va = &args; + printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: %pV\n", + sb->s_id, function, line, &vaf); va_end(args); if ((sb->s_flags & MS_RDONLY) == 0) { @@ -2715,12 +2716,12 @@ static void print_daily_error_info(unsigned long arg) es->s_first_error_func, le32_to_cpu(es->s_first_error_line)); if (es->s_first_error_ino) - printk(": inode %u", + printk(KERN_CONT ": inode %u", le32_to_cpu(es->s_first_error_ino)); if (es->s_first_error_block) - printk(": block %llu", (unsigned long long) + printk(KERN_CONT ": block %llu", (unsigned long long) le64_to_cpu(es->s_first_error_block)); - printk("\n"); + printk(KERN_CONT "\n"); } if (es->s_last_error_time) { printk(KERN_NOTICE "EXT4-fs (%s): last error at time %u: %.*s:%d", @@ -2729,12 +2730,12 @@ static void print_daily_error_info(unsigned long arg) es->s_last_error_func, le32_to_cpu(es->s_last_error_line)); if (es->s_last_error_ino) - printk(": inode %u", + printk(KERN_CONT ": inode %u", le32_to_cpu(es->s_last_error_ino)); if (es->s_last_error_block) - printk(": block %llu", (unsigned long long) + printk(KERN_CONT ": block %llu", (unsigned long long) le64_to_cpu(es->s_last_error_block)); - printk("\n"); + printk(KERN_CONT "\n"); } mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ); /* Once a day */ } -- GitLab From 559cce698eaf4ccecb2213b2519ea3a0413e5155 Mon Sep 17 00:00:00 2001 From: Taesoo Kim Date: Wed, 12 Oct 2016 23:19:18 -0400 Subject: [PATCH 0494/1167] jbd2: fix incorrect unlock on j_list_lock When 'jh->b_transaction == transaction' (asserted by below) J_ASSERT_JH(jh, (jh->b_transaction == transaction || ... 'journal->j_list_lock' will be incorrectly unlocked, since the the lock is aquired only at the end of if / else-if statements (missing the else case). Signed-off-by: Taesoo Kim Signed-off-by: Theodore Ts'o Reviewed-by: Andreas Dilger Fixes: 6e4862a5bb9d12be87e4ea5d9a60836ebed71d28 Cc: stable@vger.kernel.org # 3.14+ --- fs/jbd2/transaction.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 3d8246a9faa45..e1652665bd93d 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1149,6 +1149,7 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) JBUFFER_TRACE(jh, "file as BJ_Reserved"); spin_lock(&journal->j_list_lock); __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); + spin_unlock(&journal->j_list_lock); } else if (jh->b_transaction == journal->j_committing_transaction) { /* first access by this transaction */ jh->b_modified = 0; @@ -1156,8 +1157,8 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) JBUFFER_TRACE(jh, "set next transaction"); spin_lock(&journal->j_list_lock); jh->b_next_transaction = transaction; + spin_unlock(&journal->j_list_lock); } - spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); /* -- GitLab From c4704a4fbe834eee4109ca064131d440941f6235 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 12 Oct 2016 23:24:51 -0400 Subject: [PATCH 0495/1167] ext4: do not advertise encryption support when disabled The sysfs file /sys/fs/ext4/features/encryption was present on kernels compiled with CONFIG_EXT4_FS_ENCRYPTION=n. This was misleading because such kernels do not actually support ext4 encryption. Therefore, only provide this file on kernels compiled with CONFIG_EXT4_FS_ENCRYPTION=y. Note: since the ext4 feature files are all hardcoded to have a contents of "supported", it really is the presence or absence of the file that is significant, not the contents (and this change reflects that). Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org --- fs/ext4/sysfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c index 73bcfd41f5f26..42145be5c6b4d 100644 --- a/fs/ext4/sysfs.c +++ b/fs/ext4/sysfs.c @@ -223,14 +223,18 @@ static struct attribute *ext4_attrs[] = { EXT4_ATTR_FEATURE(lazy_itable_init); EXT4_ATTR_FEATURE(batched_discard); EXT4_ATTR_FEATURE(meta_bg_resize); +#ifdef CONFIG_EXT4_FS_ENCRYPTION EXT4_ATTR_FEATURE(encryption); +#endif EXT4_ATTR_FEATURE(metadata_csum_seed); static struct attribute *ext4_feat_attrs[] = { ATTR_LIST(lazy_itable_init), ATTR_LIST(batched_discard), ATTR_LIST(meta_bg_resize), +#ifdef CONFIG_EXT4_FS_ENCRYPTION ATTR_LIST(encryption), +#endif ATTR_LIST(metadata_csum_seed), NULL, }; -- GitLab From fb4454376df9d820d95452d71dd83da6971f9338 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 12 Oct 2016 23:30:16 -0400 Subject: [PATCH 0496/1167] fscrypto: make XTS tweak initialization endian-independent The XTS tweak (or IV) was initialized differently on little endian and big endian systems. Because the ciphertext depends on the XTS tweak, it was not possible to use an encrypted filesystem created by a little endian system on a big endian system and vice versa, even if they shared the same PAGE_SIZE. Fix this by always using little endian. This will break hypothetical big endian users of ext4 or f2fs encryption. However, all users we are aware of are little endian, and it's believed that "real" big endian users are unlikely to exist yet. So this might as well be fixed now before it's too late. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org --- fs/crypto/crypto.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 61057b7dbddbe..98f87fe8f1862 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -151,7 +151,10 @@ static int do_page_crypto(struct inode *inode, struct page *src_page, struct page *dest_page, gfp_t gfp_flags) { - u8 xts_tweak[FS_XTS_TWEAK_SIZE]; + struct { + __le64 index; + u8 padding[FS_XTS_TWEAK_SIZE - sizeof(__le64)]; + } xts_tweak; struct skcipher_request *req = NULL; DECLARE_FS_COMPLETION_RESULT(ecr); struct scatterlist dst, src; @@ -171,17 +174,15 @@ static int do_page_crypto(struct inode *inode, req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, page_crypt_complete, &ecr); - BUILD_BUG_ON(FS_XTS_TWEAK_SIZE < sizeof(index)); - memcpy(xts_tweak, &index, sizeof(index)); - memset(&xts_tweak[sizeof(index)], 0, - FS_XTS_TWEAK_SIZE - sizeof(index)); + BUILD_BUG_ON(sizeof(xts_tweak) != FS_XTS_TWEAK_SIZE); + xts_tweak.index = cpu_to_le64(index); + memset(xts_tweak.padding, 0, sizeof(xts_tweak.padding)); sg_init_table(&dst, 1); sg_set_page(&dst, dest_page, PAGE_SIZE, 0); sg_init_table(&src, 1); sg_set_page(&src, src_page, PAGE_SIZE, 0); - skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE, - xts_tweak); + skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE, &xts_tweak); if (rw == FS_DECRYPT) res = crypto_skcipher_decrypt(req); else -- GitLab From 77da3da0b22a67508eb1cf2b241a1fe852a6cb1a Mon Sep 17 00:00:00 2001 From: Aaron Brice Date: Mon, 10 Oct 2016 11:39:52 -0700 Subject: [PATCH 0497/1167] mmc: sdhci-esdhc-imx: Correct two register accesses - The DMA error interrupt bit is in a different position as compared to the sdhci standard. This is accounted for in many cases, but not handled in the case of clearing the INT_STATUS register by writing a 1 to that location. - The HOST_CONTROL register is very different as compared to the sdhci standard. This is accounted for in the write case, but not when read back out (which it is in the sdhci code). Signed-off-by: Dave Russell Signed-off-by: Aaron Brice Acked-by: Dong Aisheng Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 1f54fd8755c8e..7123ef96ed185 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -346,7 +346,8 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); u32 data; - if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { + if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE || + reg == SDHCI_INT_STATUS)) { if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) { /* * Clear and then set D3CD bit to avoid missing the @@ -555,6 +556,25 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) esdhc_clrset_le(host, 0xffff, val, reg); } +static u8 esdhc_readb_le(struct sdhci_host *host, int reg) +{ + u8 ret; + u32 val; + + switch (reg) { + case SDHCI_HOST_CONTROL: + val = readl(host->ioaddr + reg); + + ret = val & SDHCI_CTRL_LED; + ret |= (val >> 5) & SDHCI_CTRL_DMA_MASK; + ret |= (val & ESDHC_CTRL_4BITBUS); + ret |= (val & ESDHC_CTRL_8BITBUS) << 3; + return ret; + } + + return readb(host->ioaddr + reg); +} + static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -947,6 +967,7 @@ static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) static struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl_le, .read_w = esdhc_readw_le, + .read_b = esdhc_readb_le, .write_l = esdhc_writel_le, .write_w = esdhc_writew_le, .write_b = esdhc_writeb_le, -- GitLab From 5e2bd93b8fcac8c0cf83f189d996831fb21f2db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20de=20Bretagne?= Date: Sun, 9 Oct 2016 15:51:05 +0200 Subject: [PATCH 0498/1167] Bluetooth: hci_bcm: Fix autosuspend PM for Lenovo ThinkPad 8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ACPI table for BCM2E55 of Lenovo ThinkPad 8 is not correct. Set correctly IRQ polarity for this device, fixing the issue of bluetooth never resuming after autosuspend PM. Signed-off-by: Jérôme de Bretagne Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_bcm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 5ccb90ef0146e..8f6c23c20c52d 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -643,6 +643,14 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = { }, .driver_data = &acpi_active_low, }, + { /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */ + .ident = "Lenovo ThinkPad 8", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), + }, + .driver_data = &acpi_active_low, + }, { } }; -- GitLab From 233c9edcca0136f2b9b304fd4f32e9bb6ce88ea9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2016 09:09:44 +0300 Subject: [PATCH 0499/1167] afs: unmapping the wrong buffer We switched from kmap_atomic() to kmap() so the kunmap() calls need to be updated to match. Fixes: d001648ec7cf ('rxrpc: Don't expose skbs to in-kernel users [ver #2]') Signed-off-by: Dan Carpenter Signed-off-by: David Howells --- fs/afs/fsclient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 96f4d764d1a67..31c616ab9b400 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -364,7 +364,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) buffer = kmap(page); ret = afs_extract_data(call, buffer, call->count, true); - kunmap(buffer); + kunmap(page); if (ret < 0) return ret; } @@ -397,7 +397,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) page = call->reply3; buffer = kmap(page); memset(buffer + call->count, 0, PAGE_SIZE - call->count); - kunmap(buffer); + kunmap(page); } _leave(" = 0 [done]"); -- GitLab From 54fde4234579d3b1311b3ed1a1e95526a7cfdcd7 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 13 Oct 2016 08:39:52 +0100 Subject: [PATCH 0500/1167] rxrpc: Fix checker warning by not passing always-zero value to ERR_PTR() Fix the following checker warning: net/rxrpc/call_object.c:279 rxrpc_new_client_call() warn: passing zero to 'ERR_PTR' where a value that's always zero is passed to ERR_PTR() so that it can be passed to a tracepoint in an auxiliary pointer field. Just pass NULL instead to the tracepoint. Fixes: a84a46d73050 ("rxrpc: Add some additional call tracing") Reported-by: Dan Carpenter Signed-off-by: David Howells --- net/rxrpc/call_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 4353a29f3b571..1ed18d8c9c9fa 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -276,7 +276,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, goto error; trace_rxrpc_call(call, rxrpc_call_connected, atomic_read(&call->usage), - here, ERR_PTR(ret)); + here, NULL); spin_lock_bh(&call->conn->params.peer->lock); hlist_add_head(&call->error_link, -- GitLab From 07096f612fdf2bb5578cd1fecb2884bdbb1cde42 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 13 Oct 2016 08:43:17 +0100 Subject: [PATCH 0501/1167] rxrpc: Fix checking of error from ip6_route_output() ip6_route_output() doesn't return a negative error when it fails, rather the ->error field of the returned dst_entry struct needs to be checked. Reported-by: Dan Carpenter Fixes: 75b54cb57ca3 ("rxrpc: Add IPv6 support") Signed-off-by: David Howells --- net/rxrpc/peer_object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/rxrpc/peer_object.c b/net/rxrpc/peer_object.c index 941b724d523bf..862eea6b266c9 100644 --- a/net/rxrpc/peer_object.c +++ b/net/rxrpc/peer_object.c @@ -193,8 +193,8 @@ static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer) fl6->fl6_dport = htons(7001); fl6->fl6_sport = htons(7000); dst = ip6_route_output(&init_net, NULL, fl6); - if (IS_ERR(dst)) { - _leave(" [route err %ld]", PTR_ERR(dst)); + if (dst->error) { + _leave(" [route err %d]", dst->error); return; } break; -- GitLab From cf4747d7535a936105f0abe8d8109d3fe339162b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 12 Oct 2016 13:54:04 -0500 Subject: [PATCH 0502/1167] rtlwifi: Fix regression caused by commit d86e64768859 In commit d86e64768859 ("rtlwifi: rtl818x: constify local structures"), the configuration struct for most of the drivers was changed to be constant. The problem is that five of the modified drivers need to be able to update the firmware name based on the exact model of the card. As the file names were stored in one of the members of that struct, these drivers would fail with a kernel BUG splat when they tried to update the firmware name. Rather than reverting the previous commit, I used a suggestion by Johannes Berg and made the firmware file name pointers be local to the routines that update the software variables. The configuration struct of rtl8192cu, which was not touched in the previous patch, is now constantfied. Fixes: d86e64768859 ("rtlwifi: rtl818x: constify local structures") Suggested-by: Johannes Berg Signed-off-by: Larry Finger Cc: Stable # 4.8 Cc: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/core.c | 2 +- .../wireless/realtek/rtlwifi/rtl8188ee/sw.c | 8 ++++---- .../wireless/realtek/rtlwifi/rtl8192ce/sw.c | 13 +++++-------- .../wireless/realtek/rtlwifi/rtl8192cu/sw.c | 12 ++++++------ .../wireless/realtek/rtlwifi/rtl8192de/sw.c | 6 +++--- .../wireless/realtek/rtlwifi/rtl8192ee/sw.c | 8 ++++---- .../wireless/realtek/rtlwifi/rtl8192se/sw.c | 9 +++++---- .../wireless/realtek/rtlwifi/rtl8723ae/sw.c | 12 +++++------- .../wireless/realtek/rtlwifi/rtl8723be/sw.c | 6 +++--- .../wireless/realtek/rtlwifi/rtl8821ae/sw.c | 18 +++++++++--------- drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 -- 11 files changed, 45 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index f95760c13c56e..8e7f23c11680a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -111,7 +111,7 @@ static void rtl_fw_do_work(const struct firmware *firmware, void *context, if (!err) goto found_alt; } - pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name); + pr_err("Selected firmware is not available\n"); rtlpriv->max_fw_size = 0; return; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index e7b11b40e68dc..f361808def47a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -86,6 +86,7 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 tid; + char *fw_name; rtl8188ee_bt_reg_init(hw); rtlpriv->dm.dm_initialgain_enable = 1; @@ -169,10 +170,10 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw) return 1; } - rtlpriv->cfg->fw_name = "rtlwifi/rtl8188efw.bin"; + fw_name = "rtlwifi/rtl8188efw.bin"; rtlpriv->max_fw_size = 0x8000; - pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); - err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + pr_info("Using firmware %s\n", fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { @@ -284,7 +285,6 @@ static const struct rtl_hal_cfg rtl88ee_hal_cfg = { .bar_id = 2, .write_readback = true, .name = "rtl88e_pci", - .fw_name = "rtlwifi/rtl8188efw.bin", .ops = &rtl8188ee_hal_ops, .mod_params = &rtl88ee_mod_params, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index 87aa209ae325d..8b6e37ce3f669 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -96,6 +96,7 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + char *fw_name = "rtlwifi/rtl8192cfwU.bin"; rtl8192ce_bt_reg_init(hw); @@ -167,15 +168,12 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) } /* request fw */ - if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && - !IS_92C_SERIAL(rtlhal->version)) - rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin"; - else if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version)) - rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin"; + if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version)) + fw_name = "rtlwifi/rtl8192cfwU_B.bin"; rtlpriv->max_fw_size = 0x4000; - pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); - err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + pr_info("Using firmware %s\n", fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { @@ -262,7 +260,6 @@ static const struct rtl_hal_cfg rtl92ce_hal_cfg = { .bar_id = 2, .write_readback = true, .name = "rtl92c_pci", - .fw_name = "rtlwifi/rtl8192cfw.bin", .ops = &rtl8192ce_hal_ops, .mod_params = &rtl92ce_mod_params, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index 7c6f7f0d18c60..f953320f0e23a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -59,6 +59,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); int err; + char *fw_name; rtlpriv->dm.dm_initialgain_enable = true; rtlpriv->dm.dm_flag = 0; @@ -77,18 +78,18 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) } if (IS_VENDOR_UMC_A_CUT(rtlpriv->rtlhal.version) && !IS_92C_SERIAL(rtlpriv->rtlhal.version)) { - rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_A.bin"; + fw_name = "rtlwifi/rtl8192cufw_A.bin"; } else if (IS_81XXC_VENDOR_UMC_B_CUT(rtlpriv->rtlhal.version)) { - rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_B.bin"; + fw_name = "rtlwifi/rtl8192cufw_B.bin"; } else { - rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_TMSC.bin"; + fw_name = "rtlwifi/rtl8192cufw_TMSC.bin"; } /* provide name of alternative file */ rtlpriv->cfg->alt_fw_name = "rtlwifi/rtl8192cufw.bin"; - pr_info("Loading firmware %s\n", rtlpriv->cfg->fw_name); + pr_info("Loading firmware %s\n", fw_name); rtlpriv->max_fw_size = 0x4000; err = request_firmware_nowait(THIS_MODULE, 1, - rtlpriv->cfg->fw_name, rtlpriv->io.dev, + fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); return err; } @@ -187,7 +188,6 @@ static struct rtl_hal_usbint_cfg rtl92cu_interface_cfg = { static struct rtl_hal_cfg rtl92cu_hal_cfg = { .name = "rtl92c_usb", - .fw_name = "rtlwifi/rtl8192cufw.bin", .ops = &rtl8192cu_hal_ops, .mod_params = &rtl92cu_mod_params, .usb_interface_cfg = &rtl92cu_interface_cfg, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index 0538a4d095688..1ebfee18882fb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -92,6 +92,7 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) u8 tid; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + char *fw_name = "rtlwifi/rtl8192defw.bin"; rtlpriv->dm.dm_initialgain_enable = true; rtlpriv->dm.dm_flag = 0; @@ -181,10 +182,10 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->max_fw_size = 0x8000; pr_info("Driver for Realtek RTL8192DE WLAN interface\n"); - pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name); + pr_info("Loading firmware file %s\n", fw_name); /* request fw */ - err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + err = request_firmware_nowait(THIS_MODULE, 1, fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { @@ -266,7 +267,6 @@ static const struct rtl_hal_cfg rtl92de_hal_cfg = { .bar_id = 2, .write_readback = true, .name = "rtl8192de", - .fw_name = "rtlwifi/rtl8192defw.bin", .ops = &rtl8192de_hal_ops, .mod_params = &rtl92de_mod_params, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index ac299cbe59b0d..46b605de36e72 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -91,6 +91,7 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); int err = 0; + char *fw_name; rtl92ee_bt_reg_init(hw); rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; @@ -170,11 +171,11 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw) } /* request fw */ - rtlpriv->cfg->fw_name = "rtlwifi/rtl8192eefw.bin"; + fw_name = "rtlwifi/rtl8192eefw.bin"; rtlpriv->max_fw_size = 0x8000; - pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); - err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + pr_info("Using firmware %s\n", fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { @@ -266,7 +267,6 @@ static const struct rtl_hal_cfg rtl92ee_hal_cfg = { .bar_id = 2, .write_readback = true, .name = "rtl92ee_pci", - .fw_name = "rtlwifi/rtl8192eefw.bin", .ops = &rtl8192ee_hal_ops, .mod_params = &rtl92ee_mod_params, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index 5e8e02d5de8aa..3e1eaeac4fdce 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -89,12 +89,13 @@ static void rtl92se_fw_cb(const struct firmware *firmware, void *context) struct ieee80211_hw *hw = context; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rt_firmware *pfirmware = NULL; + char *fw_name = "rtlwifi/rtl8192sefw.bin"; RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, "Firmware callback routine entered!\n"); complete(&rtlpriv->firmware_loading_complete); if (!firmware) { - pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name); + pr_err("Firmware %s not available\n", fw_name); rtlpriv->max_fw_size = 0; return; } @@ -117,6 +118,7 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); int err = 0; u16 earlyrxthreshold = 7; + char *fw_name = "rtlwifi/rtl8192sefw.bin"; rtlpriv->dm.dm_initialgain_enable = true; rtlpriv->dm.dm_flag = 0; @@ -214,9 +216,9 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->max_fw_size = RTL8190_MAX_FIRMWARE_CODE_SIZE*2 + sizeof(struct fw_hdr); pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n" - "Loading firmware %s\n", rtlpriv->cfg->fw_name); + "Loading firmware %s\n", fw_name); /* request fw */ - err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + err = request_firmware_nowait(THIS_MODULE, 1, fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl92se_fw_cb); if (err) { @@ -310,7 +312,6 @@ static const struct rtl_hal_cfg rtl92se_hal_cfg = { .bar_id = 1, .write_readback = false, .name = "rtl92s_pci", - .fw_name = "rtlwifi/rtl8192sefw.bin", .ops = &rtl8192se_hal_ops, .mod_params = &rtl92se_mod_params, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index 89c828ad89f42..c51a9e8234e92 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -94,6 +94,7 @@ int rtl8723e_init_sw_vars(struct ieee80211_hw *hw) struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); int err = 0; + char *fw_name = "rtlwifi/rtl8723fw.bin"; rtl8723e_bt_reg_init(hw); @@ -176,14 +177,12 @@ int rtl8723e_init_sw_vars(struct ieee80211_hw *hw) return 1; } - if (IS_VENDOR_8723_A_CUT(rtlhal->version)) - rtlpriv->cfg->fw_name = "rtlwifi/rtl8723fw.bin"; - else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) - rtlpriv->cfg->fw_name = "rtlwifi/rtl8723fw_B.bin"; + if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) + fw_name = "rtlwifi/rtl8723fw_B.bin"; rtlpriv->max_fw_size = 0x6000; - pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); - err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + pr_info("Using firmware %s\n", fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { @@ -280,7 +279,6 @@ static const struct rtl_hal_cfg rtl8723e_hal_cfg = { .bar_id = 2, .write_readback = true, .name = "rtl8723e_pci", - .fw_name = "rtlwifi/rtl8723efw.bin", .ops = &rtl8723e_hal_ops, .mod_params = &rtl8723e_mod_params, .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 20b53f035483a..847644d1f5f53 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -91,6 +91,7 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + char *fw_name = "rtlwifi/rtl8723befw.bin"; rtl8723be_bt_reg_init(hw); rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); @@ -184,8 +185,8 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) } rtlpriv->max_fw_size = 0x8000; - pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); - err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + pr_info("Using firmware %s\n", fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { @@ -280,7 +281,6 @@ static const struct rtl_hal_cfg rtl8723be_hal_cfg = { .bar_id = 2, .write_readback = true, .name = "rtl8723be_pci", - .fw_name = "rtlwifi/rtl8723befw.bin", .ops = &rtl8723be_hal_ops, .mod_params = &rtl8723be_mod_params, .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 22f687b1f1334..297938e0effd5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -93,6 +93,7 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + char *fw_name, *wowlan_fw_name; rtl8821ae_bt_reg_init(hw); rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); @@ -203,17 +204,17 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) } if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { - rtlpriv->cfg->fw_name = "rtlwifi/rtl8812aefw.bin"; - rtlpriv->cfg->wowlan_fw_name = "rtlwifi/rtl8812aefw_wowlan.bin"; + fw_name = "rtlwifi/rtl8812aefw.bin"; + wowlan_fw_name = "rtlwifi/rtl8812aefw_wowlan.bin"; } else { - rtlpriv->cfg->fw_name = "rtlwifi/rtl8821aefw.bin"; - rtlpriv->cfg->wowlan_fw_name = "rtlwifi/rtl8821aefw_wowlan.bin"; + fw_name = "rtlwifi/rtl8821aefw.bin"; + wowlan_fw_name = "rtlwifi/rtl8821aefw_wowlan.bin"; } rtlpriv->max_fw_size = 0x8000; /*load normal firmware*/ - pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); - err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + pr_info("Using firmware %s\n", fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { @@ -222,9 +223,9 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) return 1; } /*load wowlan firmware*/ - pr_info("Using firmware %s\n", rtlpriv->cfg->wowlan_fw_name); + pr_info("Using firmware %s\n", wowlan_fw_name); err = request_firmware_nowait(THIS_MODULE, 1, - rtlpriv->cfg->wowlan_fw_name, + wowlan_fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_wowlan_fw_cb); if (err) { @@ -320,7 +321,6 @@ static const struct rtl_hal_cfg rtl8821ae_hal_cfg = { .bar_id = 2, .write_readback = true, .name = "rtl8821ae_pci", - .fw_name = "rtlwifi/rtl8821aefw.bin", .ops = &rtl8821ae_hal_ops, .mod_params = &rtl8821ae_mod_params, .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 595f7d5d091af..dafe486f84486 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2278,9 +2278,7 @@ struct rtl_hal_cfg { u8 bar_id; bool write_readback; char *name; - char *fw_name; char *alt_fw_name; - char *wowlan_fw_name; struct rtl_hal_ops *ops; struct rtl_mod_params *mod_params; struct rtl_hal_usbint_cfg *usb_interface_cfg; -- GitLab From f67b107d4ceddcf7aa65b706aaaf50d68edb52a6 Mon Sep 17 00:00:00 2001 From: Marty Faltesek Date: Mon, 10 Oct 2016 19:00:04 +0300 Subject: [PATCH 0503/1167] ath10k: cache calibration data when the core is stopped Commit 0b8e3c4ca29f ("ath10k: move cal data len to hw_params") broke retrieving the calibration data from cal_data debugfs file. The length of file was always zero. The reason is: static ssize_t ath10k_debug_cal_data_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; void *buf = file->private_data; This is obviously bogus, private_data cannot contain both struct ath10k and the buffer. Fix it by caching calibration data to ar->debug.cal_data. This also allows it to be accessed when the device is not active (interface is down). The cal_data buffer is fixed size because during the first firmware probe we don't yet know what will be the lenght of the calibration data. It was simplest just to use a fixed length. There's a WARN_ON() in ath10k_debug_cal_data_fetch() if the buffer is too small. Tested with qca988x and firmware 10.2.4.70.56. Reported-by: Nikolay Martynov Fixes: 0b8e3c4ca29f ("ath10k: move cal data len to hw_params") Cc: stable@vger.kernel.org # 4.7+ Signed-off-by: Marty Faltesek [kvalo@qca.qualcomm.com: improve commit log and minor other changes] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/debug.c | 75 +++++++++++++------------ 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index dda49af1eb744..521f1c55c19ee 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -450,6 +450,7 @@ struct ath10k_debug { u32 pktlog_filter; u32 reg_addr; u32 nf_cal_period; + void *cal_data; struct ath10k_fw_crash_data *fw_crash_data; }; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 832da6ed9f13c..82a4c67f3672b 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -30,6 +30,8 @@ /* ms */ #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 +#define ATH10K_DEBUG_CAL_DATA_LEN 12064 + #define ATH10K_FW_CRASH_DUMP_VERSION 1 /** @@ -1451,56 +1453,51 @@ static const struct file_operations fops_fw_dbglog = { .llseek = default_llseek, }; -static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file) +static int ath10k_debug_cal_data_fetch(struct ath10k *ar) { - struct ath10k *ar = inode->i_private; - void *buf; u32 hi_addr; __le32 addr; int ret; - mutex_lock(&ar->conf_mutex); - - if (ar->state != ATH10K_STATE_ON && - ar->state != ATH10K_STATE_UTF) { - ret = -ENETDOWN; - goto err; - } + lockdep_assert_held(&ar->conf_mutex); - buf = vmalloc(ar->hw_params.cal_data_len); - if (!buf) { - ret = -ENOMEM; - goto err; - } + if (WARN_ON(ar->hw_params.cal_data_len > ATH10K_DEBUG_CAL_DATA_LEN)) + return -EINVAL; hi_addr = host_interest_item_address(HI_ITEM(hi_board_data)); ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr)); if (ret) { - ath10k_warn(ar, "failed to read hi_board_data address: %d\n", ret); - goto err_vfree; + ath10k_warn(ar, "failed to read hi_board_data address: %d\n", + ret); + return ret; } - ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), buf, + ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), ar->debug.cal_data, ar->hw_params.cal_data_len); if (ret) { ath10k_warn(ar, "failed to read calibration data: %d\n", ret); - goto err_vfree; + return ret; } - file->private_data = buf; + return 0; +} - mutex_unlock(&ar->conf_mutex); +static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file) +{ + struct ath10k *ar = inode->i_private; - return 0; + mutex_lock(&ar->conf_mutex); -err_vfree: - vfree(buf); + if (ar->state == ATH10K_STATE_ON || + ar->state == ATH10K_STATE_UTF) { + ath10k_debug_cal_data_fetch(ar); + } -err: + file->private_data = ar; mutex_unlock(&ar->conf_mutex); - return ret; + return 0; } static ssize_t ath10k_debug_cal_data_read(struct file *file, @@ -1508,18 +1505,16 @@ static ssize_t ath10k_debug_cal_data_read(struct file *file, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; - void *buf = file->private_data; - return simple_read_from_buffer(user_buf, count, ppos, - buf, ar->hw_params.cal_data_len); -} + mutex_lock(&ar->conf_mutex); -static int ath10k_debug_cal_data_release(struct inode *inode, - struct file *file) -{ - vfree(file->private_data); + count = simple_read_from_buffer(user_buf, count, ppos, + ar->debug.cal_data, + ar->hw_params.cal_data_len); - return 0; + mutex_unlock(&ar->conf_mutex); + + return count; } static ssize_t ath10k_write_ani_enable(struct file *file, @@ -1580,7 +1575,6 @@ static const struct file_operations fops_ani_enable = { static const struct file_operations fops_cal_data = { .open = ath10k_debug_cal_data_open, .read = ath10k_debug_cal_data_read, - .release = ath10k_debug_cal_data_release, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1932,6 +1926,8 @@ void ath10k_debug_stop(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); + ath10k_debug_cal_data_fetch(ar); + /* Must not use _sync to avoid deadlock, we do that in * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid * warning from del_timer(). */ @@ -2344,6 +2340,10 @@ int ath10k_debug_create(struct ath10k *ar) if (!ar->debug.fw_crash_data) return -ENOMEM; + ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN); + if (!ar->debug.cal_data) + return -ENOMEM; + INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs); INIT_LIST_HEAD(&ar->debug.fw_stats.peers); @@ -2357,6 +2357,9 @@ void ath10k_debug_destroy(struct ath10k *ar) vfree(ar->debug.fw_crash_data); ar->debug.fw_crash_data = NULL; + vfree(ar->debug.cal_data); + ar->debug.cal_data = NULL; + ath10k_debug_fw_stats_reset(ar); kfree(ar->debug.tpc_stats); -- GitLab From 304e5ac118cc351eb047b6c433a89e13ea7259cf Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 11 Oct 2016 19:46:49 +0200 Subject: [PATCH 0504/1167] Revert "ath9k_hw: implement temperature compensation support for AR9003+" This reverts commit 171f6402e4aa ("ath9k_hw: implement temperature compensation support for AR9003+"). Some users report that this commit causes a regression in performance under some conditions. Fixes: 171f6402e4aa ("ath9k_hw: implement temperature compensation support for AR9003+") Cc: # 4.8 Signed-off-by: Felix Fietkau [kvalo@qca.qualcomm.com: improve commit log] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 25 +++---------------- drivers/net/wireless/ath/ath9k/hw.h | 1 - 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index b6f064a8d2645..7e27a06e5df19 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -33,7 +33,6 @@ struct coeff { enum ar9003_cal_types { IQ_MISMATCH_CAL = BIT(0), - TEMP_COMP_CAL = BIT(1), }; static void ar9003_hw_setup_calibration(struct ath_hw *ah, @@ -59,12 +58,6 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah, /* Kick-off cal */ REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); break; - case TEMP_COMP_CAL: - ath_dbg(common, CALIBRATE, - "starting Temperature Compensation Calibration\n"); - REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_LOCAL); - REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_START); - break; default: ath_err(common, "Invalid calibration type\n"); break; @@ -93,8 +86,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, /* * Accumulate cal measures for active chains */ - if (cur_caldata->calCollect) - cur_caldata->calCollect(ah); + cur_caldata->calCollect(ah); ah->cal_samples++; if (ah->cal_samples >= cur_caldata->calNumSamples) { @@ -107,8 +99,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, /* * Process accumulated data */ - if (cur_caldata->calPostProc) - cur_caldata->calPostProc(ah, numChains); + cur_caldata->calPostProc(ah, numChains); /* Calibration has finished. */ caldata->CalValid |= cur_caldata->calType; @@ -323,16 +314,9 @@ static const struct ath9k_percal_data iq_cal_single_sample = { ar9003_hw_iqcalibrate }; -static const struct ath9k_percal_data temp_cal_single_sample = { - TEMP_COMP_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, -}; - static void ar9003_hw_init_cal_settings(struct ath_hw *ah) { ah->iq_caldata.calData = &iq_cal_single_sample; - ah->temp_caldata.calData = &temp_cal_single_sample; if (AR_SREV_9300_20_OR_LATER(ah)) { ah->enabled_cals |= TX_IQ_CAL; @@ -340,7 +324,7 @@ static void ar9003_hw_init_cal_settings(struct ath_hw *ah) ah->enabled_cals |= TX_IQ_ON_AGC_CAL; } - ah->supp_cals = IQ_MISMATCH_CAL | TEMP_COMP_CAL; + ah->supp_cals = IQ_MISMATCH_CAL; } #define OFF_UPPER_LT 24 @@ -1399,9 +1383,6 @@ static void ar9003_hw_init_cal_common(struct ath_hw *ah) INIT_CAL(&ah->iq_caldata); INSERT_CAL(ah, &ah->iq_caldata); - INIT_CAL(&ah->temp_caldata); - INSERT_CAL(ah, &ah->temp_caldata); - /* Initialize current pointer to first element in list */ ah->cal_list_curr = ah->cal_list; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 2a5d3ad1169c9..9cbca1229bac0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -830,7 +830,6 @@ struct ath_hw { /* Calibration */ u32 supp_cals; struct ath9k_cal_list iq_caldata; - struct ath9k_cal_list temp_caldata; struct ath9k_cal_list adcgain_caldata; struct ath9k_cal_list adcdc_caldata; struct ath9k_cal_list *cal_list; -- GitLab From 1ea2643961b0d1b8d0e4a11af5aa69b0f92d0533 Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Wed, 12 Oct 2016 19:08:40 +0100 Subject: [PATCH 0505/1167] ath6kl: add Dell OEM SDIO I/O for the Venue 8 Pro SDIO ID 0271:0418 Signed-off-by: Alan Cox Bugzilla-ID: https://bugzilla.kernel.org/show_bug.cgi?id=67921 Reviewed-by: Steve deRosier Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/sdio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index eab0ab976af29..76eb33679d4bd 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -1401,6 +1401,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = { {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))}, {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))}, {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x18))}, {}, }; -- GitLab From abb6627910a1e783c8e034b35b7c80e5e7f98f41 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 12 Oct 2016 21:47:03 +0200 Subject: [PATCH 0506/1167] cpufreq: conservative: Fix next frequency selection Commit d352cf47d93e (cpufreq: conservative: Do not use transition notifications) overlooked the case when the "frequency step" used by the conservative governor is small relative to the distances between the available frequencies and broke the algorithm by using policy->cur instead of the previously requested frequency when computing the next one. As a result, the governor may not be able to go outside of a narrow range between two consecutive available frequencies. Fix the problem by making the governor save the previously requested frequency and select the next one relative that value (unless it is out of range, in which case policy->cur will be used instead). Fixes: d352cf47d93e (cpufreq: conservative: Do not use transition notifications) Link: https://bugzilla.kernel.org/show_bug.cgi?id=177171 Reported-and-tested-by: Aleksey Rybalkin Acked-by: Viresh Kumar Cc: 4.8+ # 4.8+ Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 18da4f8051d37..13475890d792d 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -17,6 +17,7 @@ struct cs_policy_dbs_info { struct policy_dbs_info policy_dbs; unsigned int down_skip; + unsigned int requested_freq; }; static inline struct cs_policy_dbs_info *to_dbs_info(struct policy_dbs_info *policy_dbs) @@ -61,6 +62,7 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy) { struct policy_dbs_info *policy_dbs = policy->governor_data; struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs); + unsigned int requested_freq = dbs_info->requested_freq; struct dbs_data *dbs_data = policy_dbs->dbs_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; unsigned int load = dbs_update(policy); @@ -72,10 +74,16 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy) if (cs_tuners->freq_step == 0) goto out; + /* + * If requested_freq is out of range, it is likely that the limits + * changed in the meantime, so fall back to current frequency in that + * case. + */ + if (requested_freq > policy->max || requested_freq < policy->min) + requested_freq = policy->cur; + /* Check for frequency increase */ if (load > dbs_data->up_threshold) { - unsigned int requested_freq = policy->cur; - dbs_info->down_skip = 0; /* if we are already at full speed then break out early */ @@ -83,8 +91,11 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy) goto out; requested_freq += get_freq_target(cs_tuners, policy); + if (requested_freq > policy->max) + requested_freq = policy->max; __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_H); + dbs_info->requested_freq = requested_freq; goto out; } @@ -95,7 +106,7 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy) /* Check for frequency decrease */ if (load < cs_tuners->down_threshold) { - unsigned int freq_target, requested_freq = policy->cur; + unsigned int freq_target; /* * if we cannot reduce the frequency anymore, break out early */ @@ -109,6 +120,7 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy) requested_freq = policy->min; __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_L); + dbs_info->requested_freq = requested_freq; } out: @@ -287,6 +299,7 @@ static void cs_start(struct cpufreq_policy *policy) struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data); dbs_info->down_skip = 0; + dbs_info->requested_freq = policy->cur; } static struct dbs_governor cs_governor = { -- GitLab From c611152373e84a7677cd7d496e849de4debdab66 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 7 Oct 2016 14:04:12 +0900 Subject: [PATCH 0507/1167] perf top: Fix refreshing hierarchy entries on TUI Markus reported that 'perf top --hierarchy' cannot scroll down after refresh. This was because the number of entries are not updated when hierarchy is enabled. Unlike normal report view, hierarchy mode needs to keep its own entry count since it can have non-leaf entries which can expand/collapse. Reported-and-Tested-by: Markus Trippelsdorf Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: Jiri Olsa Cc: Peter Zijlstra Fixes: f5b763feebe9 ("perf hists browser: Count number of hierarchy entries") Link: http://lkml.kernel.org/r/20161007050412.3000-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index fb8e42c7507ad..4ffff7be92993 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -601,7 +601,8 @@ int hist_browser__run(struct hist_browser *browser, const char *help) u64 nr_entries; hbt->timer(hbt->arg); - if (hist_browser__has_filter(browser)) + if (hist_browser__has_filter(browser) || + symbol_conf.report_hierarchy) hist_browser__update_nr_entries(browser); nr_entries = hist_browser__nr_entries(browser); -- GitLab From f957a5308dbbdf67aa4f8ac3233a61e802bd2373 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 10 Oct 2016 09:56:32 +0200 Subject: [PATCH 0508/1167] perf header: Set nr_numa_nodes only when we parsed all the data Sukadev reported segfault on releasing perf env's numa data. It's due to nr_numa_nodes being set no matter if the numa data gets parsed properly. The perf_env__exit crash the on releasing non existed data. Setting nr_numa_nodes only when data are parsed out properly. Signed-off-by: Jiri Olsa Reported-by: Sukadev Bhattiprolu Cc: Adrian Hunter Cc: David Ahern Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-dt9c0zgkt4hybn2cr4xiawta@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 85dd0db0a1279..2f3eded54b0cc 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1895,7 +1895,6 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse if (ph->needs_swap) nr = bswap_32(nr); - ph->env.nr_numa_nodes = nr; nodes = zalloc(sizeof(*nodes) * nr); if (!nodes) return -ENOMEM; @@ -1932,6 +1931,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse free(str); } + ph->env.nr_numa_nodes = nr; ph->env.numa_nodes = nodes; return 0; -- GitLab From 38b8767462120c62a5046b529c80b06861f9ac85 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 13 Oct 2016 17:09:36 +0200 Subject: [PATCH 0509/1167] Documentation: MIPS supports HAVE_REGS_AND_STACK_ACCESS_API This should have been part of 40e084a506eb ('MIPS: Add uprobes support.'). Signed-off-by: Ralf Baechle Fixes: 40e084a506eb ("MIPS: Add uprobes support.") Acked-by: Jonathan Corbet Cc: linux-mips@linux-mips.org Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14392/ Signed-off-by: Ralf Baechle --- Documentation/features/perf/kprobes-event/arch-support.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/features/perf/kprobes-event/arch-support.txt b/Documentation/features/perf/kprobes-event/arch-support.txt index 9855ad0443868..4660bf222db17 100644 --- a/Documentation/features/perf/kprobes-event/arch-support.txt +++ b/Documentation/features/perf/kprobes-event/arch-support.txt @@ -22,7 +22,7 @@ | m68k: | TODO | | metag: | TODO | | microblaze: | TODO | - | mips: | TODO | + | mips: | ok | | mn10300: | TODO | | nios2: | TODO | | openrisc: | TODO | -- GitLab From 50a2c95381a7d0e453d7bdfde81d0c5f8351ba54 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 13 Oct 2016 08:27:10 +0100 Subject: [PATCH 0510/1167] afs: call->operation_ID sometimes used as __be32 sometimes as u32 call->operation_ID is sometimes being used as __be32 sometimes is being used as u32. Be consistent and settle on using as u32. Signed-off-by: David Howells operation_ID); + _enter("{CB.OP %u}", call->operation_ID); - _enter("{CB.OP %u}", operation_id); - - switch (operation_id) { + switch (call->operation_ID) { case CBCallBack: call->type = &afs_SRXCBCallBack; return true; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 5497c84960557..535a38d2c1d06 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -112,7 +112,7 @@ struct afs_call { bool need_attention; /* T if RxRPC poked us */ u16 service_id; /* RxRPC service ID to call */ __be16 port; /* target UDP port */ - __be32 operation_ID; /* operation ID for an incoming call */ + u32 operation_ID; /* operation ID for an incoming call */ u32 count; /* count for use in unmarshalling */ __be32 tmp; /* place to extract temporary data */ afs_dataversion_t store_version; /* updated version expected from store */ diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 477928b259400..25f05a8d21b19 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -676,10 +676,11 @@ static int afs_deliver_cm_op_id(struct afs_call *call) ASSERTCMP(call->offset, <, 4); /* the operation ID forms the first four bytes of the request data */ - ret = afs_extract_data(call, &call->operation_ID, 4, true); + ret = afs_extract_data(call, &call->tmp, 4, true); if (ret < 0) return ret; + call->operation_ID = ntohl(call->tmp); call->state = AFS_CALL_AWAIT_REQUEST; call->offset = 0; -- GitLab From f208b87b48d5af2ea483293eccb3998c467dfba1 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Sun, 9 Oct 2016 02:35:08 -0400 Subject: [PATCH 0511/1167] sh: support CPU_J2 when compiler lacks -mj2 Signed-off-by: Rich Felker --- arch/sh/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 00476662ac2c0..336f33a419d99 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -31,7 +31,7 @@ isa-y := $(isa-y)-up endif cflags-$(CONFIG_CPU_SH2) := $(call cc-option,-m2,) -cflags-$(CONFIG_CPU_J2) := $(call cc-option,-mj2,) +cflags-$(CONFIG_CPU_J2) += $(call cc-option,-mj2,) cflags-$(CONFIG_CPU_SH2A) += $(call cc-option,-m2a,) \ $(call cc-option,-m2a-nofpu,) \ $(call cc-option,-m4-nofpu,) -- GitLab From a3f9d1b58a9ffce011ef4f074bfa36ae30eade28 Mon Sep 17 00:00:00 2001 From: Benjamin Coddington Date: Tue, 11 Oct 2016 15:53:21 -0400 Subject: [PATCH 0512/1167] pnfs/blocklayout: fix last_write_offset incorrectly set to page boundary Commit 41963c10c47a35185e68cb9049f7a3493c94d2d7 sets the block layout's last written byte to the offset of the end of the extent rather than the end of the write which incorrectly updates the inode's size for partial-page writes. Fixes: 41963c10c47a ("pnfs/blocklayout: update last_write_offset atomically with extents") Signed-off-by: Benjamin Coddington Reviewed-by: Christoph Hellwig Tested-by: Christoph Hellwig Cc: stable@vger.kernel.org # 4.8+ Signed-off-by: Anna Schumaker --- fs/nfs/blocklayout/blocklayout.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 217847679f0ea..2905479f214a4 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -344,9 +344,10 @@ static void bl_write_cleanup(struct work_struct *work) u64 start = hdr->args.offset & (loff_t)PAGE_MASK; u64 end = (hdr->args.offset + hdr->args.count + PAGE_SIZE - 1) & (loff_t)PAGE_MASK; + u64 lwb = hdr->args.offset + hdr->args.count; ext_tree_mark_written(bl, start >> SECTOR_SHIFT, - (end - start) >> SECTOR_SHIFT, end); + (end - start) >> SECTOR_SHIFT, lwb); } pnfs_ld_write_done(hdr); -- GitLab From c197d758036d8c77923ae3f88571cf198283107e Mon Sep 17 00:00:00 2001 From: Hoan Tran Date: Thu, 13 Oct 2016 10:33:35 -0700 Subject: [PATCH 0513/1167] cpufreq: CPPC: Correct desired_perf calculation The desired_perf is an abstract performance number. Its value should be in the range of [lowest perf, highest perf] of CPPC. The correct calculation is desired_perf = freq * cppc_highest_perf / cppc_dmi_max_khz And cppc_cpufreq_set_target() returns if desired_perf is exactly the same with the old perf. Signed-off-by: Hoan Tran Reviewed-by: Prashanth Prakash Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cppc_cpufreq.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 99db4227ae387..f7e98fc077c14 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -80,11 +80,17 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, { struct cpudata *cpu; struct cpufreq_freqs freqs; + u32 desired_perf; int ret = 0; cpu = all_cpu_data[policy->cpu]; - cpu->perf_ctrls.desired_perf = (u64)target_freq * policy->max / cppc_dmi_max_khz; + desired_perf = (u64)target_freq * cpu->perf_caps.highest_perf / cppc_dmi_max_khz; + /* Return if it is exactly the same perf */ + if (desired_perf == cpu->perf_ctrls.desired_perf) + return ret; + + cpu->perf_ctrls.desired_perf = desired_perf; freqs.old = policy->cur; freqs.new = target_freq; -- GitLab From dc8184aa8621ee8048652496884d9f40d4bb407f Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Mon, 10 Oct 2016 15:57:21 +0800 Subject: [PATCH 0514/1167] drm/amdgpu: change vblank_time's calculation method to reduce computational error. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c index fe36caf1b7d7b..14f57d9915e3f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c @@ -113,24 +113,26 @@ void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev, printk("\n"); } + u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev) { struct drm_device *dev = adev->ddev; struct drm_crtc *crtc; struct amdgpu_crtc *amdgpu_crtc; - u32 line_time_us, vblank_lines; + u32 vblank_in_pixels; u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */ if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { amdgpu_crtc = to_amdgpu_crtc(crtc); if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) { - line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) / - amdgpu_crtc->hw_mode.clock; - vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end - + vblank_in_pixels = + amdgpu_crtc->hw_mode.crtc_htotal * + (amdgpu_crtc->hw_mode.crtc_vblank_end - amdgpu_crtc->hw_mode.crtc_vdisplay + - (amdgpu_crtc->v_border * 2); - vblank_time_us = vblank_lines * line_time_us; + (amdgpu_crtc->v_border * 2)); + + vblank_time_us = vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock; break; } } -- GitLab From 02cfb5fccb0f9f968f0e208d89d9769aa16267bc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 12 Oct 2016 15:28:55 -0400 Subject: [PATCH 0515/1167] drm/radeon: change vblank_time's calculation method to reduce computational error. Ported from Rex's amdgpu change. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/r600_dpm.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 6a4b020dd0b45..5a26eb4545aae 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c @@ -156,19 +156,20 @@ u32 r600_dpm_get_vblank_time(struct radeon_device *rdev) struct drm_device *dev = rdev->ddev; struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; - u32 line_time_us, vblank_lines; + u32 vblank_in_pixels; u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */ if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { radeon_crtc = to_radeon_crtc(crtc); if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { - line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) / - radeon_crtc->hw_mode.clock; - vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end - - radeon_crtc->hw_mode.crtc_vdisplay + - (radeon_crtc->v_border * 2); - vblank_time_us = vblank_lines * line_time_us; + vblank_in_pixels = + radeon_crtc->hw_mode.crtc_htotal * + (radeon_crtc->hw_mode.crtc_vblank_end - + radeon_crtc->hw_mode.crtc_vdisplay + + (radeon_crtc->v_border * 2)); + + vblank_time_us = vblank_in_pixels * 1000 / radeon_crtc->hw_mode.clock; break; } } -- GitLab From e07053241b0264e7b107b2b3f4d899635985d353 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 11 Oct 2016 18:44:46 +0800 Subject: [PATCH 0516/1167] drm/amd/powerplay: fix static checker warnings in iceland_smc.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add array length check to avoid buffer overflow. Signed-off-by: Rex Zhu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c index eda802bc63c88..8c889caba420d 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c @@ -2458,7 +2458,7 @@ static int iceland_set_mc_special_registers(struct pp_hwmgr *hwmgr, PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE), "Invalid VramInfo table.", return -EINVAL); - if (!data->is_memory_gddr5) { + if (!data->is_memory_gddr5 && j < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE) { table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD; table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD; for (k = 0; k < table->num_entries; k++) { -- GitLab From 9faa6b0277fab4ab91db4d69bc47566fdfbae48b Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 11 Oct 2016 18:51:16 +0800 Subject: [PATCH 0517/1167] drm/amd/powerplay: fix static checker warnings in smu7_hwmgr.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit variable dereferenced before check it Signed-off-by: Rex Zhu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 508245d49d339..7c67a5a911823 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -3802,13 +3802,15 @@ static inline bool smu7_are_power_levels_equal(const struct smu7_performance_lev int smu7_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, const struct pp_hw_power_state *pstate2, bool *equal) { - const struct smu7_power_state *psa = cast_const_phw_smu7_power_state(pstate1); - const struct smu7_power_state *psb = cast_const_phw_smu7_power_state(pstate2); + const struct smu7_power_state *psa; + const struct smu7_power_state *psb; int i; if (pstate1 == NULL || pstate2 == NULL || equal == NULL) return -EINVAL; + psa = cast_const_phw_smu7_power_state(pstate1); + psb = cast_const_phw_smu7_power_state(pstate2); /* If the two states don't even have the same number of performance levels they cannot be the same state. */ if (psa->performance_level_count != psb->performance_level_count) { *equal = false; -- GitLab From eeb2fa0c97ba661f8b7fb210a1de10928b67a47b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2016 09:17:30 +0300 Subject: [PATCH 0518/1167] drm/amdgpu: potential NULL dereference in debugfs code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit debugfs_create_file() returns NULL on error, it only returns error pointers if debugfs isn't enabled in the config and we checked for that earlier so it can't happen. Fixes: 4f4824b55650 ('drm/amd/amdgpu: Convert ring debugfs entries to binary') Reviewed-by: Christian König Signed-off-by: Dan Carpenter Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index e1fa8731d1e2d..3cb5e903cd628 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -345,8 +345,8 @@ static int amdgpu_debugfs_ring_init(struct amdgpu_device *adev, ent = debugfs_create_file(name, S_IFREG | S_IRUGO, root, ring, &amdgpu_debugfs_ring_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); + if (!ent) + return -ENOMEM; i_size_write(ent->d_inode, ring->ring_size + 12); ring->ent = ent; -- GitLab From 24e8df6a6837d6cff182e84b838dc1d6971251fc Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 13 Oct 2016 15:32:04 +0800 Subject: [PATCH 0519/1167] drm/amd/powerplay: fix static checker warnings in smu7_hwmgr.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rex Zhu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 7c67a5a911823..e7fb8e95436b1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -1452,8 +1452,10 @@ static int smu7_get_evv_voltages(struct pp_hwmgr *hwmgr) struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table = NULL; - if (table_info != NULL) - sclk_table = table_info->vdd_dep_on_sclk; + if (table_info == NULL) + return -EINVAL; + + sclk_table = table_info->vdd_dep_on_sclk; for (i = 0; i < SMU7_MAX_LEAKAGE_COUNT; i++) { vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i; -- GitLab From aee3960a0ca34f8bf7dbcdb330c4f37a0f94dd8a Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Thu, 13 Oct 2016 17:46:45 -0400 Subject: [PATCH 0520/1167] drm/amdgpu/si_dpm: Limit clocks on HD86xx part Limit clocks on a specific HD86xx part to avoid crashes (while awaiting an appropriate PP fix). Signed-off-by: Tom St Denis Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/si_dpm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index 8bd08925b370b..3de7bca5854b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -3499,6 +3499,12 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, max_sclk = 75000; max_mclk = 80000; } + /* Limit clocks for some HD8600 parts */ + if (adev->pdev->device == 0x6660 && + adev->pdev->revision == 0x83) { + max_sclk = 75000; + max_mclk = 80000; + } if (rps->vce_active) { rps->evclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].evclk; -- GitLab From 18dd8e1a65ddae2351d0f0d6dd4a334f441fc5fa Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 26 Sep 2016 14:23:08 -0500 Subject: [PATCH 0521/1167] Do not send SMB3 SET_INFO request if nothing is changing [CIFS] We had cases where we sent a SMB2/SMB3 setinfo request with all timestamp (and DOS attribute) fields marked as 0 (ie do not change) e.g. on chmod or chown. Signed-off-by: Steve French CC: Stable --- fs/cifs/smb2inode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 4f0231e685a92..1238cd3552f9c 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -266,9 +266,15 @@ smb2_set_file_info(struct inode *inode, const char *full_path, struct tcon_link *tlink; int rc; + if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) && + (buf->LastWriteTime == 0) && (buf->ChangeTime) && + (buf->Attributes == 0)) + return 0; /* would be a no op, no sense sending this */ + tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); + rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path, FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf, SMB2_OP_SET_INFO); -- GitLab From 834170c85978b0e85805364f623393968f7a9b5e Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 30 Sep 2016 21:14:26 -0500 Subject: [PATCH 0522/1167] Enable previous version support Add ioctl to query previous versions of file Allows listing snapshots on files on SMB3 mounts. Signed-off-by: Steve French --- fs/cifs/cifs_ioctl.h | 8 ++++++++ fs/cifs/cifsglob.h | 2 ++ fs/cifs/ioctl.c | 16 +++++++++++++-- fs/cifs/smb2ops.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifs_ioctl.h b/fs/cifs/cifs_ioctl.h index 0065256881d83..57ff0756e30c6 100644 --- a/fs/cifs/cifs_ioctl.h +++ b/fs/cifs/cifs_ioctl.h @@ -36,7 +36,15 @@ struct smb_mnt_fs_info { __u64 cifs_posix_caps; } __packed; +struct smb_snapshot_array { + __u32 number_of_snapshots; + __u32 number_of_snapshots_returned; + __u32 snapshot_array_size; + /* snapshots[]; */ +} __packed; + #define CIFS_IOCTL_MAGIC 0xCF #define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int) #define CIFS_IOC_SET_INTEGRITY _IO(CIFS_IOCTL_MAGIC, 4) #define CIFS_IOC_GET_MNT_INFO _IOR(CIFS_IOCTL_MAGIC, 5, struct smb_mnt_fs_info) +#define CIFS_ENUMERATE_SNAPSHOTS _IOR(CIFS_IOCTL_MAGIC, 6, struct smb_snapshot_array) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index cd80594f14d0e..d9a17288baf3a 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -388,6 +388,8 @@ struct smb_version_operations { int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *); int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon, struct cifsFileInfo *src_file); + int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon, + struct cifsFileInfo *src_file, void __user *); int (*query_mf_symlink)(unsigned int, struct cifs_tcon *, struct cifs_sb_info *, const unsigned char *, char *, unsigned int *); diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 7a3b84e300f89..9f51b81119f2b 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -189,7 +189,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) xid = get_xid(); cifs_sb = CIFS_SB(inode->i_sb); - + cifs_dbg(VFS, "cifs ioctl 0x%x\n", command); switch (command) { case FS_IOC_GETFLAGS: if (pSMBFile == NULL) @@ -267,11 +267,23 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) tcon = tlink_tcon(pSMBFile->tlink); rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg); break; + case CIFS_ENUMERATE_SNAPSHOTS: + if (arg == 0) { + rc = -EINVAL; + goto cifs_ioc_exit; + } + tcon = tlink_tcon(pSMBFile->tlink); + if (tcon->ses->server->ops->enum_snapshots) + rc = tcon->ses->server->ops->enum_snapshots(xid, tcon, + pSMBFile, (void __user *)arg); + else + rc = -EOPNOTSUPP; + break; default: cifs_dbg(FYI, "unsupported ioctl\n"); break; } - +cifs_ioc_exit: free_xid(xid); return rc; } diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 378260cd25a62..f0872d2abc6fc 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -28,6 +28,7 @@ #include "cifs_unicode.h" #include "smb2status.h" #include "smb2glob.h" +#include "cifs_ioctl.h" static int change_conf(struct TCP_Server_Info *server) @@ -894,6 +895,50 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon, } +static int +smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon, + struct cifsFileInfo *cfile, void __user *ioc_buf) +{ + char *retbuf = NULL; + unsigned int ret_data_len = 0; + int rc; + struct smb_snapshot_array snapshot_in; + + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, + FSCTL_SRV_ENUMERATE_SNAPSHOTS, + true /* is_fsctl */, NULL, 0 /* no input data */, + (char **)&retbuf, + &ret_data_len); + cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n", + rc, ret_data_len); + if (rc) + return rc; + + if (ret_data_len && (ioc_buf != NULL) && (retbuf != NULL)) { + /* Fixup buffer */ + if (copy_from_user(&snapshot_in, ioc_buf, + sizeof(struct smb_snapshot_array))) { + rc = -EFAULT; + kfree(retbuf); + return rc; + } + if (snapshot_in.snapshot_array_size < sizeof(struct smb_snapshot_array)) { + rc = -ERANGE; + return rc; + } + + if (ret_data_len > snapshot_in.snapshot_array_size) + ret_data_len = snapshot_in.snapshot_array_size; + + if (copy_to_user(ioc_buf, retbuf, ret_data_len)) + rc = -EFAULT; + } + + kfree(retbuf); + return rc; +} + static int smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, const char *path, struct cifs_sb_info *cifs_sb, @@ -1659,6 +1704,7 @@ struct smb_version_operations smb21_operations = { .clone_range = smb2_clone_range, .wp_retry_size = smb2_wp_retry_size, .dir_needs_close = smb2_dir_needs_close, + .enum_snapshots = smb3_enum_snapshots, }; struct smb_version_operations smb30_operations = { @@ -1745,6 +1791,7 @@ struct smb_version_operations smb30_operations = { .wp_retry_size = smb2_wp_retry_size, .dir_needs_close = smb2_dir_needs_close, .fallocate = smb3_fallocate, + .enum_snapshots = smb3_enum_snapshots, }; #ifdef CONFIG_CIFS_SMB311 @@ -1832,6 +1879,7 @@ struct smb_version_operations smb311_operations = { .wp_retry_size = smb2_wp_retry_size, .dir_needs_close = smb2_dir_needs_close, .fallocate = smb3_fallocate, + .enum_snapshots = smb3_enum_snapshots, }; #endif /* CIFS_SMB311 */ -- GitLab From 24df1483c272c99ed88b0cba135d0e1dfdee3930 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 29 Sep 2016 04:20:23 -0500 Subject: [PATCH 0523/1167] Cleanup missing frees on some ioctls Cleanup some missing mem frees on some cifs ioctls, and clarify others to make more obvious that no data is returned. CC: Stable Signed-off-by: Steve French Acked-by: Sachin Prabhu --- fs/cifs/smb2ops.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index f0872d2abc6fc..5d456ebb38138 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -292,7 +292,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) cifs_dbg(FYI, "Link Speed %lld\n", le64_to_cpu(out_buf->LinkSpeed)); } - + kfree(out_buf); return rc; } #endif /* STATS2 */ @@ -705,6 +705,7 @@ smb2_clone_range(const unsigned int xid, cchunk_out: kfree(pcchunk); + kfree(retbuf); return rc; } @@ -829,7 +830,6 @@ smb2_duplicate_extents(const unsigned int xid, { int rc; unsigned int ret_data_len; - char *retbuf = NULL; struct duplicate_extents_to_file dup_ext_buf; struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink); @@ -855,7 +855,7 @@ smb2_duplicate_extents(const unsigned int xid, FSCTL_DUPLICATE_EXTENTS_TO_FILE, true /* is_fsctl */, (char *)&dup_ext_buf, sizeof(struct duplicate_extents_to_file), - (char **)&retbuf, + NULL, &ret_data_len); if (ret_data_len > 0) @@ -878,7 +878,6 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon, struct cifsFileInfo *cfile) { struct fsctl_set_integrity_information_req integr_info; - char *retbuf = NULL; unsigned int ret_data_len; integr_info.ChecksumAlgorithm = cpu_to_le16(CHECKSUM_TYPE_UNCHANGED); @@ -890,7 +889,7 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon, FSCTL_SET_INTEGRITY_INFORMATION, true /* is_fsctl */, (char *)&integr_info, sizeof(struct fsctl_set_integrity_information_req), - (char **)&retbuf, + NULL, &ret_data_len); } -- GitLab From cb978ac8b85fa8861352e57fcf8020f7f7bfbd82 Mon Sep 17 00:00:00 2001 From: Germano Percossi Date: Fri, 30 Sep 2016 21:25:24 -0500 Subject: [PATCH 0524/1167] Expose cifs module parameters in sysfs /sys/module/cifs/parameters should display the three other module load time configuration settings for cifs.ko Signed-off-by: Germano Percossi Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d2b2703fed7dd..f963c880c72d5 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -64,15 +64,15 @@ unsigned int global_secflags = CIFSSEC_DEF; unsigned int sign_CIFS_PDUs = 1; static const struct super_operations cifs_super_ops; unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; -module_param(CIFSMaxBufSize, uint, 0); +module_param(CIFSMaxBufSize, uint, 0444); MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). " "Default: 16384 Range: 8192 to 130048"); unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; -module_param(cifs_min_rcv, uint, 0); +module_param(cifs_min_rcv, uint, 0444); MODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: " "1 to 64"); unsigned int cifs_min_small = 30; -module_param(cifs_min_small, uint, 0); +module_param(cifs_min_small, uint, 0444); MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 " "Range: 2 to 256"); unsigned int cifs_max_pending = CIFS_MAX_REQ; -- GitLab From 3baf1a7b921500596b77487d5a34a27d656fc032 Mon Sep 17 00:00:00 2001 From: Sachin Prabhu Date: Fri, 7 Oct 2016 19:11:21 +0100 Subject: [PATCH 0525/1167] SMB2: Separate Kerberos authentication from SMB2_sess_setup Add helper functions and split Kerberos authentication off SMB2_sess_setup. Signed-off-by: Sachin Prabhu Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/smb2pdu.c | 276 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 230 insertions(+), 46 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index d6a0456902660..386b512189b2e 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -593,6 +593,216 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) return -EIO; } +struct SMB2_sess_data { + unsigned int xid; + struct cifs_ses *ses; + struct nls_table *nls_cp; + void (*func)(struct SMB2_sess_data *); + int result; + u64 previous_session; + + /* we will send the SMB in three pieces: + * a fixed length beginning part, an optional + * SPNEGO blob (which can be zero length), and a + * last part which will include the strings + * and rest of bcc area. This allows us to avoid + * a large buffer 17K allocation + */ + int buf0_type; + struct kvec iov[2]; +}; + +static int +SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data) +{ + int rc; + struct cifs_ses *ses = sess_data->ses; + struct smb2_sess_setup_req *req; + struct TCP_Server_Info *server = ses->server; + + rc = small_smb2_init(SMB2_SESSION_SETUP, NULL, (void **) &req); + if (rc) + return rc; + + req->hdr.SessionId = 0; /* First session, not a reauthenticate */ + + /* if reconnect, we need to send previous sess id, otherwise it is 0 */ + req->PreviousSessionId = sess_data->previous_session; + + req->Flags = 0; /* MBZ */ + /* to enable echos and oplocks */ + req->hdr.CreditRequest = cpu_to_le16(3); + + /* only one of SMB2 signing flags may be set in SMB2 request */ + if (server->sign) + req->SecurityMode = SMB2_NEGOTIATE_SIGNING_REQUIRED; + else if (global_secflags & CIFSSEC_MAY_SIGN) /* one flag unlike MUST_ */ + req->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED; + else + req->SecurityMode = 0; + + req->Capabilities = 0; + req->Channel = 0; /* MBZ */ + + sess_data->iov[0].iov_base = (char *)req; + /* 4 for rfc1002 length field and 1 for pad */ + sess_data->iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; + /* + * This variable will be used to clear the buffer + * allocated above in case of any error in the calling function. + */ + sess_data->buf0_type = CIFS_SMALL_BUFFER; + + return 0; +} + +static void +SMB2_sess_free_buffer(struct SMB2_sess_data *sess_data) +{ + free_rsp_buf(sess_data->buf0_type, sess_data->iov[0].iov_base); + sess_data->buf0_type = CIFS_NO_BUFFER; +} + +static int +SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data) +{ + int rc; + struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base; + + /* Testing shows that buffer offset must be at location of Buffer[0] */ + req->SecurityBufferOffset = + cpu_to_le16(sizeof(struct smb2_sess_setup_req) - + 1 /* pad */ - 4 /* rfc1001 len */); + req->SecurityBufferLength = cpu_to_le16(sess_data->iov[1].iov_len); + + inc_rfc1001_len(req, sess_data->iov[1].iov_len - 1 /* pad */); + + /* BB add code to build os and lm fields */ + + rc = SendReceive2(sess_data->xid, sess_data->ses, + sess_data->iov, 2, + &sess_data->buf0_type, + CIFS_LOG_ERROR | CIFS_NEG_OP); + + return rc; +} + +static int +SMB2_sess_establish_session(struct SMB2_sess_data *sess_data) +{ + int rc = 0; + struct cifs_ses *ses = sess_data->ses; + + mutex_lock(&ses->server->srv_mutex); + if (ses->server->sign && ses->server->ops->generate_signingkey) { + rc = ses->server->ops->generate_signingkey(ses); + kfree(ses->auth_key.response); + ses->auth_key.response = NULL; + if (rc) { + cifs_dbg(FYI, + "SMB3 session key generation failed\n"); + mutex_unlock(&ses->server->srv_mutex); + goto keygen_exit; + } + } + if (!ses->server->session_estab) { + ses->server->sequence_number = 0x2; + ses->server->session_estab = true; + } + mutex_unlock(&ses->server->srv_mutex); + + cifs_dbg(FYI, "SMB2/3 session established successfully\n"); + spin_lock(&GlobalMid_Lock); + ses->status = CifsGood; + ses->need_reconnect = false; + spin_unlock(&GlobalMid_Lock); + +keygen_exit: + if (!ses->server->sign) { + kfree(ses->auth_key.response); + ses->auth_key.response = NULL; + } + return rc; +} + +#ifdef CONFIG_CIFS_UPCALL +static void +SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) +{ + int rc; + struct cifs_ses *ses = sess_data->ses; + struct cifs_spnego_msg *msg; + struct key *spnego_key = NULL; + struct smb2_sess_setup_rsp *rsp = NULL; + + rc = SMB2_sess_alloc_buffer(sess_data); + if (rc) + goto out; + + spnego_key = cifs_get_spnego_key(ses); + if (IS_ERR(spnego_key)) { + rc = PTR_ERR(spnego_key); + spnego_key = NULL; + goto out; + } + + msg = spnego_key->payload.data[0]; + /* + * check version field to make sure that cifs.upcall is + * sending us a response in an expected form + */ + if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) { + cifs_dbg(VFS, + "bad cifs.upcall version. Expected %d got %d", + CIFS_SPNEGO_UPCALL_VERSION, msg->version); + rc = -EKEYREJECTED; + goto out_put_spnego_key; + } + + ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len, + GFP_KERNEL); + if (!ses->auth_key.response) { + cifs_dbg(VFS, + "Kerberos can't allocate (%u bytes) memory", + msg->sesskey_len); + rc = -ENOMEM; + goto out_put_spnego_key; + } + ses->auth_key.len = msg->sesskey_len; + + sess_data->iov[1].iov_base = msg->data + msg->sesskey_len; + sess_data->iov[1].iov_len = msg->secblob_len; + + rc = SMB2_sess_sendreceive(sess_data); + if (rc) + goto out_put_spnego_key; + + rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base; + ses->Suid = rsp->hdr.SessionId; + + ses->session_flags = le16_to_cpu(rsp->SessionFlags); + if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) + cifs_dbg(VFS, "SMB3 encryption not supported yet\n"); + + rc = SMB2_sess_establish_session(sess_data); +out_put_spnego_key: + key_invalidate(spnego_key); + key_put(spnego_key); +out: + sess_data->result = rc; + sess_data->func = NULL; + SMB2_sess_free_buffer(sess_data); +} +#else +static void +SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) +{ + cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n"); + sess_data->result = -EOPNOTSUPP; + sess_data->func = NULL; +} +#endif + int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, const struct nls_table *nls_cp) @@ -605,11 +815,11 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ struct TCP_Server_Info *server = ses->server; u16 blob_length = 0; - struct key *spnego_key = NULL; char *security_blob = NULL; unsigned char *ntlmssp_blob = NULL; bool use_spnego = false; /* else use raw ntlmssp */ u64 previous_session = ses->Suid; + struct SMB2_sess_data *sess_data; cifs_dbg(FYI, "Session Setup\n"); @@ -618,6 +828,20 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, return -EIO; } + sess_data = kzalloc(sizeof(struct SMB2_sess_data), GFP_KERNEL); + if (!sess_data) + return -ENOMEM; + sess_data->xid = xid; + sess_data->ses = ses; + sess_data->buf0_type = CIFS_NO_BUFFER; + sess_data->nls_cp = (struct nls_table *) nls_cp; + sess_data->previous_session = ses->Suid; + + if (ses->sectype == Kerberos) { + SMB2_auth_kerberos(sess_data); + goto out; + } + /* * If we are here due to reconnect, free per-smb session key * in case signing was required. @@ -670,47 +894,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, /* 4 for rfc1002 length field and 1 for pad */ iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; - if (ses->sectype == Kerberos) { -#ifdef CONFIG_CIFS_UPCALL - struct cifs_spnego_msg *msg; - - spnego_key = cifs_get_spnego_key(ses); - if (IS_ERR(spnego_key)) { - rc = PTR_ERR(spnego_key); - spnego_key = NULL; - goto ssetup_exit; - } - - msg = spnego_key->payload.data[0]; - /* - * check version field to make sure that cifs.upcall is - * sending us a response in an expected form - */ - if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) { - cifs_dbg(VFS, - "bad cifs.upcall version. Expected %d got %d", - CIFS_SPNEGO_UPCALL_VERSION, msg->version); - rc = -EKEYREJECTED; - goto ssetup_exit; - } - ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len, - GFP_KERNEL); - if (!ses->auth_key.response) { - cifs_dbg(VFS, - "Kerberos can't allocate (%u bytes) memory", - msg->sesskey_len); - rc = -ENOMEM; - goto ssetup_exit; - } - ses->auth_key.len = msg->sesskey_len; - blob_length = msg->secblob_len; - iov[1].iov_base = msg->data + msg->sesskey_len; - iov[1].iov_len = blob_length; -#else - rc = -EOPNOTSUPP; - goto ssetup_exit; -#endif /* CONFIG_CIFS_UPCALL */ - } else if (phase == NtLmNegotiate) { /* if not krb5 must be ntlmssp */ + if (phase == NtLmNegotiate) { ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), GFP_KERNEL); if (ntlmssp_blob == NULL) { @@ -853,12 +1037,12 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, kfree(ses->auth_key.response); ses->auth_key.response = NULL; } - if (spnego_key) { - key_invalidate(spnego_key); - key_put(spnego_key); - } kfree(ses->ntlmssp); + return rc; +out: + rc = sess_data->result; + kfree(sess_data); return rc; } -- GitLab From 166cea4dc3a4f66f020cfb9286225ecd228ab61d Mon Sep 17 00:00:00 2001 From: Sachin Prabhu Date: Fri, 7 Oct 2016 19:11:22 +0100 Subject: [PATCH 0526/1167] SMB2: Separate RawNTLMSSP authentication from SMB2_sess_setup We split the rawntlmssp authentication into negotiate and authencate parts. We also clean up the code and add helpers. Signed-off-by: Sachin Prabhu Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/smb2pdu.c | 361 +++++++++++++++++++++------------------------- 1 file changed, 162 insertions(+), 199 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 386b512189b2e..5ca5ea4668a14 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -803,245 +803,208 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) } #endif -int -SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void +SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data); + +static void +SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data) { - struct smb2_sess_setup_req *req; + int rc; + struct cifs_ses *ses = sess_data->ses; struct smb2_sess_setup_rsp *rsp = NULL; - struct kvec iov[2]; - int rc = 0; - int resp_buftype = CIFS_NO_BUFFER; - __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ - struct TCP_Server_Info *server = ses->server; - u16 blob_length = 0; - char *security_blob = NULL; - unsigned char *ntlmssp_blob = NULL; + char *ntlmssp_blob = NULL; bool use_spnego = false; /* else use raw ntlmssp */ - u64 previous_session = ses->Suid; - struct SMB2_sess_data *sess_data; - - cifs_dbg(FYI, "Session Setup\n"); - - if (!server) { - WARN(1, "%s: server is NULL!\n", __func__); - return -EIO; - } - - sess_data = kzalloc(sizeof(struct SMB2_sess_data), GFP_KERNEL); - if (!sess_data) - return -ENOMEM; - sess_data->xid = xid; - sess_data->ses = ses; - sess_data->buf0_type = CIFS_NO_BUFFER; - sess_data->nls_cp = (struct nls_table *) nls_cp; - sess_data->previous_session = ses->Suid; - - if (ses->sectype == Kerberos) { - SMB2_auth_kerberos(sess_data); - goto out; - } - - /* - * If we are here due to reconnect, free per-smb session key - * in case signing was required. - */ - kfree(ses->auth_key.response); - ses->auth_key.response = NULL; + u16 blob_length = 0; /* * If memory allocation is successful, caller of this function * frees it. */ ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); - if (!ses->ntlmssp) - return -ENOMEM; + if (!ses->ntlmssp) { + rc = -ENOMEM; + goto out_err; + } ses->ntlmssp->sesskey_per_smbsess = true; - /* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */ - if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP) - ses->sectype = RawNTLMSSP; - -ssetup_ntlmssp_authenticate: - if (phase == NtLmChallenge) - phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ - - rc = small_smb2_init(SMB2_SESSION_SETUP, NULL, (void **) &req); + rc = SMB2_sess_alloc_buffer(sess_data); if (rc) - return rc; - - req->hdr.SessionId = 0; /* First session, not a reauthenticate */ + goto out_err; - /* if reconnect, we need to send previous sess id, otherwise it is 0 */ - req->PreviousSessionId = previous_session; + ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), + GFP_KERNEL); + if (ntlmssp_blob == NULL) { + rc = -ENOMEM; + goto out; + } - req->Flags = 0; /* MBZ */ - /* to enable echos and oplocks */ - req->hdr.CreditRequest = cpu_to_le16(3); + build_ntlmssp_negotiate_blob(ntlmssp_blob, ses); + if (use_spnego) { + /* BB eventually need to add this */ + cifs_dbg(VFS, "spnego not supported for SMB2 yet\n"); + rc = -EOPNOTSUPP; + goto out; + } else { + blob_length = sizeof(struct _NEGOTIATE_MESSAGE); + /* with raw NTLMSSP we don't encapsulate in SPNEGO */ + } + sess_data->iov[1].iov_base = ntlmssp_blob; + sess_data->iov[1].iov_len = blob_length; - /* only one of SMB2 signing flags may be set in SMB2 request */ - if (server->sign) - req->SecurityMode = SMB2_NEGOTIATE_SIGNING_REQUIRED; - else if (global_secflags & CIFSSEC_MAY_SIGN) /* one flag unlike MUST_ */ - req->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED; - else - req->SecurityMode = 0; + rc = SMB2_sess_sendreceive(sess_data); + rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base; - req->Capabilities = 0; - req->Channel = 0; /* MBZ */ + /* If true, rc here is expected and not an error */ + if (sess_data->buf0_type != CIFS_NO_BUFFER && + rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) + rc = 0; - iov[0].iov_base = (char *)req; - /* 4 for rfc1002 length field and 1 for pad */ - iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; + if (rc) + goto out; - if (phase == NtLmNegotiate) { - ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), - GFP_KERNEL); - if (ntlmssp_blob == NULL) { - rc = -ENOMEM; - goto ssetup_exit; - } - build_ntlmssp_negotiate_blob(ntlmssp_blob, ses); - if (use_spnego) { - /* blob_length = build_spnego_ntlmssp_blob( - &security_blob, - sizeof(struct _NEGOTIATE_MESSAGE), - ntlmssp_blob); */ - /* BB eventually need to add this */ - cifs_dbg(VFS, "spnego not supported for SMB2 yet\n"); - rc = -EOPNOTSUPP; - kfree(ntlmssp_blob); - goto ssetup_exit; - } else { - blob_length = sizeof(struct _NEGOTIATE_MESSAGE); - /* with raw NTLMSSP we don't encapsulate in SPNEGO */ - security_blob = ntlmssp_blob; - } - iov[1].iov_base = security_blob; - iov[1].iov_len = blob_length; - } else if (phase == NtLmAuthenticate) { - req->hdr.SessionId = ses->Suid; - rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses, - nls_cp); - if (rc) { - cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", - rc); - goto ssetup_exit; /* BB double check error handling */ - } - if (use_spnego) { - /* blob_length = build_spnego_ntlmssp_blob( - &security_blob, - blob_length, - ntlmssp_blob); */ - cifs_dbg(VFS, "spnego not supported for SMB2 yet\n"); - rc = -EOPNOTSUPP; - kfree(ntlmssp_blob); - goto ssetup_exit; - } else { - security_blob = ntlmssp_blob; - } - iov[1].iov_base = security_blob; - iov[1].iov_len = blob_length; - } else { - cifs_dbg(VFS, "illegal ntlmssp phase\n"); + if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 != + le16_to_cpu(rsp->SecurityBufferOffset)) { + cifs_dbg(VFS, "Invalid security buffer offset %d\n", + le16_to_cpu(rsp->SecurityBufferOffset)); rc = -EIO; - goto ssetup_exit; + goto out; } + rc = decode_ntlmssp_challenge(rsp->Buffer, + le16_to_cpu(rsp->SecurityBufferLength), ses); + if (rc) + goto out; - /* Testing shows that buffer offset must be at location of Buffer[0] */ - req->SecurityBufferOffset = - cpu_to_le16(sizeof(struct smb2_sess_setup_req) - - 1 /* pad */ - 4 /* rfc1001 len */); - req->SecurityBufferLength = cpu_to_le16(blob_length); + cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n"); - inc_rfc1001_len(req, blob_length - 1 /* pad */); - /* BB add code to build os and lm fields */ + ses->Suid = rsp->hdr.SessionId; + ses->session_flags = le16_to_cpu(rsp->SessionFlags); + if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) + cifs_dbg(VFS, "SMB3 encryption not supported yet\n"); - rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, - CIFS_LOG_ERROR | CIFS_NEG_OP); +out: + kfree(ntlmssp_blob); + SMB2_sess_free_buffer(sess_data); + if (!rc) { + sess_data->result = 0; + sess_data->func = SMB2_sess_auth_rawntlmssp_authenticate; + return; + } +out_err: + kfree(ses->ntlmssp); + ses->ntlmssp = NULL; + sess_data->result = rc; + sess_data->func = NULL; +} - kfree(security_blob); - rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base; - ses->Suid = rsp->hdr.SessionId; - if (resp_buftype != CIFS_NO_BUFFER && - rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) { - if (phase != NtLmNegotiate) { - cifs_dbg(VFS, "Unexpected more processing error\n"); - goto ssetup_exit; - } - if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 != - le16_to_cpu(rsp->SecurityBufferOffset)) { - cifs_dbg(VFS, "Invalid security buffer offset %d\n", - le16_to_cpu(rsp->SecurityBufferOffset)); - rc = -EIO; - goto ssetup_exit; - } +static void +SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data) +{ + int rc; + struct cifs_ses *ses = sess_data->ses; + struct smb2_sess_setup_req *req; + struct smb2_sess_setup_rsp *rsp = NULL; + unsigned char *ntlmssp_blob = NULL; + bool use_spnego = false; /* else use raw ntlmssp */ + u16 blob_length = 0; + + rc = SMB2_sess_alloc_buffer(sess_data); + if (rc) + goto out; + + req = (struct smb2_sess_setup_req *) sess_data->iov[0].iov_base; + req->hdr.SessionId = ses->Suid; - /* NTLMSSP Negotiate sent now processing challenge (response) */ - phase = NtLmChallenge; /* process ntlmssp challenge */ - rc = 0; /* MORE_PROCESSING is not an error here but expected */ - rc = decode_ntlmssp_challenge(rsp->Buffer, - le16_to_cpu(rsp->SecurityBufferLength), ses); + rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses, + sess_data->nls_cp); + if (rc) { + cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", rc); + goto out; } - /* - * BB eventually add code for SPNEGO decoding of NtlmChallenge blob, - * but at least the raw NTLMSSP case works. - */ - /* - * No tcon so can't do - * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); - */ - if (rc != 0) - goto ssetup_exit; + if (use_spnego) { + /* BB eventually need to add this */ + cifs_dbg(VFS, "spnego not supported for SMB2 yet\n"); + rc = -EOPNOTSUPP; + goto out; + } + sess_data->iov[1].iov_base = ntlmssp_blob; + sess_data->iov[1].iov_len = blob_length; + + rc = SMB2_sess_sendreceive(sess_data); + if (rc) + goto out; + + rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base; + ses->Suid = rsp->hdr.SessionId; ses->session_flags = le16_to_cpu(rsp->SessionFlags); if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) cifs_dbg(VFS, "SMB3 encryption not supported yet\n"); -ssetup_exit: - free_rsp_buf(resp_buftype, rsp); - /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */ - if ((phase == NtLmChallenge) && (rc == 0)) - goto ssetup_ntlmssp_authenticate; + rc = SMB2_sess_establish_session(sess_data); +out: + kfree(ntlmssp_blob); + SMB2_sess_free_buffer(sess_data); + kfree(ses->ntlmssp); + ses->ntlmssp = NULL; + sess_data->result = rc; + sess_data->func = NULL; +} - if (!rc) { - mutex_lock(&server->srv_mutex); - if (server->sign && server->ops->generate_signingkey) { - rc = server->ops->generate_signingkey(ses); - kfree(ses->auth_key.response); - ses->auth_key.response = NULL; - if (rc) { - cifs_dbg(FYI, - "SMB3 session key generation failed\n"); - mutex_unlock(&server->srv_mutex); - goto keygen_exit; - } - } - if (!server->session_estab) { - server->sequence_number = 0x2; - server->session_estab = true; - } - mutex_unlock(&server->srv_mutex); +static int +SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data) +{ + if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP) + ses->sectype = RawNTLMSSP; - cifs_dbg(FYI, "SMB2/3 session established successfully\n"); - spin_lock(&GlobalMid_Lock); - ses->status = CifsGood; - ses->need_reconnect = false; - spin_unlock(&GlobalMid_Lock); + switch (ses->sectype) { + case Kerberos: + sess_data->func = SMB2_auth_kerberos; + break; + case RawNTLMSSP: + sess_data->func = SMB2_sess_auth_rawntlmssp_negotiate; + break; + default: + cifs_dbg(VFS, "secType %d not supported!\n", ses->sectype); + return -EOPNOTSUPP; } -keygen_exit: - if (!server->sign) { - kfree(ses->auth_key.response); - ses->auth_key.response = NULL; + return 0; +} + +int +SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, + const struct nls_table *nls_cp) +{ + int rc = 0; + struct TCP_Server_Info *server = ses->server; + struct SMB2_sess_data *sess_data; + + cifs_dbg(FYI, "Session Setup\n"); + + if (!server) { + WARN(1, "%s: server is NULL!\n", __func__); + return -EIO; } - kfree(ses->ntlmssp); - return rc; -out: + sess_data = kzalloc(sizeof(struct SMB2_sess_data), GFP_KERNEL); + if (!sess_data) + return -ENOMEM; + + rc = SMB2_select_sec(ses, sess_data); + if (rc) + goto out; + sess_data->xid = xid; + sess_data->ses = ses; + sess_data->buf0_type = CIFS_NO_BUFFER; + sess_data->nls_cp = (struct nls_table *) nls_cp; + + while (sess_data->func) + sess_data->func(sess_data); + rc = sess_data->result; +out: kfree(sess_data); return rc; } -- GitLab From f2cca6a7c99fdeadacd0bdc37d825c4bc2b03653 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Fri, 7 Oct 2016 17:26:36 -0700 Subject: [PATCH 0527/1167] CIFS: Fix persistent handles re-opening on reconnect openFileList of tcon can be changed while cifs_reopen_file() is called that can lead to an unexpected behavior when we return to the loop. Fix this by introducing a temp list for keeping all file handles that need to be reopen. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 1 + fs/cifs/file.c | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d9a17288baf3a..0c828d3c48c38 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1065,6 +1065,7 @@ struct cifsFileInfo { kuid_t uid; /* allows finding which FileInfo structure */ __u32 pid; /* process id who opened file */ struct cifs_fid fid; /* file id from remote */ + struct list_head rlist; /* reconnect list */ /* BB add lock scope info here if needed */ ; /* lock scope id (0 if none) */ struct dentry *dentry; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8f27c8a74384b..07c14f9217cb8 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -763,19 +763,31 @@ int cifs_close(struct inode *inode, struct file *file) void cifs_reopen_persistent_handles(struct cifs_tcon *tcon) { - struct cifsFileInfo *open_file = NULL; + struct cifsFileInfo *open_file; struct list_head *tmp; struct list_head *tmp1; + struct list_head tmp_list; + + cifs_dbg(FYI, "Reopen persistent handles"); + INIT_LIST_HEAD(&tmp_list); /* list all files open on tree connection, reopen resilient handles */ spin_lock(&tcon->open_file_lock); - list_for_each_safe(tmp, tmp1, &tcon->openFileList) { + list_for_each(tmp, &tcon->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, tlist); - spin_unlock(&tcon->open_file_lock); - cifs_reopen_file(open_file, false /* do not flush */); - spin_lock(&tcon->open_file_lock); + if (!open_file->invalidHandle) + continue; + cifsFileInfo_get(open_file); + list_add_tail(&open_file->rlist, &tmp_list); } spin_unlock(&tcon->open_file_lock); + + list_for_each_safe(tmp, tmp1, &tmp_list) { + open_file = list_entry(tmp, struct cifsFileInfo, rlist); + cifs_reopen_file(open_file, false /* do not flush */); + list_del_init(&open_file->rlist); + cifsFileInfo_put(open_file); + } } int cifs_closedir(struct inode *inode, struct file *file) -- GitLab From de74025052ef63852d80a444ea19f2bdd7bec63f Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Tue, 11 Oct 2016 15:34:07 -0700 Subject: [PATCH 0528/1167] CIFS: Reset read oplock to NONE if we have mandatory locks after reopen We are already doing the same thing for an ordinary open case: we can't keep read oplock on a file if we have mandatory byte-range locks because pagereading can conflict with these locks on a server. Fix it by setting oplock level to NONE. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/file.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 07c14f9217cb8..7f5f6176c6f15 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -739,6 +739,15 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) * to the server to get the new inode info. */ + /* + * If the server returned a read oplock and we have mandatory brlocks, + * set oplock level to None. + */ + if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) { + cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n"); + oplock = 0; + } + server->ops->set_fid(cfile, &cfile->fid, oplock); if (oparms.reconnect) cifs_relock_file(cfile); -- GitLab From cb348edb6bef7250d1d0f8f2d7dac152d8b52626 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 4 Oct 2016 14:40:44 +0200 Subject: [PATCH 0529/1167] ovl: explain error values when removing acl from workdir Suggested-by: Linus Torvalds Signed-off-by: Miklos Szeredi --- fs/overlayfs/super.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 8ccebaf64c5b3..eff0f909cd788 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -832,6 +832,19 @@ static struct dentry *ovl_workdir_create(struct vfsmount *mnt, if (err) goto out_dput; + /* + * Try to remove POSIX ACL xattrs from workdir. We are good if: + * + * a) success (there was a POSIX ACL xattr and was removed) + * b) -ENODATA (there was no POSIX ACL xattr) + * c) -EOPNOTSUPP (POSIX ACL xattrs are not supported) + * + * There are various other error values that could effectively + * mean that the xattr doesn't exist (e.g. -ERANGE is returned + * if the xattr name is too long), but the set of filesystems + * allowed as upper are limited to "normal" ones, where checking + * for the above two errors is sufficient. + */ err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_DEFAULT); if (err && err != -ENODATA && err != -EOPNOTSUPP) goto out_dput; -- GitLab From 78a3fa4f3249055b472983065b30c02392cf7e2a Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 4 Oct 2016 14:40:44 +0200 Subject: [PATCH 0530/1167] ovl: use generic_readlink All filesystems that are backers for overlayfs would also use generic_readlink(). Move this logic to the overlay itself, which is a nice cleanup. Signed-off-by: Miklos Szeredi --- fs/overlayfs/inode.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index ce5d7dfaf7693..50dc214c44f2d 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -176,25 +176,6 @@ static const char *ovl_get_link(struct dentry *dentry, return p; } -static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz) -{ - struct path realpath; - struct inode *realinode; - const struct cred *old_cred; - int err; - - ovl_path_real(dentry, &realpath); - realinode = realpath.dentry->d_inode; - - if (!realinode->i_op->readlink) - return -EINVAL; - - old_cred = ovl_override_creds(dentry->d_sb); - err = realinode->i_op->readlink(realpath.dentry, buf, bufsiz); - revert_creds(old_cred); - return err; -} - bool ovl_is_private_xattr(const char *name) { return strncmp(name, OVL_XATTR_PREFIX, @@ -381,7 +362,7 @@ static const struct inode_operations ovl_file_inode_operations = { static const struct inode_operations ovl_symlink_inode_operations = { .setattr = ovl_setattr, .get_link = ovl_get_link, - .readlink = ovl_readlink, + .readlink = generic_readlink, .getattr = ovl_getattr, .setxattr = generic_setxattr, .getxattr = generic_getxattr, -- GitLab From d60874cd58fcb21372f2df698c20f8cf2f78fdcb Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 4 Oct 2016 14:40:45 +0200 Subject: [PATCH 0531/1167] vfs: add vfs_get_link() helper This helper is for filesystems that want to read the symlink and are better off with the get_link() interface (returning a char *) rather than the readlink() interface (copy into a userspace buffer). Also call the LSM hook for readlink (not get_link) since this is for symlink reading not following. Signed-off-by: Miklos Szeredi --- fs/namei.c | 25 +++++++++++++++++++++++++ include/linux/fs.h | 1 + 2 files changed, 26 insertions(+) diff --git a/fs/namei.c b/fs/namei.c index adb04146df092..8a2c2959da08e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4677,6 +4677,31 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) } EXPORT_SYMBOL(generic_readlink); +/** + * vfs_get_link - get symlink body + * @dentry: dentry on which to get symbolic link + * @done: caller needs to free returned data with this + * + * Calls security hook and i_op->get_link() on the supplied inode. + * + * It does not touch atime. That's up to the caller if necessary. + * + * Does not work on "special" symlinks like /proc/$$/fd/N + */ +const char *vfs_get_link(struct dentry *dentry, struct delayed_call *done) +{ + const char *res = ERR_PTR(-EINVAL); + struct inode *inode = d_inode(dentry); + + if (d_is_symlink(dentry)) { + res = ERR_PTR(security_inode_readlink(dentry)); + if (!res) + res = inode->i_op->get_link(dentry, inode, done); + } + return res; +} +EXPORT_SYMBOL(vfs_get_link); + /* get the link contents into pagecache */ const char *page_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *callback) diff --git a/include/linux/fs.h b/include/linux/fs.h index 901e25d495ccf..bc8ac5108368e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2919,6 +2919,7 @@ extern int vfs_stat(const char __user *, struct kstat *); extern int vfs_lstat(const char __user *, struct kstat *); extern int vfs_fstat(unsigned int, struct kstat *); extern int vfs_fstatat(int , const char __user *, struct kstat *, int); +extern const char *vfs_get_link(struct dentry *, struct delayed_call *); extern int __generic_block_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, -- GitLab From 7764235becf3b72bd124400fbffe670531322135 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 4 Oct 2016 14:40:45 +0200 Subject: [PATCH 0532/1167] ovl: use vfs_get_link() Resulting in a complete removal of a function basically implementing the inverse of vfs_readlink(). As a bonus, now the proper security hook is also called. Signed-off-by: Miklos Szeredi --- fs/overlayfs/copy_up.c | 46 ++++++------------------------------------ fs/overlayfs/inode.c | 10 +-------- 2 files changed, 7 insertions(+), 49 deletions(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 796d06fafd091..e9d4013ed3c6a 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -177,40 +177,6 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len) return error; } -static char *ovl_read_symlink(struct dentry *realdentry) -{ - int res; - char *buf; - struct inode *inode = realdentry->d_inode; - mm_segment_t old_fs; - - res = -EINVAL; - if (!inode->i_op->readlink) - goto err; - - res = -ENOMEM; - buf = (char *) __get_free_page(GFP_KERNEL); - if (!buf) - goto err; - - old_fs = get_fs(); - set_fs(get_ds()); - /* The cast to a user pointer is valid due to the set_fs() */ - res = inode->i_op->readlink(realdentry, - (char __user *)buf, PAGE_SIZE - 1); - set_fs(old_fs); - if (res < 0) { - free_page((unsigned long) buf); - goto err; - } - buf[res] = '\0'; - - return buf; - -err: - return ERR_PTR(res); -} - static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat) { struct iattr attr = { @@ -342,18 +308,20 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, struct path *lowerpath, struct kstat *stat) { + DEFINE_DELAYED_CALL(done); struct dentry *workdir = ovl_workdir(dentry); int err; struct kstat pstat; struct path parentpath; + struct dentry *lowerdentry = lowerpath->dentry; struct dentry *upperdir; struct dentry *upperdentry; - char *link = NULL; + const char *link = NULL; if (WARN_ON(!workdir)) return -EROFS; - ovl_do_check_copy_up(lowerpath->dentry); + ovl_do_check_copy_up(lowerdentry); ovl_path_upper(parent, &parentpath); upperdir = parentpath.dentry; @@ -363,7 +331,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, return err; if (S_ISLNK(stat->mode)) { - link = ovl_read_symlink(lowerpath->dentry); + link = vfs_get_link(lowerdentry, &done); if (IS_ERR(link)) return PTR_ERR(link); } @@ -388,9 +356,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, } out_unlock: unlock_rename(workdir, upperdir); - - if (link) - free_page((unsigned long) link); + do_delayed_call(&done); return err; } diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 50dc214c44f2d..bc6d261db669f 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -156,22 +156,14 @@ static const char *ovl_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { - struct dentry *realdentry; - struct inode *realinode; const struct cred *old_cred; const char *p; if (!dentry) return ERR_PTR(-ECHILD); - realdentry = ovl_dentry_real(dentry); - realinode = realdentry->d_inode; - - if (WARN_ON(!realinode->i_op->get_link)) - return ERR_PTR(-EPERM); - old_cred = ovl_override_creds(dentry->d_sb); - p = realinode->i_op->get_link(realdentry, realinode, done); + p = vfs_get_link(ovl_dentry_real(dentry), done); revert_creds(old_cred); return p; } -- GitLab From 1ec6ec14a2943f6f611fc1d5fb2d4eaa85bd9d72 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Fri, 14 Oct 2016 09:48:53 +0800 Subject: [PATCH 0533/1167] x86/smp: Add irq_enter/exit() in smp_reschedule_interrupt() =============================== [ INFO: suspicious RCU usage. ] 4.8.0+ #24 Not tainted ------------------------------- ./arch/x86/include/asm/msr-trace.h:47 suspicious rcu_dereference_check() usage! other info that might help us debug this: RCU used illegally from idle CPU! rcu_scheduler_active = 1, debug_locks = 0 RCU used illegally from extended quiescent state! no locks held by swapper/1/0. [] do_trace_write_msr+0x135/0x140 [] native_write_msr+0x20/0x30 [] native_apic_msr_eoi_write+0x1d/0x30 [] smp_reschedule_interrupt+0x1d/0x30 [] reschedule_interrupt+0x96/0xa0 Reschedule interrupt may be called in cpu idle state. This causes lockdep check warning above. Add irq_enter/exit() in smp_reschedule_interrupt(), irq_enter() tells the RCU subsystems to end the extended quiescent state, so the following trace call in ack_APIC_irq() works correctly. Signed-off-by: Wanpeng Li Cc: Peter Zijlstra Cc: Mike Galbraith Link: http://lkml.kernel.org/r/1476409733-5133-1-git-send-email-wanpeng.li@hotmail.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/smp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 658777cf38512..ac2ee87deb55a 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -259,8 +259,10 @@ static inline void __smp_reschedule_interrupt(void) __visible void smp_reschedule_interrupt(struct pt_regs *regs) { + irq_enter(); ack_APIC_irq(); __smp_reschedule_interrupt(); + irq_exit(); /* * KVM uses this interrupt to force a cpu out of guest mode */ -- GitLab From c836eeda3e1e652d424bbbbb908f07eb7380448c Mon Sep 17 00:00:00 2001 From: "Longpeng(Mike)" Date: Fri, 14 Oct 2016 08:42:20 +0800 Subject: [PATCH 0534/1167] x86: Remove duplicate rtit status MSR macro The MSR_IA32_RTIT_STATUS is defined twice, so remove one. Signed-off-by: Longpeng(Mike) Acked-by: Borislav Petkov Cc: len.brown@intel.com Cc: peterz@infradead.org Cc: rafael.j.wysocki@intel.com Cc: alexander.shishkin@linux.intel.com Cc: ray.huang@amd.com Cc: Aravind.Gopalakrishnan@amd.com Cc: wu.wubin@huawei.com Cc: srinivas.pandruvada@linux.intel.com Cc: zhaoshenglong@huawei.com Cc: vladimir_zapolskiy@mentor.com Link: http://lkml.kernel.org/r/1476405740-80816-1-git-send-email-longpeng2@huawei.com Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/msr-index.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 56f4c6676b290..78f3760ca1f29 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -88,7 +88,6 @@ #define MSR_IA32_RTIT_CTL 0x00000570 #define MSR_IA32_RTIT_STATUS 0x00000571 -#define MSR_IA32_RTIT_STATUS 0x00000571 #define MSR_IA32_RTIT_ADDR0_A 0x00000580 #define MSR_IA32_RTIT_ADDR0_B 0x00000581 #define MSR_IA32_RTIT_ADDR1_A 0x00000582 -- GitLab From c0ca8df717061ae3d2ea624024033103c64210ae Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 13 Oct 2016 16:15:32 +0300 Subject: [PATCH 0535/1167] irqchip/eznps: Acknowledge NPS_IPI before calling the handler IPI_IRQ (also TIMER0_IRQ) should be acked before the action->handler is called in handle_percpu_devid_irq. The IPI irq is edge sensitive and we might miss an IPI interrupt if it is triggered again while the handler runs. Fixes: 44df427c894a ("irqchip: add nps Internal and external irqchips") Signed-off-by: Noam Camus Cc: marc.zyngier@arm.com Cc: jason@lakedaemon.net Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1476364532-12634-1-git-send-email-noamca@mellanox.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-eznps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-eznps.c b/drivers/irqchip/irq-eznps.c index efbf0e4304b70..ebc2b0b15f677 100644 --- a/drivers/irqchip/irq-eznps.c +++ b/drivers/irqchip/irq-eznps.c @@ -85,7 +85,7 @@ static void nps400_irq_eoi_global(struct irq_data *irqd) nps_ack_gic(); } -static void nps400_irq_eoi(struct irq_data *irqd) +static void nps400_irq_ack(struct irq_data *irqd) { unsigned int __maybe_unused irq = irqd_to_hwirq(irqd); @@ -103,7 +103,7 @@ static struct irq_chip nps400_irq_chip_percpu = { .name = "NPS400 IC", .irq_mask = nps400_irq_mask, .irq_unmask = nps400_irq_unmask, - .irq_eoi = nps400_irq_eoi, + .irq_ack = nps400_irq_ack, }; static int nps400_irq_map(struct irq_domain *d, unsigned int virq, -- GitLab From c024f06b3de372cd67f86b142992ac88fc3a7d18 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 13 Oct 2016 20:35:30 +0000 Subject: [PATCH 0536/1167] irqchip/jcore: Fix lost per-cpu interrupts The J-Core AIC does not have separate interrupt numbers reserved for cpu-local vs global interrupts. Instead, the driver requesting the irq is expected to know whether its device uses per-cpu interrupts or not. Previously it was assumed that handle_simple_irq could work for both cases, but it intentionally drops interrupts for an irq number that already has a handler running. This resulted in the timer interrupt for one cpu being lost when multiple cpus' timers were set for approximately the same expiration time, leading to stalls. In theory the same could also happen with IPIs. To solve the problem, instead of registering handle_simple_irq as the handler, register a wrapper function which checks whether the irq to be handled was requested as per-cpu or not, and passes it to handle_simple_irq or handle_percpu_irq accordingly. Fixes: 981b58f66cfc ("irqchip/jcore-aic: Add J-Core AIC driver") Signed-off-by: Rich Felker Cc: Marc Zyngier Cc: Jason Cooper Cc: linux-sh@vger.kernel.org Link: http://lkml.kernel.org/r/f18cec30bc17e3f52e478dd9f6714bfab02f227f.1476390724.git.dalias@libc.org Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-jcore-aic.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-jcore-aic.c b/drivers/irqchip/irq-jcore-aic.c index 84b01dec277df..033bccb41455c 100644 --- a/drivers/irqchip/irq-jcore-aic.c +++ b/drivers/irqchip/irq-jcore-aic.c @@ -25,12 +25,30 @@ static struct irq_chip jcore_aic; +/* + * The J-Core AIC1 and AIC2 are cpu-local interrupt controllers and do + * not distinguish or use distinct irq number ranges for per-cpu event + * interrupts (timer, IPI). Since information to determine whether a + * particular irq number should be treated as per-cpu is not available + * at mapping time, we use a wrapper handler function which chooses + * the right handler at runtime based on whether IRQF_PERCPU was used + * when requesting the irq. + */ + +static void handle_jcore_irq(struct irq_desc *desc) +{ + if (irqd_is_per_cpu(irq_desc_get_irq_data(desc))) + handle_percpu_irq(desc); + else + handle_simple_irq(desc); +} + static int jcore_aic_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct irq_chip *aic = d->host_data; - irq_set_chip_and_handler(irq, aic, handle_simple_irq); + irq_set_chip_and_handler(irq, aic, handle_jcore_irq); return 0; } -- GitLab From d102eb5c1ac5e6743b1c6d145c06a25d98ad1375 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Oct 2016 10:26:21 +0300 Subject: [PATCH 0537/1167] irqchip/gicv3: Handle loop timeout proper The timeout loop terminates when the loop count is zero, but the decrement of the count variable is post check. So count is -1 when we check for the timeout and therefor the error message is supressed. Change it to predecrement, so the error message is emitted. [ tglx: Massaged changelog ] Fixes: a2c225101234 ("irqchip: gic-v3: Refactor gic_enable_redist to support both enabling and disabling") Signed-off-by: Dan Carpenter Acked-by: Sudeep Holla Cc: Marc Zyngier Cc: kernel-janitors@vger.kernel.org Cc: Jason Cooper Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20161014072534.GA15168@mwanda Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 9b81bd8b929c0..19d642eae096b 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -153,7 +153,7 @@ static void gic_enable_redist(bool enable) return; /* No PM support in this redistributor */ } - while (count--) { + while (--count) { val = readl_relaxed(rbase + GICR_WAKER); if (enable ^ (bool)(val & GICR_WAKER_ChildrenAsleep)) break; -- GitLab From 68d00f332e0ba7f60f212be74ede290c9f873bc5 Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Tue, 11 Oct 2016 22:47:20 +0300 Subject: [PATCH 0538/1167] ip6_tunnel: fix ip6_tnl_lookup The commit ea3dc9601bda ("ip6_tunnel: Add support for wildcard tunnel endpoints.") introduces support for wildcards in tunnels endpoints, but in some rare circumstances ip6_tnl_lookup selects wrong tunnel interface relying only on source or destination address of the packet and not checking presence of wildcard in tunnels endpoints. Later in ip6_tnl_rcv this packets can be dicarded because of difference in ipproto even if fallback device have proper ipproto configuration. This patch adds checks of wildcard endpoint in tunnel avoiding such behavior Fixes: ea3dc9601bda ("ip6_tunnel: Add support for wildcard tunnel endpoints.") Signed-off-by: Vadim Fedorenko Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 6a66adba0c229..5692d6b8da95a 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -157,6 +157,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_ hash = HASH(&any, local); for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { if (ipv6_addr_equal(local, &t->parms.laddr) && + ipv6_addr_any(&t->parms.raddr) && (t->dev->flags & IFF_UP)) return t; } @@ -164,6 +165,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_ hash = HASH(remote, &any); for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { if (ipv6_addr_equal(remote, &t->parms.raddr) && + ipv6_addr_any(&t->parms.laddr) && (t->dev->flags & IFF_UP)) return t; } -- GitLab From a220445f9f4382c36a53d8ef3e08165fa27f7e2c Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Wed, 12 Oct 2016 10:10:40 +0200 Subject: [PATCH 0539/1167] ipv6: correctly add local routes when lo goes up The goal of the patch is to fix this scenario: ip link add dummy1 type dummy ip link set dummy1 up ip link set lo down ; ip link set lo up After that sequence, the local route to the link layer address of dummy1 is not there anymore. When the loopback is set down, all local routes are deleted by addrconf_ifdown()/rt6_ifdown(). At this time, the rt6_info entry still exists, because the corresponding idev has a reference on it. After the rcu grace period, dst_rcu_free() is called, and thus ___dst_free(), which will set obsolete to DST_OBSOLETE_DEAD. In this case, init_loopback() is called before dst_rcu_free(), thus obsolete is still sets to something <= 0. So, the function doesn't add the route again. To avoid that race, let's check the rt6 refcnt instead. Fixes: 25fb6ca4ed9c ("net IPv6 : Fix broken IPv6 routing table after loopback down-up") Fixes: a881ae1f625c ("ipv6: don't call addrconf_dst_alloc again when enable lo") Fixes: 33d99113b110 ("ipv6: reallocate addrconf router for ipv6 address when lo device up") Reported-by: Francesco Santoro Reported-by: Samuel Gauthier CC: Balakumaran Kannan CC: Maruthi Thotad CC: Sabrina Dubroca CC: Hannes Frederic Sowa CC: Weilong Chen CC: Gao feng Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d8983e15f8594..9faafe58516ab 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3018,7 +3018,7 @@ static void init_loopback(struct net_device *dev) * lo device down, release this obsolete dst and * reallocate a new router for ifa. */ - if (sp_ifa->rt->dst.obsolete > 0) { + if (!atomic_read(&sp_ifa->rt->rt6i_ref)) { ip6_rt_put(sp_ifa->rt); sp_ifa->rt = NULL; } else { -- GitLab From 558c5eb58a5c029745b29558782d528b05aba8a5 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 12 Oct 2016 15:55:40 -0300 Subject: [PATCH 0540/1167] net: wan: slic_ds26522: add SPI device ID table to fix module autoload If the driver is built as a module, module alias information isn't filled so the module won't be autoloaded. Add a SPI device ID table and use the MODULE_DEVICE_TABLE() macro so the information is exported in the module. Before this patch: $ modinfo drivers/net/wan/slic_ds26522.ko | grep alias $ After this patch: $ modinfo drivers/net/wan/slic_ds26522.ko | grep alias alias: spi:ds26522 Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller --- drivers/net/wan/slic_ds26522.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wan/slic_ds26522.c b/drivers/net/wan/slic_ds26522.c index d06a887a23521..53366a2232f0b 100644 --- a/drivers/net/wan/slic_ds26522.c +++ b/drivers/net/wan/slic_ds26522.c @@ -223,6 +223,12 @@ static int slic_ds26522_probe(struct spi_device *spi) return ret; } +static const struct spi_device_id slic_ds26522_id[] = { + { .name = "ds26522" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(spi, slic_ds26522_id); + static const struct of_device_id slic_ds26522_match[] = { { .compatible = "maxim,ds26522", @@ -239,6 +245,7 @@ static struct spi_driver slic_ds26522_driver = { }, .probe = slic_ds26522_probe, .remove = slic_ds26522_remove, + .id_table = slic_ds26522_id, }; static int __init slic_ds26522_init(void) -- GitLab From 485c9d43382172c1b2ecf42deb4476b5e37e1264 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 12 Oct 2016 15:55:41 -0300 Subject: [PATCH 0541/1167] net: wan: slic_ds26522: Export OF module alias information When the device is registered via OF, the OF table is used to match the driver instead of the SPI device ID table, but the entries in the later are used as aliasses to load the module if the driver was not built-in. This is because the SPI core always reports an SPI module alias instead of an OF one, but that could change so it's better to always export it. Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller --- drivers/net/wan/slic_ds26522.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wan/slic_ds26522.c b/drivers/net/wan/slic_ds26522.c index 53366a2232f0b..b776a0ab106c0 100644 --- a/drivers/net/wan/slic_ds26522.c +++ b/drivers/net/wan/slic_ds26522.c @@ -235,6 +235,7 @@ static const struct of_device_id slic_ds26522_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, slic_ds26522_match); static struct spi_driver slic_ds26522_driver = { .driver = { -- GitLab From 059f01410822b9a37fac0f4da8c2202c2d39e7a5 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 12 Oct 2016 16:05:59 -0300 Subject: [PATCH 0542/1167] net: wan: slic_ds26522: Allow driver to built if COMPILE_TEST is enabled The driver only has runtime but no build time dependency with FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE. So it can be built for testing purposes if the COMPILE_TEST option is enabled. This is useful to have more build coverage and make sure that the driver is not affected by changes that could cause build regressions. Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller --- drivers/net/wan/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 33ab3345d333b..4e9fe75d70675 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -294,7 +294,7 @@ config FSL_UCC_HDLC config SLIC_DS26522 tristate "Slic Maxim ds26522 card support" depends on SPI - depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE + depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE || COMPILE_TEST help This module initializes and configures the slic maxim card in T1 or E1 mode. -- GitLab From f56f7d2e1cbe6a34dbda177d4d6245d8f8cb94bd Mon Sep 17 00:00:00 2001 From: Alexander Alemayhu Date: Thu, 13 Oct 2016 17:09:51 +0200 Subject: [PATCH 0543/1167] Documentation/networking: update git urls to use https over http This fixes the following errors when trying to clone the urls: Cloning into 'net'... fatal: repository 'http://git.kernel.org/cgit/linux/kernel/git/davem/net.git/' not found Cloning into 'net-next'... fatal: repository 'http://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/' not found Cloning into 'linux'... fatal: repository 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/' not found Cloning into 'stable-queue'... fatal: repository 'http://git.kernel.org/cgit/linux/kernel/git/stable/stable-queue.git/' not found Signed-off-by: Alexander Alemayhu Signed-off-by: David S. Miller --- Documentation/networking/netdev-FAQ.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/networking/netdev-FAQ.txt b/Documentation/networking/netdev-FAQ.txt index 0fe1c6e0dbcd5..a20b2fae942b2 100644 --- a/Documentation/networking/netdev-FAQ.txt +++ b/Documentation/networking/netdev-FAQ.txt @@ -29,8 +29,8 @@ A: There are always two trees (git repositories) in play. Both are driven Linus, and net-next is where the new code goes for the future release. You can find the trees here: - http://git.kernel.org/?p=linux/kernel/git/davem/net.git - http://git.kernel.org/?p=linux/kernel/git/davem/net-next.git + https://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git + https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git Q: How often do changes from these trees make it to the mainline Linus tree? @@ -76,7 +76,7 @@ Q: So where are we now in this cycle? A: Load the mainline (Linus) page here: - http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git + https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git and note the top of the "tags" section. If it is rc1, it is early in the dev cycle. If it was tagged rc7 a week ago, then a release @@ -123,7 +123,7 @@ A: Normally Greg Kroah-Hartman collects stable commits himself, but It contains the patches which Dave has selected, but not yet handed off to Greg. If Greg already has the patch, then it will be here: - http://git.kernel.org/cgit/linux/kernel/git/stable/stable-queue.git + https://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git A quick way to find whether the patch is in this stable-queue is to simply clone the repo, and then git grep the mainline commit ID, e.g. -- GitLab From fc791b6335152c5278dc4a4991bcb2d329f806f9 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 13 Oct 2016 18:26:56 +0200 Subject: [PATCH 0544/1167] IB/ipoib: move back IB LL address into the hard header After the commit 9207f9d45b0a ("net: preserve IP control block during GSO segmentation"), the GSO CB and the IPoIB CB conflict. That destroy the IPoIB address information cached there, causing a severe performance regression, as better described here: http://marc.info/?l=linux-kernel&m=146787279825501&w=2 This change moves the data cached by the IPoIB driver from the skb control lock into the IPoIB hard header, as done before the commit 936d7de3d736 ("IPoIB: Stop lying about hard_header_len and use skb->cb to stash LL addresses"). In order to avoid GRO issue, on packet reception, the IPoIB driver stash into the skb a dummy pseudo header, so that the received packets have actually a hard header matching the declared length. To avoid changing the connected mode maximum mtu, the allocated head buffer size is increased by the pseudo header length. After this commit, IPoIB performances are back to pre-regression value. v2 -> v3: rebased v1 -> v2: avoid changing the max mtu, increasing the head buf size Fixes: 9207f9d45b0a ("net: preserve IP control block during GSO segmentation") Signed-off-by: Paolo Abeni Signed-off-by: David S. Miller --- drivers/infiniband/ulp/ipoib/ipoib.h | 20 ++++--- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 15 +++--- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 12 ++--- drivers/infiniband/ulp/ipoib/ipoib_main.c | 54 +++++++++++-------- .../infiniband/ulp/ipoib/ipoib_multicast.c | 6 ++- 5 files changed, 64 insertions(+), 43 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 7b8d2d9e22633..da12717a3eb79 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -63,6 +63,8 @@ enum ipoib_flush_level { enum { IPOIB_ENCAP_LEN = 4, + IPOIB_PSEUDO_LEN = 20, + IPOIB_HARD_LEN = IPOIB_ENCAP_LEN + IPOIB_PSEUDO_LEN, IPOIB_UD_HEAD_SIZE = IB_GRH_BYTES + IPOIB_ENCAP_LEN, IPOIB_UD_RX_SG = 2, /* max buffer needed for 4K mtu */ @@ -134,15 +136,21 @@ struct ipoib_header { u16 reserved; }; -struct ipoib_cb { - struct qdisc_skb_cb qdisc_cb; - u8 hwaddr[INFINIBAND_ALEN]; +struct ipoib_pseudo_header { + u8 hwaddr[INFINIBAND_ALEN]; }; -static inline struct ipoib_cb *ipoib_skb_cb(const struct sk_buff *skb) +static inline void skb_add_pseudo_hdr(struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct ipoib_cb)); - return (struct ipoib_cb *)skb->cb; + char *data = skb_push(skb, IPOIB_PSEUDO_LEN); + + /* + * only the ipoib header is present now, make room for a dummy + * pseudo header and set skb field accordingly + */ + memset(data, 0, IPOIB_PSEUDO_LEN); + skb_reset_mac_header(skb); + skb_pull(skb, IPOIB_HARD_LEN); } /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 4ad297d3de897..339a1eecdfe30 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -63,6 +63,8 @@ MODULE_PARM_DESC(cm_data_debug_level, #define IPOIB_CM_RX_DELAY (3 * 256 * HZ) #define IPOIB_CM_RX_UPDATE_MASK (0x3) +#define IPOIB_CM_RX_RESERVE (ALIGN(IPOIB_HARD_LEN, 16) - IPOIB_ENCAP_LEN) + static struct ib_qp_attr ipoib_cm_err_attr = { .qp_state = IB_QPS_ERR }; @@ -146,15 +148,15 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, struct sk_buff *skb; int i; - skb = dev_alloc_skb(IPOIB_CM_HEAD_SIZE + 12); + skb = dev_alloc_skb(ALIGN(IPOIB_CM_HEAD_SIZE + IPOIB_PSEUDO_LEN, 16)); if (unlikely(!skb)) return NULL; /* - * IPoIB adds a 4 byte header. So we need 12 more bytes to align the + * IPoIB adds a IPOIB_ENCAP_LEN byte header, this will align the * IP header to a multiple of 16. */ - skb_reserve(skb, 12); + skb_reserve(skb, IPOIB_CM_RX_RESERVE); mapping[0] = ib_dma_map_single(priv->ca, skb->data, IPOIB_CM_HEAD_SIZE, DMA_FROM_DEVICE); @@ -624,9 +626,9 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) if (wc->byte_len < IPOIB_CM_COPYBREAK) { int dlen = wc->byte_len; - small_skb = dev_alloc_skb(dlen + 12); + small_skb = dev_alloc_skb(dlen + IPOIB_CM_RX_RESERVE); if (small_skb) { - skb_reserve(small_skb, 12); + skb_reserve(small_skb, IPOIB_CM_RX_RESERVE); ib_dma_sync_single_for_cpu(priv->ca, rx_ring[wr_id].mapping[0], dlen, DMA_FROM_DEVICE); skb_copy_from_linear_data(skb, small_skb->data, dlen); @@ -663,8 +665,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) copied: skb->protocol = ((struct ipoib_header *) skb->data)->proto; - skb_reset_mac_header(skb); - skb_pull(skb, IPOIB_ENCAP_LEN); + skb_add_pseudo_hdr(skb); ++dev->stats.rx_packets; dev->stats.rx_bytes += skb->len; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index be11d5d5b8c1d..830fecb6934c8 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -128,16 +128,15 @@ static struct sk_buff *ipoib_alloc_rx_skb(struct net_device *dev, int id) buf_size = IPOIB_UD_BUF_SIZE(priv->max_ib_mtu); - skb = dev_alloc_skb(buf_size + IPOIB_ENCAP_LEN); + skb = dev_alloc_skb(buf_size + IPOIB_HARD_LEN); if (unlikely(!skb)) return NULL; /* - * IB will leave a 40 byte gap for a GRH and IPoIB adds a 4 byte - * header. So we need 4 more bytes to get to 48 and align the - * IP header to a multiple of 16. + * the IP header will be at IPOIP_HARD_LEN + IB_GRH_BYTES, that is + * 64 bytes aligned */ - skb_reserve(skb, 4); + skb_reserve(skb, sizeof(struct ipoib_pseudo_header)); mapping = priv->rx_ring[id].mapping; mapping[0] = ib_dma_map_single(priv->ca, skb->data, buf_size, @@ -253,8 +252,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) skb_pull(skb, IB_GRH_BYTES); skb->protocol = ((struct ipoib_header *) skb->data)->proto; - skb_reset_mac_header(skb); - skb_pull(skb, IPOIB_ENCAP_LEN); + skb_add_pseudo_hdr(skb); ++dev->stats.rx_packets; dev->stats.rx_bytes += skb->len; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 5636fc3da6b86..b58d9dca5c934 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -925,9 +925,12 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, ipoib_neigh_free(neigh); goto err_drop; } - if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) + if (skb_queue_len(&neigh->queue) < + IPOIB_MAX_PATH_REC_QUEUE) { + /* put pseudoheader back on for next time */ + skb_push(skb, IPOIB_PSEUDO_LEN); __skb_queue_tail(&neigh->queue, skb); - else { + } else { ipoib_warn(priv, "queue length limit %d. Packet drop.\n", skb_queue_len(&neigh->queue)); goto err_drop; @@ -964,7 +967,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, } static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, - struct ipoib_cb *cb) + struct ipoib_pseudo_header *phdr) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_path *path; @@ -972,16 +975,18 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, spin_lock_irqsave(&priv->lock, flags); - path = __path_find(dev, cb->hwaddr + 4); + path = __path_find(dev, phdr->hwaddr + 4); if (!path || !path->valid) { int new_path = 0; if (!path) { - path = path_rec_create(dev, cb->hwaddr + 4); + path = path_rec_create(dev, phdr->hwaddr + 4); new_path = 1; } if (path) { if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { + /* put pseudoheader back on for next time */ + skb_push(skb, IPOIB_PSEUDO_LEN); __skb_queue_tail(&path->queue, skb); } else { ++dev->stats.tx_dropped; @@ -1009,10 +1014,12 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, be16_to_cpu(path->pathrec.dlid)); spin_unlock_irqrestore(&priv->lock, flags); - ipoib_send(dev, skb, path->ah, IPOIB_QPN(cb->hwaddr)); + ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr)); return; } else if ((path->query || !path_rec_start(dev, path)) && skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { + /* put pseudoheader back on for next time */ + skb_push(skb, IPOIB_PSEUDO_LEN); __skb_queue_tail(&path->queue, skb); } else { ++dev->stats.tx_dropped; @@ -1026,13 +1033,15 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_neigh *neigh; - struct ipoib_cb *cb = ipoib_skb_cb(skb); + struct ipoib_pseudo_header *phdr; struct ipoib_header *header; unsigned long flags; + phdr = (struct ipoib_pseudo_header *) skb->data; + skb_pull(skb, sizeof(*phdr)); header = (struct ipoib_header *) skb->data; - if (unlikely(cb->hwaddr[4] == 0xff)) { + if (unlikely(phdr->hwaddr[4] == 0xff)) { /* multicast, arrange "if" according to probability */ if ((header->proto != htons(ETH_P_IP)) && (header->proto != htons(ETH_P_IPV6)) && @@ -1045,13 +1054,13 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } /* Add in the P_Key for multicast*/ - cb->hwaddr[8] = (priv->pkey >> 8) & 0xff; - cb->hwaddr[9] = priv->pkey & 0xff; + phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; + phdr->hwaddr[9] = priv->pkey & 0xff; - neigh = ipoib_neigh_get(dev, cb->hwaddr); + neigh = ipoib_neigh_get(dev, phdr->hwaddr); if (likely(neigh)) goto send_using_neigh; - ipoib_mcast_send(dev, cb->hwaddr, skb); + ipoib_mcast_send(dev, phdr->hwaddr, skb); return NETDEV_TX_OK; } @@ -1060,16 +1069,16 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) case htons(ETH_P_IP): case htons(ETH_P_IPV6): case htons(ETH_P_TIPC): - neigh = ipoib_neigh_get(dev, cb->hwaddr); + neigh = ipoib_neigh_get(dev, phdr->hwaddr); if (unlikely(!neigh)) { - neigh_add_path(skb, cb->hwaddr, dev); + neigh_add_path(skb, phdr->hwaddr, dev); return NETDEV_TX_OK; } break; case htons(ETH_P_ARP): case htons(ETH_P_RARP): /* for unicast ARP and RARP should always perform path find */ - unicast_arp_send(skb, dev, cb); + unicast_arp_send(skb, dev, phdr); return NETDEV_TX_OK; default: /* ethertype not supported by IPoIB */ @@ -1086,11 +1095,13 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) goto unref; } } else if (neigh->ah) { - ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(cb->hwaddr)); + ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(phdr->hwaddr)); goto unref; } if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { + /* put pseudoheader back on for next time */ + skb_push(skb, sizeof(*phdr)); spin_lock_irqsave(&priv->lock, flags); __skb_queue_tail(&neigh->queue, skb); spin_unlock_irqrestore(&priv->lock, flags); @@ -1122,8 +1133,8 @@ static int ipoib_hard_header(struct sk_buff *skb, unsigned short type, const void *daddr, const void *saddr, unsigned len) { + struct ipoib_pseudo_header *phdr; struct ipoib_header *header; - struct ipoib_cb *cb = ipoib_skb_cb(skb); header = (struct ipoib_header *) skb_push(skb, sizeof *header); @@ -1132,12 +1143,13 @@ static int ipoib_hard_header(struct sk_buff *skb, /* * we don't rely on dst_entry structure, always stuff the - * destination address into skb->cb so we can figure out where + * destination address into skb hard header so we can figure out where * to send the packet later. */ - memcpy(cb->hwaddr, daddr, INFINIBAND_ALEN); + phdr = (struct ipoib_pseudo_header *) skb_push(skb, sizeof(*phdr)); + memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); - return sizeof *header; + return IPOIB_HARD_LEN; } static void ipoib_set_mcast_list(struct net_device *dev) @@ -1759,7 +1771,7 @@ void ipoib_setup(struct net_device *dev) dev->flags |= IFF_BROADCAST | IFF_MULTICAST; - dev->hard_header_len = IPOIB_ENCAP_LEN; + dev->hard_header_len = IPOIB_HARD_LEN; dev->addr_len = INFINIBAND_ALEN; dev->type = ARPHRD_INFINIBAND; dev->tx_queue_len = ipoib_sendq_size * 2; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index d3394b6add24a..1909dd252c940 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -796,9 +796,11 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb) __ipoib_mcast_add(dev, mcast); list_add_tail(&mcast->list, &priv->multicast_list); } - if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE) + if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE) { + /* put pseudoheader back on for next time */ + skb_push(skb, sizeof(struct ipoib_pseudo_header)); skb_queue_tail(&mcast->pkt_queue, skb); - else { + } else { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } -- GitLab From 9d6280da39c04832d6abf5f4ecc8175c9aad91c0 Mon Sep 17 00:00:00 2001 From: Jiri Bohac Date: Thu, 13 Oct 2016 18:50:02 +0200 Subject: [PATCH 0545/1167] IPv6: Drop the temporary address regen_timer The randomized interface identifier (rndid) was periodically updated from the regen_timer timer. Simplify the code by updating the rndid only when needed by ipv6_try_regen_rndid(). This makes the follow-up DESYNC_FACTOR fix much simpler. Also it fixes a reference counting error in this error path, where an in6_dev_put was missing: err = addrconf_sysctl_register(ndev); if (err) { ipv6_mc_destroy_dev(ndev); - del_timer(&ndev->regen_timer); snmp6_unregister_dev(ndev); goto err_release; Signed-off-by: Jiri Bohac Signed-off-by: David S. Miller --- include/net/if_inet6.h | 1 - net/ipv6/addrconf.c | 61 +++++++----------------------------------- 2 files changed, 9 insertions(+), 53 deletions(-) diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 515352c6280a4..ae707352f4638 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -191,7 +191,6 @@ struct inet6_dev { int dead; u8 rndid[8]; - struct timer_list regen_timer; struct list_head tempaddr_list; struct in6_addr token; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 9faafe58516ab..58c3d73403a5d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -147,9 +147,8 @@ static inline void addrconf_sysctl_unregister(struct inet6_dev *idev) } #endif -static void __ipv6_regen_rndid(struct inet6_dev *idev); -static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); -static void ipv6_regen_rndid(unsigned long data); +static void ipv6_regen_rndid(struct inet6_dev *idev); +static void ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); static int ipv6_count_addresses(struct inet6_dev *idev); @@ -409,9 +408,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) goto err_release; } - /* One reference from device. We must do this before - * we invoke __ipv6_regen_rndid(). - */ + /* One reference from device. */ in6_dev_hold(ndev); if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) @@ -425,17 +422,14 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) #endif INIT_LIST_HEAD(&ndev->tempaddr_list); - setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev); if ((dev->flags&IFF_LOOPBACK) || dev->type == ARPHRD_TUNNEL || dev->type == ARPHRD_TUNNEL6 || dev->type == ARPHRD_SIT || dev->type == ARPHRD_NONE) { ndev->cnf.use_tempaddr = -1; - } else { - in6_dev_hold(ndev); - ipv6_regen_rndid((unsigned long) ndev); - } + } else + ipv6_regen_rndid(ndev); ndev->token = in6addr_any; @@ -447,7 +441,6 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) err = addrconf_sysctl_register(ndev); if (err) { ipv6_mc_destroy_dev(ndev); - del_timer(&ndev->regen_timer); snmp6_unregister_dev(ndev); goto err_release; } @@ -1222,7 +1215,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i } in6_ifa_hold(ifp); memcpy(addr.s6_addr, ifp->addr.s6_addr, 8); - __ipv6_try_regen_rndid(idev, tmpaddr); + ipv6_try_regen_rndid(idev, tmpaddr); memcpy(&addr.s6_addr[8], idev->rndid, 8); age = (now - ifp->tstamp) / HZ; tmp_valid_lft = min_t(__u32, @@ -2150,7 +2143,7 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) } /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ -static void __ipv6_regen_rndid(struct inet6_dev *idev) +static void ipv6_regen_rndid(struct inet6_dev *idev) { regen: get_random_bytes(idev->rndid, sizeof(idev->rndid)); @@ -2179,43 +2172,10 @@ static void __ipv6_regen_rndid(struct inet6_dev *idev) } } -static void ipv6_regen_rndid(unsigned long data) -{ - struct inet6_dev *idev = (struct inet6_dev *) data; - unsigned long expires; - - rcu_read_lock_bh(); - write_lock_bh(&idev->lock); - - if (idev->dead) - goto out; - - __ipv6_regen_rndid(idev); - - expires = jiffies + - idev->cnf.temp_prefered_lft * HZ - - idev->cnf.regen_max_retry * idev->cnf.dad_transmits * - NEIGH_VAR(idev->nd_parms, RETRANS_TIME) - - idev->cnf.max_desync_factor * HZ; - if (time_before(expires, jiffies)) { - pr_warn("%s: too short regeneration interval; timer disabled for %s\n", - __func__, idev->dev->name); - goto out; - } - - if (!mod_timer(&idev->regen_timer, expires)) - in6_dev_hold(idev); - -out: - write_unlock_bh(&idev->lock); - rcu_read_unlock_bh(); - in6_dev_put(idev); -} - -static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) +static void ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) { if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0) - __ipv6_regen_rndid(idev); + ipv6_regen_rndid(idev); } /* @@ -3594,9 +3554,6 @@ static int addrconf_ifdown(struct net_device *dev, int how) if (!how) idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); - if (how && del_timer(&idev->regen_timer)) - in6_dev_put(idev); - /* Step 3: clear tempaddr list */ while (!list_empty(&idev->tempaddr_list)) { ifa = list_first_entry(&idev->tempaddr_list, -- GitLab From 76506a986dc31394fd1f2741db037d29c7e57843 Mon Sep 17 00:00:00 2001 From: Jiri Bohac Date: Thu, 13 Oct 2016 18:52:15 +0200 Subject: [PATCH 0546/1167] IPv6: fix DESYNC_FACTOR The IPv6 temporary address generation uses a variable called DESYNC_FACTOR to prevent hosts updating the addresses at the same time. Quoting RFC 4941: ... The value DESYNC_FACTOR is a random value (different for each client) that ensures that clients don't synchronize with each other and generate new addresses at exactly the same time ... DESYNC_FACTOR is defined as: DESYNC_FACTOR -- A random value within the range 0 - MAX_DESYNC_FACTOR. It is computed once at system start (rather than each time it is used) and must never be greater than (TEMP_VALID_LIFETIME - REGEN_ADVANCE). First, I believe the RFC has a typo in it and meant to say: "and must never be greater than (TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE)" The reason is that at various places in the RFC, DESYNC_FACTOR is used in a calculation like (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR) or (TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE - DESYNC_FACTOR). It needs to be smaller than (TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE) for the result of these calculations to be larger than zero. It's never used in a calculation together with TEMP_VALID_LIFETIME. I already submitted an errata to the rfc-editor: https://www.rfc-editor.org/errata_search.php?rfc=4941 The Linux implementation of DESYNC_FACTOR is very wrong: max_desync_factor is used in places DESYNC_FACTOR should be used. max_desync_factor is initialized to the RFC-recommended value for MAX_DESYNC_FACTOR (600) but the whole point is to get a _random_ value. And nothing ensures that the value used is not greater than (TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE), which leads to underflows. The effect can easily be observed when setting the temp_prefered_lft sysctl e.g. to 60. The preferred lifetime of the temporary addresses will be bogus. TEMP_PREFERRED_LIFETIME and REGEN_ADVANCE are not constants and can be influenced by these three sysctls: regen_max_retry, dad_transmits and temp_prefered_lft. Thus, the upper bound for desync_factor needs to be re-calculated each time a new address is generated and if desync_factor is larger than the new upper bound, a new random value needs to be re-generated. And since we already have max_desync_factor configurable per interface, we also need to calculate and store desync_factor per interface. Signed-off-by: Jiri Bohac Signed-off-by: David S. Miller --- include/net/if_inet6.h | 1 + net/ipv6/addrconf.c | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index ae707352f4638..b0576cb2ab25d 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -190,6 +190,7 @@ struct inet6_dev { __u32 if_flags; int dead; + u32 desync_factor; u8 rndid[8]; struct list_head tempaddr_list; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 58c3d73403a5d..cc7c26d05f452 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -422,6 +422,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) #endif INIT_LIST_HEAD(&ndev->tempaddr_list); + ndev->desync_factor = U32_MAX; if ((dev->flags&IFF_LOOPBACK) || dev->type == ARPHRD_TUNNEL || dev->type == ARPHRD_TUNNEL6 || @@ -1183,6 +1184,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i int ret = 0; u32 addr_flags; unsigned long now = jiffies; + long max_desync_factor; write_lock_bh(&idev->lock); if (ift) { @@ -1218,20 +1220,41 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i ipv6_try_regen_rndid(idev, tmpaddr); memcpy(&addr.s6_addr[8], idev->rndid, 8); age = (now - ifp->tstamp) / HZ; + + regen_advance = idev->cnf.regen_max_retry * + idev->cnf.dad_transmits * + NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ; + + /* recalculate max_desync_factor each time and update + * idev->desync_factor if it's larger + */ + max_desync_factor = min_t(__u32, + idev->cnf.max_desync_factor, + idev->cnf.temp_prefered_lft - regen_advance); + + if (unlikely(idev->desync_factor > max_desync_factor)) { + if (max_desync_factor > 0) { + get_random_bytes(&idev->desync_factor, + sizeof(idev->desync_factor)); + idev->desync_factor %= max_desync_factor; + } else { + idev->desync_factor = 0; + } + } + tmp_valid_lft = min_t(__u32, ifp->valid_lft, idev->cnf.temp_valid_lft + age); - tmp_prefered_lft = min_t(__u32, - ifp->prefered_lft, - idev->cnf.temp_prefered_lft + age - - idev->cnf.max_desync_factor); + tmp_prefered_lft = idev->cnf.temp_prefered_lft + age - + idev->desync_factor; + /* guard against underflow in case of concurrent updates to cnf */ + if (unlikely(tmp_prefered_lft < 0)) + tmp_prefered_lft = 0; + tmp_prefered_lft = min_t(__u32, ifp->prefered_lft, tmp_prefered_lft); tmp_plen = ifp->prefix_len; tmp_tstamp = ifp->tstamp; spin_unlock_bh(&ifp->lock); - regen_advance = idev->cnf.regen_max_retry * - idev->cnf.dad_transmits * - NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ; write_unlock_bh(&idev->lock); /* A temporary address is created only if this calculated Preferred @@ -2316,7 +2339,7 @@ static void manage_tempaddrs(struct inet6_dev *idev, max_valid = 0; max_prefered = idev->cnf.temp_prefered_lft - - idev->cnf.max_desync_factor - age; + idev->desync_factor - age; if (max_prefered < 0) max_prefered = 0; -- GitLab From ce6b04ee8b112cc9d5ef41ba697a3ffabc630f42 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 13 Oct 2016 22:57:01 +0300 Subject: [PATCH 0547/1167] qed: Fix static checker warning. Smatch compains about qed_roce_ll2_tx() dereference of the 'cdev' variable while testing its validity later. As the validation checking is an over-kill [variable would always be set], simply remove it. Reported-by: Dan Carpenter Fixes: abd49676c707 ("qed: Add RoCE ll2 & GSI support") Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_roce.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 76831a398bedf..c73638ceb1ad9 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -2809,11 +2809,6 @@ static int qed_roce_ll2_stop(struct qed_dev *cdev) struct qed_roce_ll2_info *roce_ll2 = hwfn->ll2; int rc; - if (!cdev) { - DP_ERR(cdev, "qed roce ll2 stop: invalid cdev\n"); - return -EINVAL; - } - if (roce_ll2->handle == QED_LL2_UNUSED_HANDLE) { DP_ERR(cdev, "qed roce ll2 stop: cannot stop an unused LL2\n"); return -EINVAL; @@ -2850,7 +2845,7 @@ static int qed_roce_ll2_tx(struct qed_dev *cdev, int rc; int i; - if (!cdev || !pkt || !params) { + if (!pkt || !params) { DP_ERR(cdev, "roce ll2 tx: failed tx because one of the following is NULL - drv=%p, pkt=%p, params=%p\n", cdev, pkt, params); -- GitLab From 0189efb8f4f830b9ac7a7c56c0c6e260859e950d Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 13 Oct 2016 22:57:02 +0300 Subject: [PATCH 0548/1167] qed*: Fix Kconfig dependencies with INFINIBAND_QEDR The qedr driver would require a tristate Kconfig option [to allow it to compile as a module], and toward that end we've added the INFINIBAND_QEDR option. But as we've made the compilation of the qed/qede infrastructure required for RoCE dependent on the option we'd be facing linking difficulties in case that QED=y or QEDE=y, and INFINIBAND_QEDR=m. To resolve this, we seperate between the INFINIBAND_QEDR option and the infrastructure support in qed/qede by introducing a new QED_RDMA option which would be selected by INFINIBAND_QEDR but would be a boolean instead of a tristate; Following that, the qed/qede is fixed based on this new option so that all config combinations would be supported. Fixes: cee9fbd8e2e9 ("qede: add qedr framework") Reported-by: Arnd Bergmann Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/Kconfig | 4 + drivers/net/ethernet/qlogic/qed/Makefile | 2 +- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 7 +- drivers/net/ethernet/qlogic/qed/qed_dev.c | 14 ++-- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 1 + drivers/net/ethernet/qlogic/qed/qed_ll2.h | 20 ----- drivers/net/ethernet/qlogic/qed/qed_main.c | 28 ++++--- drivers/net/ethernet/qlogic/qed/qed_roce.c | 91 +++++++++++----------- drivers/net/ethernet/qlogic/qed/qed_roce.h | 75 +++++++++++------- drivers/net/ethernet/qlogic/qed/qed_spq.c | 4 - drivers/net/ethernet/qlogic/qede/Makefile | 2 +- include/linux/qed/qede_roce.h | 2 +- 12 files changed, 120 insertions(+), 130 deletions(-) diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig index 0df1391f9663b..77567727528a0 100644 --- a/drivers/net/ethernet/qlogic/Kconfig +++ b/drivers/net/ethernet/qlogic/Kconfig @@ -107,10 +107,14 @@ config QEDE ---help--- This enables the support for ... +config QED_RDMA + bool + config INFINIBAND_QEDR tristate "QLogic qede RoCE sources [debug]" depends on QEDE && 64BIT select QED_LL2 + select QED_RDMA default n ---help--- This provides a temporary node that allows the compilation diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile index cda0af7fbc20d..967acf322c09a 100644 --- a/drivers/net/ethernet/qlogic/qed/Makefile +++ b/drivers/net/ethernet/qlogic/qed/Makefile @@ -5,4 +5,4 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \ qed_selftest.o qed_dcbx.o qed_debug.o qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o qed-$(CONFIG_QED_LL2) += qed_ll2.o -qed-$(CONFIG_INFINIBAND_QEDR) += qed_roce.o +qed-$(CONFIG_QED_RDMA) += qed_roce.o diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index 82370a1a59ad9..277db7831f7b6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -47,13 +47,8 @@ #define TM_ALIGN BIT(TM_SHIFT) #define TM_ELEM_SIZE 4 -/* ILT constants */ -#if IS_ENABLED(CONFIG_INFINIBAND_QEDR) /* For RoCE we configure to 64K to cover for RoCE max tasks 256K purpose. */ -#define ILT_DEFAULT_HW_P_SIZE 4 -#else -#define ILT_DEFAULT_HW_P_SIZE 3 -#endif +#define ILT_DEFAULT_HW_P_SIZE (IS_ENABLED(CONFIG_QED_RDMA) ? 4 : 3) #define ILT_PAGE_IN_BYTES(hw_p_size) (1U << ((hw_p_size) + 12)) #define ILT_CFG_REG(cli, reg) PSWRQ2_REG_ ## cli ## _ ## reg ## _RT_OFFSET diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 754f6a908858d..21adf52083209 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1422,19 +1422,19 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) u32 *feat_num = p_hwfn->hw_info.feat_num; int num_features = 1; -#if IS_ENABLED(CONFIG_INFINIBAND_QEDR) - /* Roce CNQ each requires: 1 status block + 1 CNQ. We divide the - * status blocks equally between L2 / RoCE but with consideration as - * to how many l2 queues / cnqs we have - */ - if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) { + if (IS_ENABLED(CONFIG_QED_RDMA) && + p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) { + /* Roce CNQ each requires: 1 status block + 1 CNQ. We divide + * the status blocks equally between L2 / RoCE but with + * consideration as to how many l2 queues / cnqs we have. + */ num_features++; feat_num[QED_RDMA_CNQ] = min_t(u32, RESC_NUM(p_hwfn, QED_SB) / num_features, RESC_NUM(p_hwfn, QED_RDMA_CNQ_RAM)); } -#endif + feat_num[QED_PF_L2_QUE] = min_t(u32, RESC_NUM(p_hwfn, QED_SB) / num_features, RESC_NUM(p_hwfn, QED_L2_QUEUE)); diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 02a8be2faed7f..7856e5241b52d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -38,6 +38,7 @@ #include "qed_mcp.h" #include "qed_reg_addr.h" #include "qed_sp.h" +#include "qed_roce.h" #define QED_LL2_RX_REGISTERED(ll2) ((ll2)->rx_queue.b_cb_registred) #define QED_LL2_TX_REGISTERED(ll2) ((ll2)->tx_queue.b_cb_registred) diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h b/drivers/net/ethernet/qlogic/qed/qed_ll2.h index 80a5dc2d652d3..4e3d62a16cab7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h @@ -293,24 +293,4 @@ void qed_ll2_setup(struct qed_hwfn *p_hwfn, */ void qed_ll2_free(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2_connections); -void qed_ll2b_complete_rx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t rx_buf_addr, - u16 data_length, - u8 data_length_error, - u16 parse_flags, - u16 vlan, - u32 src_mac_addr_hi, - u16 src_mac_addr_lo, bool b_last_packet); -void qed_ll2b_complete_tx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t first_frag_addr, - bool b_last_fragment, bool b_last_packet); -void qed_ll2b_release_tx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t first_frag_addr, - bool b_last_fragment, bool b_last_packet); #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 4ee3151e80c24..6eb2401b9e226 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -33,10 +33,8 @@ #include "qed_hw.h" #include "qed_selftest.h" -#if IS_ENABLED(CONFIG_INFINIBAND_QEDR) #define QED_ROCE_QPS (8192) #define QED_ROCE_DPIS (8) -#endif static char version[] = "QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n"; @@ -682,9 +680,7 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev, enum qed_int_mode int_mode) { struct qed_sb_cnt_info sb_cnt_info; -#if IS_ENABLED(CONFIG_INFINIBAND_QEDR) - int num_l2_queues; -#endif + int num_l2_queues = 0; int rc; int i; @@ -715,8 +711,9 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev, cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors - cdev->num_hwfns; -#if IS_ENABLED(CONFIG_INFINIBAND_QEDR) - num_l2_queues = 0; + if (!IS_ENABLED(CONFIG_QED_RDMA)) + return 0; + for_each_hwfn(cdev, i) num_l2_queues += FEAT_NUM(&cdev->hwfns[i], QED_PF_L2_QUE); @@ -738,7 +735,6 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev, DP_VERBOSE(cdev, QED_MSG_RDMA, "roce_msix_cnt=%d roce_msix_base=%d\n", cdev->int_params.rdma_msix_cnt, cdev->int_params.rdma_msix_base); -#endif return 0; } @@ -843,18 +839,20 @@ static void qed_update_pf_params(struct qed_dev *cdev, { int i; -#if IS_ENABLED(CONFIG_INFINIBAND_QEDR) - params->rdma_pf_params.num_qps = QED_ROCE_QPS; - params->rdma_pf_params.min_dpis = QED_ROCE_DPIS; - /* divide by 3 the MRs to avoid MF ILT overflow */ - params->rdma_pf_params.num_mrs = RDMA_MAX_TIDS; - params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX; -#endif for (i = 0; i < cdev->num_hwfns; i++) { struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; p_hwfn->pf_params = *params; } + + if (!IS_ENABLED(CONFIG_QED_RDMA)) + return; + + params->rdma_pf_params.num_qps = QED_ROCE_QPS; + params->rdma_pf_params.min_dpis = QED_ROCE_DPIS; + /* divide by 3 the MRs to avoid MF ILT overflow */ + params->rdma_pf_params.num_mrs = RDMA_MAX_TIDS; + params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX; } static int qed_slowpath_start(struct qed_dev *cdev, diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index c73638ceb1ad9..187df38542f72 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -129,17 +129,12 @@ static void qed_bmap_release_id(struct qed_hwfn *p_hwfn, } } -u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id) +static u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id) { /* First sb id for RoCE is after all the l2 sb */ return FEAT_NUM((struct qed_hwfn *)p_hwfn, QED_PF_L2_QUE) + rel_sb_id; } -u32 qed_rdma_query_cau_timer_res(void *rdma_cxt) -{ - return QED_CAU_DEF_RX_TIMER_RES; -} - static int qed_rdma_alloc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_rdma_start_in_params *params) @@ -275,7 +270,7 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn, return rc; } -void qed_rdma_resc_free(struct qed_hwfn *p_hwfn) +static void qed_rdma_resc_free(struct qed_hwfn *p_hwfn) { struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; @@ -527,6 +522,26 @@ static int qed_rdma_start_fw(struct qed_hwfn *p_hwfn, return qed_spq_post(p_hwfn, p_ent, NULL); } +static int qed_rdma_alloc_tid(void *rdma_cxt, u32 *itid) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID\n"); + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + rc = qed_rdma_bmap_alloc_id(p_hwfn, + &p_hwfn->p_rdma_info->tid_map, itid); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); + if (rc) + goto out; + + rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_TASK, *itid); +out: + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID - done, rc = %d\n", rc); + return rc; +} + static int qed_rdma_reserve_lkey(struct qed_hwfn *p_hwfn) { struct qed_rdma_device *dev = p_hwfn->p_rdma_info->dev; @@ -573,7 +588,7 @@ static int qed_rdma_setup(struct qed_hwfn *p_hwfn, return qed_rdma_start_fw(p_hwfn, params, p_ptt); } -int qed_rdma_stop(void *rdma_cxt) +static int qed_rdma_stop(void *rdma_cxt) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; struct rdma_close_func_ramrod_data *p_ramrod; @@ -629,8 +644,8 @@ int qed_rdma_stop(void *rdma_cxt) return rc; } -int qed_rdma_add_user(void *rdma_cxt, - struct qed_rdma_add_user_out_params *out_params) +static int qed_rdma_add_user(void *rdma_cxt, + struct qed_rdma_add_user_out_params *out_params) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; u32 dpi_start_offset; @@ -664,7 +679,7 @@ int qed_rdma_add_user(void *rdma_cxt, return rc; } -struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt) +static struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; struct qed_rdma_port *p_port = p_hwfn->p_rdma_info->port; @@ -680,7 +695,7 @@ struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt) return p_port; } -struct qed_rdma_device *qed_rdma_query_device(void *rdma_cxt) +static struct qed_rdma_device *qed_rdma_query_device(void *rdma_cxt) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; @@ -690,7 +705,7 @@ struct qed_rdma_device *qed_rdma_query_device(void *rdma_cxt) return p_hwfn->p_rdma_info->dev; } -void qed_rdma_free_tid(void *rdma_cxt, u32 itid) +static void qed_rdma_free_tid(void *rdma_cxt, u32 itid) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; @@ -701,27 +716,7 @@ void qed_rdma_free_tid(void *rdma_cxt, u32 itid) spin_unlock_bh(&p_hwfn->p_rdma_info->lock); } -int qed_rdma_alloc_tid(void *rdma_cxt, u32 *itid) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID\n"); - - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - rc = qed_rdma_bmap_alloc_id(p_hwfn, - &p_hwfn->p_rdma_info->tid_map, itid); - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); - if (rc) - goto out; - - rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_TASK, *itid); -out: - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID - done, rc = %d\n", rc); - return rc; -} - -void qed_rdma_cnq_prod_update(void *rdma_cxt, u8 qz_offset, u16 prod) +static void qed_rdma_cnq_prod_update(void *rdma_cxt, u8 qz_offset, u16 prod) { struct qed_hwfn *p_hwfn; u16 qz_num; @@ -816,7 +811,7 @@ static int qed_rdma_get_int(struct qed_dev *cdev, struct qed_int_info *info) return 0; } -int qed_rdma_alloc_pd(void *rdma_cxt, u16 *pd) +static int qed_rdma_alloc_pd(void *rdma_cxt, u16 *pd) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; u32 returned_id; @@ -1985,9 +1980,9 @@ int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) return 0; } -int qed_rdma_query_qp(void *rdma_cxt, - struct qed_rdma_qp *qp, - struct qed_rdma_query_qp_out_params *out_params) +static int qed_rdma_query_qp(void *rdma_cxt, + struct qed_rdma_qp *qp, + struct qed_rdma_query_qp_out_params *out_params) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; int rc; @@ -2022,7 +2017,7 @@ int qed_rdma_query_qp(void *rdma_cxt, return rc; } -int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp) +static int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; int rc = 0; @@ -2215,9 +2210,9 @@ static int qed_roce_modify_qp(struct qed_hwfn *p_hwfn, return rc; } -int qed_rdma_modify_qp(void *rdma_cxt, - struct qed_rdma_qp *qp, - struct qed_rdma_modify_qp_in_params *params) +static int qed_rdma_modify_qp(void *rdma_cxt, + struct qed_rdma_qp *qp, + struct qed_rdma_modify_qp_in_params *params) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; enum qed_roce_qp_state prev_state; @@ -2312,8 +2307,9 @@ int qed_rdma_modify_qp(void *rdma_cxt, return rc; } -int qed_rdma_register_tid(void *rdma_cxt, - struct qed_rdma_register_tid_in_params *params) +static int +qed_rdma_register_tid(void *rdma_cxt, + struct qed_rdma_register_tid_in_params *params) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; struct rdma_register_tid_ramrod_data *p_ramrod; @@ -2450,7 +2446,7 @@ int qed_rdma_register_tid(void *rdma_cxt, return rc; } -int qed_rdma_deregister_tid(void *rdma_cxt, u32 itid) +static int qed_rdma_deregister_tid(void *rdma_cxt, u32 itid) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; struct rdma_deregister_tid_ramrod_data *p_ramrod; @@ -2561,7 +2557,8 @@ void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) qed_rdma_dpm_conf(p_hwfn, p_ptt); } -int qed_rdma_start(void *rdma_cxt, struct qed_rdma_start_in_params *params) +static int qed_rdma_start(void *rdma_cxt, + struct qed_rdma_start_in_params *params) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; struct qed_ptt *p_ptt; @@ -2601,7 +2598,7 @@ static int qed_rdma_init(struct qed_dev *cdev, return qed_rdma_start(QED_LEADING_HWFN(cdev), params); } -void qed_rdma_remove_user(void *rdma_cxt, u16 dpi) +static void qed_rdma_remove_user(void *rdma_cxt, u16 dpi) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.h b/drivers/net/ethernet/qlogic/qed/qed_roce.h index 2f091e8a0f40b..691413176734d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.h +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.h @@ -181,36 +181,55 @@ struct qed_rdma_qp { dma_addr_t shared_queue_phys_addr; }; -int -qed_rdma_add_user(void *rdma_cxt, - struct qed_rdma_add_user_out_params *out_params); -int qed_rdma_alloc_pd(void *rdma_cxt, u16 *pd); -int qed_rdma_alloc_tid(void *rdma_cxt, u32 *tid); -int qed_rdma_deregister_tid(void *rdma_cxt, u32 tid); -void qed_rdma_free_tid(void *rdma_cxt, u32 tid); -struct qed_rdma_device *qed_rdma_query_device(void *rdma_cxt); -struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt); -int -qed_rdma_register_tid(void *rdma_cxt, - struct qed_rdma_register_tid_in_params *params); -void qed_rdma_remove_user(void *rdma_cxt, u16 dpi); -int qed_rdma_start(void *p_hwfn, struct qed_rdma_start_in_params *params); -int qed_rdma_stop(void *rdma_cxt); -u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id); -u32 qed_rdma_query_cau_timer_res(void *p_hwfn); -void qed_rdma_cnq_prod_update(void *rdma_cxt, u8 cnq_index, u16 prod); -void qed_rdma_resc_free(struct qed_hwfn *p_hwfn); +#if IS_ENABLED(CONFIG_QED_RDMA) +void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); void qed_async_roce_event(struct qed_hwfn *p_hwfn, struct event_ring_entry *p_eqe); -int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp); -int qed_rdma_modify_qp(void *rdma_cxt, struct qed_rdma_qp *qp, - struct qed_rdma_modify_qp_in_params *params); -int qed_rdma_query_qp(void *rdma_cxt, struct qed_rdma_qp *qp, - struct qed_rdma_query_qp_out_params *out_params); - -#if IS_ENABLED(CONFIG_INFINIBAND_QEDR) -void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); +void qed_ll2b_complete_tx_gsi_packet(struct qed_hwfn *p_hwfn, + u8 connection_handle, + void *cookie, + dma_addr_t first_frag_addr, + bool b_last_fragment, bool b_last_packet); +void qed_ll2b_release_tx_gsi_packet(struct qed_hwfn *p_hwfn, + u8 connection_handle, + void *cookie, + dma_addr_t first_frag_addr, + bool b_last_fragment, bool b_last_packet); +void qed_ll2b_complete_rx_gsi_packet(struct qed_hwfn *p_hwfn, + u8 connection_handle, + void *cookie, + dma_addr_t rx_buf_addr, + u16 data_length, + u8 data_length_error, + u16 parse_flags, + u16 vlan, + u32 src_mac_addr_hi, + u16 src_mac_addr_lo, bool b_last_packet); #else -void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} +static inline void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} +static inline void qed_async_roce_event(struct qed_hwfn *p_hwfn, struct event_ring_entry *p_eqe) {} +static inline void qed_ll2b_complete_tx_gsi_packet(struct qed_hwfn *p_hwfn, + u8 connection_handle, + void *cookie, + dma_addr_t first_frag_addr, + bool b_last_fragment, + bool b_last_packet) {} +static inline void qed_ll2b_release_tx_gsi_packet(struct qed_hwfn *p_hwfn, + u8 connection_handle, + void *cookie, + dma_addr_t first_frag_addr, + bool b_last_fragment, + bool b_last_packet) {} +static inline void qed_ll2b_complete_rx_gsi_packet(struct qed_hwfn *p_hwfn, + u8 connection_handle, + void *cookie, + dma_addr_t rx_buf_addr, + u16 data_length, + u8 data_length_error, + u16 parse_flags, + u16 vlan, + u32 src_mac_addr_hi, + u16 src_mac_addr_lo, + bool b_last_packet) {} #endif #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index caff41544898b..9fbaf9429fd0a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -28,9 +28,7 @@ #include "qed_reg_addr.h" #include "qed_sp.h" #include "qed_sriov.h" -#if IS_ENABLED(CONFIG_INFINIBAND_QEDR) #include "qed_roce.h" -#endif /*************************************************************************** * Structures & Definitions @@ -240,11 +238,9 @@ qed_async_event_completion(struct qed_hwfn *p_hwfn, struct event_ring_entry *p_eqe) { switch (p_eqe->protocol_id) { -#if IS_ENABLED(CONFIG_INFINIBAND_QEDR) case PROTOCOLID_ROCE: qed_async_roce_event(p_hwfn, p_eqe); return 0; -#endif case PROTOCOLID_COMMON: return qed_sriov_eqe_event(p_hwfn, p_eqe->opcode, diff --git a/drivers/net/ethernet/qlogic/qede/Makefile b/drivers/net/ethernet/qlogic/qede/Makefile index 28dc58919c851..048a230c3ce0c 100644 --- a/drivers/net/ethernet/qlogic/qede/Makefile +++ b/drivers/net/ethernet/qlogic/qede/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_QEDE) := qede.o qede-y := qede_main.o qede_ethtool.o qede-$(CONFIG_DCB) += qede_dcbnl.o -qede-$(CONFIG_INFINIBAND_QEDR) += qede_roce.o +qede-$(CONFIG_QED_RDMA) += qede_roce.o diff --git a/include/linux/qed/qede_roce.h b/include/linux/qed/qede_roce.h index 99fbe6d55acb2..f48d64b0e2fb9 100644 --- a/include/linux/qed/qede_roce.h +++ b/include/linux/qed/qede_roce.h @@ -68,7 +68,7 @@ void qede_roce_unregister_driver(struct qedr_driver *drv); bool qede_roce_supported(struct qede_dev *dev); -#if IS_ENABLED(CONFIG_INFINIBAND_QEDR) +#if IS_ENABLED(CONFIG_QED_RDMA) int qede_roce_dev_add(struct qede_dev *dev); void qede_roce_dev_event_open(struct qede_dev *dev); void qede_roce_dev_event_close(struct qede_dev *dev); -- GitLab From 8c93beaf5714b9ddfa4a0b4bcf89725d2021e903 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 13 Oct 2016 22:57:03 +0300 Subject: [PATCH 0549/1167] qed: Additional work toward cleaning C=1 This cleans many of the warnings that would arise in qed as a result of compilations with C=1; Most of those are the addition of missing 'static' to functions, although there are several other fixes as well. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 8 +- drivers/net/ethernet/qlogic/qed/qed_debug.c | 53 ++++----- drivers/net/ethernet/qlogic/qed/qed_dev.c | 5 +- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 15 +-- drivers/net/ethernet/qlogic/qed/qed_main.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_roce.c | 118 +++----------------- drivers/net/ethernet/qlogic/qed/qed_roce.h | 20 ---- drivers/net/ethernet/qlogic/qed/qed_sp.h | 1 - 8 files changed, 58 insertions(+), 164 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index 277db7831f7b6..0c42c240b5cfd 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -344,14 +344,14 @@ static struct qed_tid_seg *qed_cxt_tid_seg_info(struct qed_hwfn *p_hwfn, return NULL; } -void qed_cxt_set_srq_count(struct qed_hwfn *p_hwfn, u32 num_srqs) +static void qed_cxt_set_srq_count(struct qed_hwfn *p_hwfn, u32 num_srqs) { struct qed_cxt_mngr *p_mgr = p_hwfn->p_cxt_mngr; p_mgr->srq_count = num_srqs; } -u32 qed_cxt_get_srq_count(struct qed_hwfn *p_hwfn) +static u32 qed_cxt_get_srq_count(struct qed_hwfn *p_hwfn) { struct qed_cxt_mngr *p_mgr = p_hwfn->p_cxt_mngr; @@ -1799,8 +1799,8 @@ int qed_cxt_get_cid_info(struct qed_hwfn *p_hwfn, struct qed_cxt_info *p_info) return 0; } -void qed_rdma_set_pf_params(struct qed_hwfn *p_hwfn, - struct qed_rdma_pf_params *p_params) +static void qed_rdma_set_pf_params(struct qed_hwfn *p_hwfn, + struct qed_rdma_pf_params *p_params) { u32 num_cons, num_tasks, num_qps, num_mrs, num_srqs; enum protocol_type proto; diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c index 88e7d5bef9098..68f19ca57f965 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.c +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c @@ -405,7 +405,7 @@ struct phy_defs { /***************************** Constant Arrays *******************************/ /* Debug arrays */ -static struct dbg_array s_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {0} }; +static struct dbg_array s_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {NULL} }; /* Chip constant definitions array */ static struct chip_defs s_chip_defs[MAX_CHIP_IDS] = { @@ -4028,10 +4028,10 @@ static enum dbg_status qed_mcp_trace_read_meta(struct qed_hwfn *p_hwfn, } /* Dump MCP Trace */ -enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u32 *dump_buf, - bool dump, u32 *num_dumped_dwords) +static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 *dump_buf, + bool dump, u32 *num_dumped_dwords) { u32 trace_data_grc_addr, trace_data_size_bytes, trace_data_size_dwords; u32 trace_meta_size_dwords, running_bundle_id, offset = 0; @@ -4130,10 +4130,10 @@ enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, } /* Dump GRC FIFO */ -enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u32 *dump_buf, - bool dump, u32 *num_dumped_dwords) +static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 *dump_buf, + bool dump, u32 *num_dumped_dwords) { u32 offset = 0, dwords_read, size_param_offset; bool fifo_has_data; @@ -4192,10 +4192,10 @@ enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, } /* Dump IGU FIFO */ -enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u32 *dump_buf, - bool dump, u32 *num_dumped_dwords) +static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 *dump_buf, + bool dump, u32 *num_dumped_dwords) { u32 offset = 0, dwords_read, size_param_offset; bool fifo_has_data; @@ -4255,10 +4255,11 @@ enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, } /* Protection Override dump */ -enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u32 *dump_buf, - bool dump, u32 *num_dumped_dwords) +static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 *dump_buf, + bool dump, + u32 *num_dumped_dwords) { u32 offset = 0, size_param_offset, override_window_dwords; @@ -6339,10 +6340,11 @@ enum dbg_status qed_print_fw_asserts_results(struct qed_hwfn *p_hwfn, } /* Wrapper for unifying the idle_chk and mcp_trace api */ -enum dbg_status qed_print_idle_chk_results_wrapper(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf) +static enum dbg_status +qed_print_idle_chk_results_wrapper(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf) { u32 num_errors, num_warnnings; @@ -6413,8 +6415,8 @@ static void qed_dbg_print_feature(u8 *p_text_buf, u32 text_size) #define QED_RESULTS_BUF_MIN_SIZE 16 /* Generic function for decoding debug feature info */ -enum dbg_status format_feature(struct qed_hwfn *p_hwfn, - enum qed_dbg_features feature_idx) +static enum dbg_status format_feature(struct qed_hwfn *p_hwfn, + enum qed_dbg_features feature_idx) { struct qed_dbg_feature *feature = &p_hwfn->cdev->dbg_params.features[feature_idx]; @@ -6480,8 +6482,9 @@ enum dbg_status format_feature(struct qed_hwfn *p_hwfn, } /* Generic function for performing the dump of a debug feature. */ -enum dbg_status qed_dbg_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - enum qed_dbg_features feature_idx) +static enum dbg_status qed_dbg_dump(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_dbg_features feature_idx) { struct qed_dbg_feature *feature = &p_hwfn->cdev->dbg_params.features[feature_idx]; diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 21adf52083209..edae5fc5fccdd 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -497,12 +497,13 @@ int qed_resc_alloc(struct qed_dev *cdev) if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) { num_cons = qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ROCE, - 0) * 2; + NULL) * 2; n_eqes += num_cons + 2 * MAX_NUM_VFS_BB; } else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { num_cons = qed_cxt_get_proto_cid_count(p_hwfn, - PROTOCOLID_ISCSI, 0); + PROTOCOLID_ISCSI, + NULL); n_eqes += 2 * num_cons; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 7856e5241b52d..ce171a80bdafa 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -141,11 +141,11 @@ static void qed_ll2_kill_buffers(struct qed_dev *cdev) qed_ll2_dealloc_buffer(cdev, buffer); } -void qed_ll2b_complete_rx_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - struct qed_ll2_rx_packet *p_pkt, - struct core_rx_fast_path_cqe *p_cqe, - bool b_last_packet) +static void qed_ll2b_complete_rx_packet(struct qed_hwfn *p_hwfn, + u8 connection_handle, + struct qed_ll2_rx_packet *p_pkt, + struct core_rx_fast_path_cqe *p_cqe, + bool b_last_packet) { u16 packet_length = le16_to_cpu(p_cqe->packet_length); struct qed_ll2_buffer *buffer = p_pkt->cookie; @@ -516,7 +516,7 @@ static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, void *cookie) return rc; } -void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) +static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) { struct qed_ll2_info *p_ll2_conn = NULL; struct qed_ll2_rx_packet *p_pkt = NULL; @@ -1124,9 +1124,6 @@ static void qed_ll2_prepare_tx_packet_set_bd(struct qed_hwfn *p_hwfn, DMA_REGPAIR_LE(start_bd->addr, first_frag); start_bd->nbytes = cpu_to_le16(first_frag_len); - SET_FIELD(start_bd->bd_flags.as_bitfield, CORE_TX_BD_FLAGS_ROCE_FLAV, - type); - DP_VERBOSE(p_hwfn, (NETIF_MSG_TX_QUEUED | QED_MSG_LL2), "LL2 [q 0x%02x cid 0x%08x type 0x%08x] Tx Producer at [0x%04x] - set with a %04x bytes %02x BDs buffer at %08x:%08x\n", diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 6eb2401b9e226..8dc3f4670f640 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -1430,7 +1430,7 @@ static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) return status; } -struct qed_selftest_ops qed_selftest_ops_pass = { +static struct qed_selftest_ops qed_selftest_ops_pass = { .selftest_memory = &qed_selftest_memory, .selftest_interrupt = &qed_selftest_interrupt, .selftest_register = &qed_selftest_register, diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 187df38542f72..f3a825a8f8d52 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -157,7 +157,8 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn, p_hwfn->p_rdma_info = p_rdma_info; p_rdma_info->proto = PROTOCOLID_ROCE; - num_cons = qed_cxt_get_proto_cid_count(p_hwfn, p_rdma_info->proto, 0); + num_cons = qed_cxt_get_proto_cid_count(p_hwfn, p_rdma_info->proto, + NULL); p_rdma_info->num_qps = num_cons / 2; @@ -831,7 +832,7 @@ static int qed_rdma_alloc_pd(void *rdma_cxt, u16 *pd) return rc; } -void qed_rdma_free_pd(void *rdma_cxt, u16 pd) +static void qed_rdma_free_pd(void *rdma_cxt, u16 pd) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; @@ -868,8 +869,9 @@ qed_rdma_toggle_bit_create_resize_cq(struct qed_hwfn *p_hwfn, u16 icid) return toggle_bit; } -int qed_rdma_create_cq(void *rdma_cxt, - struct qed_rdma_create_cq_in_params *params, u16 *icid) +static int qed_rdma_create_cq(void *rdma_cxt, + struct qed_rdma_create_cq_in_params *params, + u16 *icid) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; struct qed_rdma_info *p_info = p_hwfn->p_rdma_info; @@ -952,98 +954,10 @@ int qed_rdma_create_cq(void *rdma_cxt, return rc; } -int qed_rdma_resize_cq(void *rdma_cxt, - struct qed_rdma_resize_cq_in_params *in_params, - struct qed_rdma_resize_cq_out_params *out_params) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - struct rdma_resize_cq_output_params *p_ramrod_res; - struct rdma_resize_cq_ramrod_data *p_ramrod; - enum qed_rdma_toggle_bit toggle_bit; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - dma_addr_t ramrod_res_phys; - u8 fw_return_code; - int rc = -ENOMEM; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", in_params->icid); - - p_ramrod_res = - (struct rdma_resize_cq_output_params *) - dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(struct rdma_resize_cq_output_params), - &ramrod_res_phys, GFP_KERNEL); - if (!p_ramrod_res) { - DP_NOTICE(p_hwfn, - "qed resize cq failed: cannot allocate memory (ramrod)\n"); - return rc; - } - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.cid = in_params->icid; - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - rc = qed_sp_init_request(p_hwfn, &p_ent, - RDMA_RAMROD_RESIZE_CQ, - p_hwfn->p_rdma_info->proto, &init_data); - if (rc) - goto err; - - p_ramrod = &p_ent->ramrod.rdma_resize_cq; - - p_ramrod->flags = 0; - - /* toggle the bit for every resize or create cq for a given icid */ - toggle_bit = qed_rdma_toggle_bit_create_resize_cq(p_hwfn, - in_params->icid); - - SET_FIELD(p_ramrod->flags, - RDMA_RESIZE_CQ_RAMROD_DATA_TOGGLE_BIT, toggle_bit); - - SET_FIELD(p_ramrod->flags, - RDMA_RESIZE_CQ_RAMROD_DATA_IS_TWO_LEVEL_PBL, - in_params->pbl_two_level); - - p_ramrod->pbl_log_page_size = in_params->pbl_page_size_log - 12; - p_ramrod->pbl_num_pages = cpu_to_le16(in_params->pbl_num_pages); - p_ramrod->max_cqes = cpu_to_le32(in_params->cq_size); - DMA_REGPAIR_LE(p_ramrod->pbl_addr, in_params->pbl_ptr); - DMA_REGPAIR_LE(p_ramrod->output_params_addr, ramrod_res_phys); - - rc = qed_spq_post(p_hwfn, p_ent, &fw_return_code); - if (rc) - goto err; - - if (fw_return_code != RDMA_RETURN_OK) { - DP_NOTICE(p_hwfn, "fw_return_code = %d\n", fw_return_code); - rc = -EINVAL; - goto err; - } - - out_params->prod = le32_to_cpu(p_ramrod_res->old_cq_prod); - out_params->cons = le32_to_cpu(p_ramrod_res->old_cq_cons); - - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(struct rdma_resize_cq_output_params), - p_ramrod_res, ramrod_res_phys); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Resized CQ, rc = %d\n", rc); - - return rc; - -err: dma_free_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(struct rdma_resize_cq_output_params), - p_ramrod_res, ramrod_res_phys); - DP_NOTICE(p_hwfn, "Resized CQ, Failed - rc = %d\n", rc); - - return rc; -} - -int qed_rdma_destroy_cq(void *rdma_cxt, - struct qed_rdma_destroy_cq_in_params *in_params, - struct qed_rdma_destroy_cq_out_params *out_params) +static int +qed_rdma_destroy_cq(void *rdma_cxt, + struct qed_rdma_destroy_cq_in_params *in_params, + struct qed_rdma_destroy_cq_out_params *out_params) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; struct rdma_destroy_cq_output_params *p_ramrod_res; @@ -1164,7 +1078,7 @@ static enum roce_flavor qed_roce_mode_to_flavor(enum roce_mode roce_mode) return flavor; } -int qed_roce_alloc_cid(struct qed_hwfn *p_hwfn, u16 *cid) +static int qed_roce_alloc_cid(struct qed_hwfn *p_hwfn, u16 *cid) { struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; u32 responder_icid; @@ -1788,9 +1702,9 @@ static int qed_roce_sp_destroy_qp_requester(struct qed_hwfn *p_hwfn, return rc; } -int qed_roce_query_qp(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp, - struct qed_rdma_query_qp_out_params *out_params) +static int qed_roce_query_qp(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + struct qed_rdma_query_qp_out_params *out_params) { struct roce_query_qp_resp_output_params *p_resp_ramrod_res; struct roce_query_qp_req_output_params *p_req_ramrod_res; @@ -1931,7 +1845,7 @@ int qed_roce_query_qp(struct qed_hwfn *p_hwfn, return rc; } -int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) +static int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) { u32 num_invalidated_mw = 0; u32 num_bound_mw = 0; @@ -2033,7 +1947,7 @@ static int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp) return rc; } -struct qed_rdma_qp * +static struct qed_rdma_qp * qed_rdma_create_qp(void *rdma_cxt, struct qed_rdma_create_qp_in_params *in_params, struct qed_rdma_create_qp_out_params *out_params) diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.h b/drivers/net/ethernet/qlogic/qed/qed_roce.h index 691413176734d..279f342af8db1 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.h +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.h @@ -95,26 +95,6 @@ struct qed_rdma_info { enum protocol_type proto; }; -struct qed_rdma_resize_cq_in_params { - u16 icid; - u32 cq_size; - bool pbl_two_level; - u64 pbl_ptr; - u16 pbl_num_pages; - u8 pbl_page_size_log; -}; - -struct qed_rdma_resize_cq_out_params { - u32 prod; - u32 cons; -}; - -struct qed_rdma_resize_cnq_in_params { - u32 cnq_id; - u32 pbl_page_size_log; - u64 pbl_ptr; -}; - struct qed_rdma_qp { struct regpair qp_handle; struct regpair qp_handle_async; diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index 652c908197582..b2c08e4d2a9b9 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -80,7 +80,6 @@ union ramrod_data { struct roce_destroy_qp_resp_ramrod_data roce_destroy_qp_resp; struct roce_destroy_qp_req_ramrod_data roce_destroy_qp_req; struct rdma_create_cq_ramrod_data rdma_create_cq; - struct rdma_resize_cq_ramrod_data rdma_resize_cq; struct rdma_destroy_cq_ramrod_data rdma_destroy_cq; struct rdma_srq_create_ramrod_data rdma_create_srq; struct rdma_srq_destroy_ramrod_data rdma_destroy_srq; -- GitLab From 958b3d396d7f80755e2c2e6a8f873a669f38de10 Mon Sep 17 00:00:00 2001 From: Brenden Blanco Date: Thu, 13 Oct 2016 13:13:11 -0700 Subject: [PATCH 0550/1167] net/mlx4_en: fixup xdp tx irq to match rx In cases where the number of tx rings is not a multiple of the number of rx rings, the tx completion event will be handled on a different core from the transmit and population of the ring. Races on the ring will lead to a double-free of the page, and possibly other corruption. The rings are initialized by default with a valid multiple of rings, based on the number of cpus, therefore an invalid configuration requires ethtool to change the ring layout. For instance 'ethtool -L eth0 rx 9 tx 8' will cause packets received on rx0, and XDP_TX'd to tx48, to be completed on cpu3 (48 % 9 == 3). Resolve this discrepancy by shifting the irq for the xdp tx queues to start again from 0, modulo rx_ring_num. Fixes: 9ecc2d86171a ("net/mlx4_en: add xdp forwarding and data write support") Reported-by: Jesper Dangaard Brouer Signed-off-by: Brenden Blanco Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_cq.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 132cea655920d..e3be7e44ff51f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -127,7 +127,15 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, /* For TX we use the same irq per ring we assigned for the RX */ struct mlx4_en_cq *rx_cq; - + int xdp_index; + + /* The xdp tx irq must align with the rx ring that forwards to + * it, so reindex these from 0. This should only happen when + * tx_ring_num is not a multiple of rx_ring_num. + */ + xdp_index = (priv->xdp_ring_num - priv->tx_ring_num) + cq_idx; + if (xdp_index >= 0) + cq_idx = xdp_index; cq_idx = cq_idx % priv->rx_ring_num; rx_cq = priv->rx_cq[cq_idx]; cq->vector = rx_cq->vector; -- GitLab From da146d3b5262c1866c868b9dec1bd0f834d6ded6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Oct 2016 16:07:03 -0400 Subject: [PATCH 0551/1167] drm/amdgpu: fix amdgpu_need_full_reset (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IP types are not an index. Each asic may have number and type of IPs. Properly check the the type rather than using the type id as an index. v2: fix all the IPs to not use IP type as an idx as well. Reviewed-by: Chunming Zhou Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 23 +++++++++++++++------- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 12 ++--------- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 17 ++++++++-------- drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 13 ++++++------ drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 14 ++++++------- drivers/gpu/drm/amd/amdgpu/tonga_ih.c | 14 ++++++------- drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 14 ++++++------- drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 15 +++++++------- drivers/gpu/drm/amd/include/amd_shared.h | 2 +- 9 files changed, 60 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 15afe22ca8909..fda0e57c5e0f9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2075,7 +2075,8 @@ static bool amdgpu_check_soft_reset(struct amdgpu_device *adev) if (!adev->ip_block_status[i].valid) continue; if (adev->ip_blocks[i].funcs->check_soft_reset) - adev->ip_blocks[i].funcs->check_soft_reset(adev); + adev->ip_block_status[i].hang = + adev->ip_blocks[i].funcs->check_soft_reset(adev); if (adev->ip_block_status[i].hang) { DRM_INFO("IP block:%d is hang!\n", i); asic_hang = true; @@ -2104,12 +2105,20 @@ static int amdgpu_pre_soft_reset(struct amdgpu_device *adev) static bool amdgpu_need_full_reset(struct amdgpu_device *adev) { - if (adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang || - adev->ip_block_status[AMD_IP_BLOCK_TYPE_SMC].hang || - adev->ip_block_status[AMD_IP_BLOCK_TYPE_ACP].hang || - adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang) { - DRM_INFO("Some block need full reset!\n"); - return true; + int i; + + for (i = 0; i < adev->num_ip_blocks; i++) { + if (!adev->ip_block_status[i].valid) + continue; + if ((adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) || + (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_SMC) || + (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_ACP) || + (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_DCE)) { + if (adev->ip_block_status[i].hang) { + DRM_INFO("Some block need full reset!\n"); + return true; + } + } } return false; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 613ebb7ed50f5..4108c686aa7c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -3188,16 +3188,11 @@ static int dce_v10_0_wait_for_idle(void *handle) return 0; } -static int dce_v10_0_check_soft_reset(void *handle) +static bool dce_v10_0_check_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (dce_v10_0_is_display_hung(adev)) - adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang = true; - else - adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang = false; - - return 0; + return dce_v10_0_is_display_hung(adev); } static int dce_v10_0_soft_reset(void *handle) @@ -3205,9 +3200,6 @@ static int dce_v10_0_soft_reset(void *handle) u32 srbm_soft_reset = 0, tmp; struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang) - return 0; - if (dce_v10_0_is_display_hung(adev)) srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 5b289186dc92f..ee6a48a092143 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -5144,7 +5144,7 @@ static int gfx_v8_0_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int gfx_v8_0_check_soft_reset(void *handle) +static bool gfx_v8_0_check_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 grbm_soft_reset = 0, srbm_soft_reset = 0; @@ -5196,16 +5196,14 @@ static int gfx_v8_0_check_soft_reset(void *handle) SRBM_SOFT_RESET, SOFT_RESET_SEM, 1); if (grbm_soft_reset || srbm_soft_reset) { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang = true; adev->gfx.grbm_soft_reset = grbm_soft_reset; adev->gfx.srbm_soft_reset = srbm_soft_reset; + return true; } else { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang = false; adev->gfx.grbm_soft_reset = 0; adev->gfx.srbm_soft_reset = 0; + return false; } - - return 0; } static void gfx_v8_0_inactive_hqd(struct amdgpu_device *adev, @@ -5233,7 +5231,8 @@ static int gfx_v8_0_pre_soft_reset(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 grbm_soft_reset = 0, srbm_soft_reset = 0; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang) + if ((!adev->gfx.grbm_soft_reset) && + (!adev->gfx.srbm_soft_reset)) return 0; grbm_soft_reset = adev->gfx.grbm_soft_reset; @@ -5271,7 +5270,8 @@ static int gfx_v8_0_soft_reset(void *handle) u32 grbm_soft_reset = 0, srbm_soft_reset = 0; u32 tmp; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang) + if ((!adev->gfx.grbm_soft_reset) && + (!adev->gfx.srbm_soft_reset)) return 0; grbm_soft_reset = adev->gfx.grbm_soft_reset; @@ -5341,7 +5341,8 @@ static int gfx_v8_0_post_soft_reset(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 grbm_soft_reset = 0, srbm_soft_reset = 0; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang) + if ((!adev->gfx.grbm_soft_reset) && + (!adev->gfx.srbm_soft_reset)) return 0; grbm_soft_reset = adev->gfx.grbm_soft_reset; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 1b319f5bc6962..c22ef140a5421 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -1099,7 +1099,7 @@ static int gmc_v8_0_wait_for_idle(void *handle) } -static int gmc_v8_0_check_soft_reset(void *handle) +static bool gmc_v8_0_check_soft_reset(void *handle) { u32 srbm_soft_reset = 0; struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -1116,20 +1116,19 @@ static int gmc_v8_0_check_soft_reset(void *handle) SRBM_SOFT_RESET, SOFT_RESET_MC, 1); } if (srbm_soft_reset) { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang = true; adev->mc.srbm_soft_reset = srbm_soft_reset; + return true; } else { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang = false; adev->mc.srbm_soft_reset = 0; + return false; } - return 0; } static int gmc_v8_0_pre_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang) + if (!adev->mc.srbm_soft_reset) return 0; gmc_v8_0_mc_stop(adev, &adev->mc.save); @@ -1145,7 +1144,7 @@ static int gmc_v8_0_soft_reset(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang) + if (!adev->mc.srbm_soft_reset) return 0; srbm_soft_reset = adev->mc.srbm_soft_reset; @@ -1175,7 +1174,7 @@ static int gmc_v8_0_post_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang) + if (!adev->mc.srbm_soft_reset) return 0; gmc_v8_0_mc_resume(adev, &adev->mc.save); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index f325fd86430b9..a9d10941fb53d 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -1268,7 +1268,7 @@ static int sdma_v3_0_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int sdma_v3_0_check_soft_reset(void *handle) +static bool sdma_v3_0_check_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset = 0; @@ -1281,14 +1281,12 @@ static int sdma_v3_0_check_soft_reset(void *handle) } if (srbm_soft_reset) { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang = true; adev->sdma.srbm_soft_reset = srbm_soft_reset; + return true; } else { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang = false; adev->sdma.srbm_soft_reset = 0; + return false; } - - return 0; } static int sdma_v3_0_pre_soft_reset(void *handle) @@ -1296,7 +1294,7 @@ static int sdma_v3_0_pre_soft_reset(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset = 0; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang) + if (!adev->sdma.srbm_soft_reset) return 0; srbm_soft_reset = adev->sdma.srbm_soft_reset; @@ -1315,7 +1313,7 @@ static int sdma_v3_0_post_soft_reset(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset = 0; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang) + if (!adev->sdma.srbm_soft_reset) return 0; srbm_soft_reset = adev->sdma.srbm_soft_reset; @@ -1335,7 +1333,7 @@ static int sdma_v3_0_soft_reset(void *handle) u32 srbm_soft_reset = 0; u32 tmp; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang) + if (!adev->sdma.srbm_soft_reset) return 0; srbm_soft_reset = adev->sdma.srbm_soft_reset; diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c index d127d59f953a8..b4ea229bb4498 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c @@ -373,7 +373,7 @@ static int tonga_ih_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int tonga_ih_check_soft_reset(void *handle) +static bool tonga_ih_check_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset = 0; @@ -384,21 +384,19 @@ static int tonga_ih_check_soft_reset(void *handle) SOFT_RESET_IH, 1); if (srbm_soft_reset) { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang = true; adev->irq.srbm_soft_reset = srbm_soft_reset; + return true; } else { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang = false; adev->irq.srbm_soft_reset = 0; + return false; } - - return 0; } static int tonga_ih_pre_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang) + if (!adev->irq.srbm_soft_reset) return 0; return tonga_ih_hw_fini(adev); @@ -408,7 +406,7 @@ static int tonga_ih_post_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang) + if (!adev->irq.srbm_soft_reset) return 0; return tonga_ih_hw_init(adev); @@ -419,7 +417,7 @@ static int tonga_ih_soft_reset(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang) + if (!adev->irq.srbm_soft_reset) return 0; srbm_soft_reset = adev->irq.srbm_soft_reset; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index e0fd9f21ed958..ab3df6d756562 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -770,7 +770,7 @@ static int uvd_v6_0_wait_for_idle(void *handle) } #define AMDGPU_UVD_STATUS_BUSY_MASK 0xfd -static int uvd_v6_0_check_soft_reset(void *handle) +static bool uvd_v6_0_check_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset = 0; @@ -782,19 +782,19 @@ static int uvd_v6_0_check_soft_reset(void *handle) srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_UVD, 1); if (srbm_soft_reset) { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang = true; adev->uvd.srbm_soft_reset = srbm_soft_reset; + return true; } else { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang = false; adev->uvd.srbm_soft_reset = 0; + return false; } - return 0; } + static int uvd_v6_0_pre_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang) + if (!adev->uvd.srbm_soft_reset) return 0; uvd_v6_0_stop(adev); @@ -806,7 +806,7 @@ static int uvd_v6_0_soft_reset(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang) + if (!adev->uvd.srbm_soft_reset) return 0; srbm_soft_reset = adev->uvd.srbm_soft_reset; @@ -836,7 +836,7 @@ static int uvd_v6_0_post_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang) + if (!adev->uvd.srbm_soft_reset) return 0; mdelay(5); diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 3f6db4ec0102d..8533269ec1606 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -561,7 +561,7 @@ static int vce_v3_0_wait_for_idle(void *handle) #define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) -static int vce_v3_0_check_soft_reset(void *handle) +static bool vce_v3_0_check_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset = 0; @@ -591,16 +591,15 @@ static int vce_v3_0_check_soft_reset(void *handle) srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); } WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); + mutex_unlock(&adev->grbm_idx_mutex); if (srbm_soft_reset) { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true; adev->vce.srbm_soft_reset = srbm_soft_reset; + return true; } else { - adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false; adev->vce.srbm_soft_reset = 0; + return false; } - mutex_unlock(&adev->grbm_idx_mutex); - return 0; } static int vce_v3_0_soft_reset(void *handle) @@ -608,7 +607,7 @@ static int vce_v3_0_soft_reset(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) + if (!adev->vce.srbm_soft_reset) return 0; srbm_soft_reset = adev->vce.srbm_soft_reset; @@ -638,7 +637,7 @@ static int vce_v3_0_pre_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) + if (!adev->vce.srbm_soft_reset) return 0; mdelay(5); @@ -651,7 +650,7 @@ static int vce_v3_0_post_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) + if (!adev->vce.srbm_soft_reset) return 0; mdelay(5); diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index c934b78c9e2f0..bec8125bceb0d 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -165,7 +165,7 @@ struct amd_ip_funcs { /* poll for idle */ int (*wait_for_idle)(void *handle); /* check soft reset the IP block */ - int (*check_soft_reset)(void *handle); + bool (*check_soft_reset)(void *handle); /* pre soft reset the IP block */ int (*pre_soft_reset)(void *handle); /* soft reset the IP block */ -- GitLab From 3e96dbfd5899c562e08c7ff27e5d5b21bb218e8a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Oct 2016 11:22:17 -0400 Subject: [PATCH 0552/1167] drm/amdgpu: disable smu hw first on tear down Otherwise, you can't disable dpm. Tested-by and Reviewed-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index fda0e57c5e0f9..c5e6fc5806628 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1437,6 +1437,30 @@ static int amdgpu_fini(struct amdgpu_device *adev) { int i, r; + /* need to disable SMC first */ + for (i = 0; i < adev->num_ip_blocks; i++) { + if (!adev->ip_block_status[i].hw) + continue; + if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_SMC) { + /* ungate blocks before hw fini so that we can shutdown the blocks safely */ + r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev, + AMD_CG_STATE_UNGATE); + if (r) { + DRM_ERROR("set_clockgating_state(ungate) of IP block <%s> failed %d\n", + adev->ip_blocks[i].funcs->name, r); + return r; + } + r = adev->ip_blocks[i].funcs->hw_fini((void *)adev); + /* XXX handle errors */ + if (r) { + DRM_DEBUG("hw_fini of IP block <%s> failed %d\n", + adev->ip_blocks[i].funcs->name, r); + } + adev->ip_block_status[i].hw = false; + break; + } + } + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_block_status[i].hw) continue; -- GitLab From ca3d28de6268e75739f0c5d40ec6010b1d84f03a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Oct 2016 10:08:00 -0400 Subject: [PATCH 0553/1167] drm/amdgpu/powerplay: implement thermal sensor for CZ/ST Add missing functionality. Reviewed-by: Tom St Denis Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c index 7e4fcbbbe0865..960424913496d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c @@ -1785,6 +1785,21 @@ static int cz_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_c return 0; } +static int cz_thermal_get_temperature(struct pp_hwmgr *hwmgr) +{ + int actual_temp = 0; + uint32_t val = cgs_read_ind_register(hwmgr->device, + CGS_IND_REG__SMC, ixTHM_TCON_CUR_TMP); + uint32_t temp = PHM_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP); + + if (PHM_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP_RANGE_SEL)) + actual_temp = ((temp / 8) - 49) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; + else + actual_temp = (temp / 8) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return actual_temp; +} + static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, int32_t *value) { struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); @@ -1881,6 +1896,9 @@ static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, int32_t *value) case AMDGPU_PP_SENSOR_VCE_POWER: *value = cz_hwmgr->vce_power_gated ? 0 : 1; return 0; + case AMDGPU_PP_SENSOR_GPU_TEMP: + *value = cz_thermal_get_temperature(hwmgr); + return 0; default: return -EINVAL; } -- GitLab From 154061db8853035deb258b685b8a791cf97f023f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Oct 2016 09:55:47 -0400 Subject: [PATCH 0554/1167] drm/amdgpu/dpm: implement thermal sensor for CZ/ST Previous code was just a copy/paste from KV. Reviewed-by: Tom St Denis Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/cz_dpm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c index f80a0834e889e..3c082e1437303 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c @@ -1514,14 +1514,16 @@ static int cz_dpm_set_powergating_state(void *handle, return 0; } -/* borrowed from KV, need future unify */ static int cz_dpm_get_temperature(struct amdgpu_device *adev) { int actual_temp = 0; - uint32_t temp = RREG32_SMC(0xC0300E0C); + uint32_t val = RREG32_SMC(ixTHM_TCON_CUR_TMP); + uint32_t temp = REG_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP); - if (temp) + if (REG_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP_RANGE_SEL)) actual_temp = 1000 * ((temp / 8) - 49); + else + actual_temp = 1000 * (temp / 8); return actual_temp; } -- GitLab From dcb2ff56417362c31f6b430c3c531a84581e8721 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Mon, 10 Oct 2016 17:58:32 +0200 Subject: [PATCH 0555/1167] dm mirror: fix read error on recovery after default leg failure If a default leg has failed, any read will cause a new operational default leg to be selected and the read is resubmitted. But until now the read will return failure even though it was successful due to resubmission. The reason for this is bio->bi_error was not being cleared before resubmitting the bio. Fix by clearing bio->bi_error before resubmission. Fixes: 4246a0b63bd8 ("block: add a bi_error field to struct bio") Cc: stable@vger.kernel.org # 4.3+ Signed-off-by: Heinz Mauelshagen Signed-off-by: Mike Snitzer --- drivers/md/dm-raid1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index bdf1606f67bcf..7a6254d54baf8 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1292,6 +1292,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error) dm_bio_restore(bd, bio); bio_record->details.bi_bdev = NULL; + bio->bi_error = 0; queue_bio(ms, bio, rw); return DM_ENDIO_INCOMPLETE; -- GitLab From 12a7cf5ba6c776a2621d8972c7d42e8d3d959d20 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Mon, 10 Oct 2016 18:48:06 +0200 Subject: [PATCH 0556/1167] dm mirror: use all available legs on multiple failures When any leg(s) have failed, any read will cause a new operational default leg to be selected and the read is resubmitted to it. If that new default leg fails the read too, no other still accessible legs are used to resubmit the read again -- thus failing the io. Fix by allowing the read to get resubmitted until all operational legs have been exhausted. Also, remove any details.bi_dev use as a flag. Signed-off-by: Heinz Mauelshagen Signed-off-by: Mike Snitzer --- drivers/md/dm-raid1.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 7a6254d54baf8..9a8b71067c6eb 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -145,7 +145,6 @@ static void dispatch_bios(void *context, struct bio_list *bio_list) struct dm_raid1_bio_record { struct mirror *m; - /* if details->bi_bdev == NULL, details were not saved */ struct dm_bio_details details; region_t write_region; }; @@ -1200,8 +1199,6 @@ static int mirror_map(struct dm_target *ti, struct bio *bio) struct dm_raid1_bio_record *bio_record = dm_per_bio_data(bio, sizeof(struct dm_raid1_bio_record)); - bio_record->details.bi_bdev = NULL; - if (rw == WRITE) { /* Save region for mirror_end_io() handler */ bio_record->write_region = dm_rh_bio_to_region(ms->rh, bio); @@ -1260,22 +1257,12 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error) } if (error == -EOPNOTSUPP) - goto out; + return error; if ((error == -EWOULDBLOCK) && (bio->bi_opf & REQ_RAHEAD)) - goto out; + return error; if (unlikely(error)) { - if (!bio_record->details.bi_bdev) { - /* - * There wasn't enough memory to record necessary - * information for a retry or there was no other - * mirror in-sync. - */ - DMERR_LIMIT("Mirror read failed."); - return -EIO; - } - m = bio_record->m; DMERR("Mirror read failed from %s. Trying alternative device.", @@ -1291,7 +1278,6 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error) bd = &bio_record->details; dm_bio_restore(bd, bio); - bio_record->details.bi_bdev = NULL; bio->bi_error = 0; queue_bio(ms, bio, rw); @@ -1300,9 +1286,6 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error) DMERR("All replicated volumes dead, failing I/O"); } -out: - bio_record->details.bi_bdev = NULL; - return error; } -- GitLab From 36c285c5335931d2c67b79e0d0f4e873c858c50d Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 13 Oct 2016 15:25:09 +0800 Subject: [PATCH 0557/1167] drm/amd/powerplay: notify smu no display by default. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index e7fb8e95436b1..1c73ac7c24ba5 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -1226,7 +1226,7 @@ int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to enable VR hot GPIO interrupt!", result = tmp_result); - smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)PPSMC_HasDisplay); + smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)PPSMC_NoDisplay); tmp_result = smu7_enable_sclk_control(hwmgr); PP_ASSERT_WITH_CODE((0 == tmp_result), -- GitLab From f28a9b65c9e3697ba8d2ab371fae4fea15638676 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 13 Oct 2016 15:24:12 +0800 Subject: [PATCH 0558/1167] drm/amd/powerplay: fix bug stop dpm can't work on Vi. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- .../powerplay/eventmgr/eventactionchains.c | 1 + .../gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 39 ++++++++++++------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c index 92b1178438755..8cee4e0f9fde6 100644 --- a/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c +++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c @@ -49,6 +49,7 @@ static const pem_event_action * const uninitialize_event[] = { uninitialize_display_phy_access_tasks, disable_gfx_voltage_island_power_gating_tasks, disable_gfx_clock_gating_tasks, + uninitialize_thermal_controller_tasks, set_boot_state_tasks, adjust_power_state_tasks, disable_dynamic_state_management_tasks, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 1c73ac7c24ba5..609996c84ad5a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -1030,20 +1030,19 @@ static int smu7_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr) struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); /* disable SCLK dpm */ - if (!data->sclk_dpm_key_disabled) - PP_ASSERT_WITH_CODE( - (smum_send_msg_to_smc(hwmgr->smumgr, - PPSMC_MSG_DPM_Disable) == 0), - "Failed to disable SCLK DPM!", - return -EINVAL); + if (!data->sclk_dpm_key_disabled) { + PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr), + "Trying to disable SCLK DPM when DPM is disabled", + return 0); + smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Disable); + } /* disable MCLK dpm */ if (!data->mclk_dpm_key_disabled) { - PP_ASSERT_WITH_CODE( - (smum_send_msg_to_smc(hwmgr->smumgr, - PPSMC_MSG_MCLKDPM_Disable) == 0), - "Failed to disable MCLK DPM!", - return -EINVAL); + PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr), + "Trying to disable MCLK DPM when DPM is disabled", + return 0); + smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MCLKDPM_Disable); } return 0; @@ -1069,10 +1068,13 @@ static int smu7_stop_dpm(struct pp_hwmgr *hwmgr) return -EINVAL); } - if (smu7_disable_sclk_mclk_dpm(hwmgr)) { - printk(KERN_ERR "Failed to disable Sclk DPM and Mclk DPM!"); - return -EINVAL; - } + smu7_disable_sclk_mclk_dpm(hwmgr); + + PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr), + "Trying to disable voltage DPM when DPM is disabled", + return 0); + + smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Voltage_Cntl_Disable); return 0; } @@ -1306,6 +1308,12 @@ int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE((tmp_result == 0), "Failed to disable thermal auto throttle!", result = tmp_result); + if (1 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) { + PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DisableAvfs)), + "Failed to disable AVFS!", + return -EINVAL); + } + tmp_result = smu7_stop_dpm(hwmgr); PP_ASSERT_WITH_CODE((tmp_result == 0), "Failed to stop DPM!", result = tmp_result); @@ -4328,6 +4336,7 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .set_mclk_od = smu7_set_mclk_od, .get_clock_by_type = smu7_get_clock_by_type, .read_sensor = smu7_read_sensor, + .dynamic_state_management_disable = smu7_disable_dpm_tasks, }; uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock, -- GitLab From 11ed3e0ef354cdc9c4577a187fa60a053137b507 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 12 Oct 2016 11:48:39 +0200 Subject: [PATCH 0559/1167] MIPS: Wire up new pkey_{mprotect,alloc,free} syscalls Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14380/ Signed-off-by: Ralf Baechle Signed-off-by: Linus Torvalds --- arch/mips/include/uapi/asm/unistd.h | 22 ++++++++++++++++------ arch/mips/kernel/scall32-o32.S | 3 +++ arch/mips/kernel/scall64-64.S | 3 +++ arch/mips/kernel/scall64-n32.S | 3 +++ arch/mips/kernel/scall64-o32.S | 3 +++ 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/uapi/asm/unistd.h b/arch/mips/include/uapi/asm/unistd.h index 24ad815c7f38d..3e940dbe02629 100644 --- a/arch/mips/include/uapi/asm/unistd.h +++ b/arch/mips/include/uapi/asm/unistd.h @@ -383,16 +383,20 @@ #define __NR_copy_file_range (__NR_Linux + 360) #define __NR_preadv2 (__NR_Linux + 361) #define __NR_pwritev2 (__NR_Linux + 362) +#define __NR_pkey_mprotect (__NR_Linux + 363) +#define __NR_pkey_alloc (__NR_Linux + 364) +#define __NR_pkey_free (__NR_Linux + 365) + /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_Linux_syscalls 362 +#define __NR_Linux_syscalls 365 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ #define __NR_O32_Linux 4000 -#define __NR_O32_Linux_syscalls 362 +#define __NR_O32_Linux_syscalls 365 #if _MIPS_SIM == _MIPS_SIM_ABI64 @@ -723,16 +727,19 @@ #define __NR_copy_file_range (__NR_Linux + 320) #define __NR_preadv2 (__NR_Linux + 321) #define __NR_pwritev2 (__NR_Linux + 322) +#define __NR_pkey_mprotect (__NR_Linux + 323) +#define __NR_pkey_alloc (__NR_Linux + 324) +#define __NR_pkey_free (__NR_Linux + 325) /* * Offset of the last Linux 64-bit flavoured syscall */ -#define __NR_Linux_syscalls 322 +#define __NR_Linux_syscalls 325 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ #define __NR_64_Linux 5000 -#define __NR_64_Linux_syscalls 322 +#define __NR_64_Linux_syscalls 325 #if _MIPS_SIM == _MIPS_SIM_NABI32 @@ -1067,15 +1074,18 @@ #define __NR_copy_file_range (__NR_Linux + 324) #define __NR_preadv2 (__NR_Linux + 325) #define __NR_pwritev2 (__NR_Linux + 326) +#define __NR_pkey_mprotect (__NR_Linux + 327) +#define __NR_pkey_alloc (__NR_Linux + 328) +#define __NR_pkey_free (__NR_Linux + 329) /* * Offset of the last N32 flavoured syscall */ -#define __NR_Linux_syscalls 326 +#define __NR_Linux_syscalls 329 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ #define __NR_N32_Linux 6000 -#define __NR_N32_Linux_syscalls 326 +#define __NR_N32_Linux_syscalls 329 #endif /* _UAPI_ASM_UNISTD_H */ diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index c8e43e0c4066b..c29d397eee86c 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -597,3 +597,6 @@ EXPORT(sys_call_table) PTR sys_copy_file_range /* 4360 */ PTR sys_preadv2 PTR sys_pwritev2 + PTR sys_pkey_mprotect + PTR sys_pkey_alloc + PTR sys_pkey_free /* 4365 */ diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index e6ede125059fe..0687f96ee9126 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -435,4 +435,7 @@ EXPORT(sys_call_table) PTR sys_copy_file_range /* 5320 */ PTR sys_preadv2 PTR sys_pwritev2 + PTR sys_pkey_mprotect + PTR sys_pkey_alloc + PTR sys_pkey_free /* 5325 */ .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 51d3988933f83..0331ba39a065b 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -430,4 +430,7 @@ EXPORT(sysn32_call_table) PTR sys_copy_file_range PTR compat_sys_preadv2 /* 6325 */ PTR compat_sys_pwritev2 + PTR sys_pkey_mprotect + PTR sys_pkey_alloc + PTR sys_pkey_free .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 6efa7136748f6..5a47042dd25f7 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -585,4 +585,7 @@ EXPORT(sys32_call_table) PTR sys_copy_file_range /* 4360 */ PTR compat_sys_preadv2 PTR compat_sys_pwritev2 + PTR sys_pkey_mprotect + PTR sys_pkey_alloc + PTR sys_pkey_free /* 4365 */ .size sys32_call_table,.-sys32_call_table -- GitLab From 496063426dece3f47e21f9f3387205d6ca03bd2a Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 14 Oct 2016 14:26:24 -0400 Subject: [PATCH 0560/1167] pkeys: Remove easily triggered WARN This easy-to-trigger warning shows up instantly when running Trinity on a kernel with CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS disabled. At most this should have been a printk, but the -EINVAL alone should be more than adequate indicator that something isn't available. Signed-off-by: Dave Jones Signed-off-by: Linus Torvalds --- include/linux/pkeys.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/pkeys.h b/include/linux/pkeys.h index e4c08c1ff0c59..a1bacf1150b21 100644 --- a/include/linux/pkeys.h +++ b/include/linux/pkeys.h @@ -25,7 +25,6 @@ static inline int mm_pkey_alloc(struct mm_struct *mm) static inline int mm_pkey_free(struct mm_struct *mm, int pkey) { - WARN_ONCE(1, "free of protection key when disabled"); return -EINVAL; } -- GitLab From 2e0cbc4dd077aea4f1693583fd68eaed4d60464b Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 10 Oct 2016 13:15:30 +0300 Subject: [PATCH 0561/1167] qedr: Add RoCE driver framework Adds a skeletal implementation of the qed* RoCE driver - basically the ability to communicate with the qede driver and receive notifications from it regarding various init/exit events. Signed-off-by: Rajesh Borundia Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/Kconfig | 2 + drivers/infiniband/hw/Makefile | 1 + drivers/infiniband/hw/qedr/Kconfig | 7 + drivers/infiniband/hw/qedr/Makefile | 3 + drivers/infiniband/hw/qedr/main.c | 254 ++++++++++++++++++++++++++++ drivers/infiniband/hw/qedr/qedr.h | 61 +++++++ drivers/net/ethernet/qlogic/Kconfig | 11 -- include/uapi/linux/pci_regs.h | 3 + 8 files changed, 331 insertions(+), 11 deletions(-) create mode 100644 drivers/infiniband/hw/qedr/Kconfig create mode 100644 drivers/infiniband/hw/qedr/Makefile create mode 100644 drivers/infiniband/hw/qedr/main.c create mode 100644 drivers/infiniband/hw/qedr/qedr.h diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 19a418a1b6312..fb3fb89640e59 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -89,4 +89,6 @@ source "drivers/infiniband/sw/rxe/Kconfig" source "drivers/infiniband/hw/hfi1/Kconfig" +source "drivers/infiniband/hw/qedr/Kconfig" + endif # INFINIBAND diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile index 21fe401ff178b..e7a5ed9f6f3fb 100644 --- a/drivers/infiniband/hw/Makefile +++ b/drivers/infiniband/hw/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_INFINIBAND_OCRDMA) += ocrdma/ obj-$(CONFIG_INFINIBAND_USNIC) += usnic/ obj-$(CONFIG_INFINIBAND_HFI1) += hfi1/ obj-$(CONFIG_INFINIBAND_HNS) += hns/ +obj-$(CONFIG_INFINIBAND_QEDR) += qedr/ diff --git a/drivers/infiniband/hw/qedr/Kconfig b/drivers/infiniband/hw/qedr/Kconfig new file mode 100644 index 0000000000000..7c06d85568d44 --- /dev/null +++ b/drivers/infiniband/hw/qedr/Kconfig @@ -0,0 +1,7 @@ +config INFINIBAND_QEDR + tristate "QLogic RoCE driver" + depends on 64BIT && QEDE + select QED_LL2 + ---help--- + This driver provides low-level InfiniBand over Ethernet + support for QLogic QED host channel adapters (HCAs). diff --git a/drivers/infiniband/hw/qedr/Makefile b/drivers/infiniband/hw/qedr/Makefile new file mode 100644 index 0000000000000..3a5b7a2882814 --- /dev/null +++ b/drivers/infiniband/hw/qedr/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_INFINIBAND_QEDR) := qedr.o + +qedr-y := main.o diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c new file mode 100644 index 0000000000000..7387d029a35b6 --- /dev/null +++ b/drivers/infiniband/hw/qedr/main.c @@ -0,0 +1,254 @@ +/* QLogic qedr NIC Driver + * Copyright (c) 2015-2016 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include "qedr.h" + +MODULE_DESCRIPTION("QLogic 40G/100G ROCE Driver"); +MODULE_AUTHOR("QLogic Corporation"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(QEDR_MODULE_VERSION); + +void qedr_ib_dispatch_event(struct qedr_dev *dev, u8 port_num, + enum ib_event_type type) +{ + struct ib_event ibev; + + ibev.device = &dev->ibdev; + ibev.element.port_num = port_num; + ibev.event = type; + + ib_dispatch_event(&ibev); +} + +static enum rdma_link_layer qedr_link_layer(struct ib_device *device, + u8 port_num) +{ + return IB_LINK_LAYER_ETHERNET; +} + +static int qedr_register_device(struct qedr_dev *dev) +{ + strlcpy(dev->ibdev.name, "qedr%d", IB_DEVICE_NAME_MAX); + + memcpy(dev->ibdev.node_desc, QEDR_NODE_DESC, sizeof(QEDR_NODE_DESC)); + dev->ibdev.owner = THIS_MODULE; + + dev->ibdev.get_link_layer = qedr_link_layer; + + return 0; +} + +/* QEDR sysfs interface */ +static ssize_t show_rev(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct qedr_dev *dev = dev_get_drvdata(device); + + return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->pdev->vendor); +} + +static ssize_t show_hca_type(struct device *device, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%s\n", "HCA_TYPE_TO_SET"); +} + +static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); +static DEVICE_ATTR(hca_type, S_IRUGO, show_hca_type, NULL); + +static struct device_attribute *qedr_attributes[] = { + &dev_attr_hw_rev, + &dev_attr_hca_type +}; + +static void qedr_remove_sysfiles(struct qedr_dev *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(qedr_attributes); i++) + device_remove_file(&dev->ibdev.dev, qedr_attributes[i]); +} + +static void qedr_pci_set_atomic(struct qedr_dev *dev, struct pci_dev *pdev) +{ + struct pci_dev *bridge; + u32 val; + + dev->atomic_cap = IB_ATOMIC_NONE; + + bridge = pdev->bus->self; + if (!bridge) + return; + + /* Check whether we are connected directly or via a switch */ + while (bridge && bridge->bus->parent) { + DP_DEBUG(dev, QEDR_MSG_INIT, + "Device is not connected directly to root. bridge->bus->number=%d primary=%d\n", + bridge->bus->number, bridge->bus->primary); + /* Need to check Atomic Op Routing Supported all the way to + * root complex. + */ + pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &val); + if (!(val & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) { + pcie_capability_clear_word(pdev, + PCI_EXP_DEVCTL2, + PCI_EXP_DEVCTL2_ATOMIC_REQ); + return; + } + bridge = bridge->bus->parent->self; + } + bridge = pdev->bus->self; + + /* according to bridge capability */ + pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &val); + if (val & PCI_EXP_DEVCAP2_ATOMIC_COMP64) { + pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2, + PCI_EXP_DEVCTL2_ATOMIC_REQ); + dev->atomic_cap = IB_ATOMIC_GLOB; + } else { + pcie_capability_clear_word(pdev, PCI_EXP_DEVCTL2, + PCI_EXP_DEVCTL2_ATOMIC_REQ); + } +} + +static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, + struct net_device *ndev) +{ + struct qedr_dev *dev; + int rc = 0, i; + + dev = (struct qedr_dev *)ib_alloc_device(sizeof(*dev)); + if (!dev) { + pr_err("Unable to allocate ib device\n"); + return NULL; + } + + DP_DEBUG(dev, QEDR_MSG_INIT, "qedr add device called\n"); + + dev->pdev = pdev; + dev->ndev = ndev; + dev->cdev = cdev; + + qedr_pci_set_atomic(dev, pdev); + + rc = qedr_register_device(dev); + if (rc) { + DP_ERR(dev, "Unable to allocate register device\n"); + goto init_err; + } + + for (i = 0; i < ARRAY_SIZE(qedr_attributes); i++) + if (device_create_file(&dev->ibdev.dev, qedr_attributes[i])) + goto init_err; + + DP_DEBUG(dev, QEDR_MSG_INIT, "qedr driver loaded successfully\n"); + return dev; + +init_err: + ib_dealloc_device(&dev->ibdev); + DP_ERR(dev, "qedr driver load failed rc=%d\n", rc); + + return NULL; +} + +static void qedr_remove(struct qedr_dev *dev) +{ + /* First unregister with stack to stop all the active traffic + * of the registered clients. + */ + qedr_remove_sysfiles(dev); + + ib_dealloc_device(&dev->ibdev); +} + +static int qedr_close(struct qedr_dev *dev) +{ + qedr_ib_dispatch_event(dev, 1, IB_EVENT_PORT_ERR); + + return 0; +} + +static void qedr_shutdown(struct qedr_dev *dev) +{ + qedr_close(dev); + qedr_remove(dev); +} + +/* event handling via NIC driver ensures that all the NIC specific + * initialization done before RoCE driver notifies + * event to stack. + */ +static void qedr_notify(struct qedr_dev *dev, enum qede_roce_event event) +{ + switch (event) { + case QEDE_UP: + qedr_ib_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE); + break; + case QEDE_DOWN: + qedr_close(dev); + break; + case QEDE_CLOSE: + qedr_shutdown(dev); + break; + case QEDE_CHANGE_ADDR: + qedr_ib_dispatch_event(dev, 1, IB_EVENT_GID_CHANGE); + break; + default: + pr_err("Event not supported\n"); + } +} + +static struct qedr_driver qedr_drv = { + .name = "qedr_driver", + .add = qedr_add, + .remove = qedr_remove, + .notify = qedr_notify, +}; + +static int __init qedr_init_module(void) +{ + return qede_roce_register_driver(&qedr_drv); +} + +static void __exit qedr_exit_module(void) +{ + qede_roce_unregister_driver(&qedr_drv); +} + +module_init(qedr_init_module); +module_exit(qedr_exit_module); diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h new file mode 100644 index 0000000000000..801417080f114 --- /dev/null +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -0,0 +1,61 @@ +/* QLogic qedr NIC Driver + * Copyright (c) 2015-2016 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __QEDR_H__ +#define __QEDR_H__ + +#include +#include +#include +#include + +#define QEDR_MODULE_VERSION "8.10.10.0" +#define QEDR_NODE_DESC "QLogic 579xx RoCE HCA" +#define DP_NAME(dev) ((dev)->ibdev.name) + +#define DP_DEBUG(dev, module, fmt, ...) \ + pr_debug("(%s) " module ": " fmt, \ + DP_NAME(dev) ? DP_NAME(dev) : "", ## __VA_ARGS__) + +#define QEDR_MSG_INIT "INIT" + +struct qedr_dev { + struct ib_device ibdev; + struct qed_dev *cdev; + struct pci_dev *pdev; + struct net_device *ndev; + + enum ib_atomic_cap atomic_cap; + + u32 dp_module; + u8 dp_level; +}; +#endif diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig index 0df1391f9663b..1e8339a67f6e1 100644 --- a/drivers/net/ethernet/qlogic/Kconfig +++ b/drivers/net/ethernet/qlogic/Kconfig @@ -107,15 +107,4 @@ config QEDE ---help--- This enables the support for ... -config INFINIBAND_QEDR - tristate "QLogic qede RoCE sources [debug]" - depends on QEDE && 64BIT - select QED_LL2 - default n - ---help--- - This provides a temporary node that allows the compilation - and logical testing of the InfiniBand over Ethernet support - for QLogic QED. This would be replaced by the 'real' option - once the QEDR driver is added [+relocated]. - endif # NET_VENDOR_QLOGIC diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index d812172d1d7b4..e5a2e68b2236e 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -612,6 +612,8 @@ */ #define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ #define PCI_EXP_DEVCAP2_ARI 0x00000020 /* Alternative Routing-ID */ +#define PCI_EXP_DEVCAP2_ATOMIC_ROUTE 0x00000040 /* Atomic Op routing */ +#define PCI_EXP_DEVCAP2_ATOMIC_COMP64 0x00000100 /* Atomic 64-bit compare */ #define PCI_EXP_DEVCAP2_LTR 0x00000800 /* Latency tolerance reporting */ #define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */ #define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */ @@ -619,6 +621,7 @@ #define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ #define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */ #define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */ +#define PCI_EXP_DEVCTL2_ATOMIC_REQ 0x0040 /* Set Atomic requests */ #define PCI_EXP_DEVCTL2_IDO_REQ_EN 0x0100 /* Allow IDO for requests */ #define PCI_EXP_DEVCTL2_IDO_CMP_EN 0x0200 /* Allow IDO for completions */ #define PCI_EXP_DEVCTL2_LTR_EN 0x0400 /* Enable LTR mechanism */ -- GitLab From ec72fce401c6dc6fc89c49f30dc2c67920c4d5bf Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 10 Oct 2016 13:15:31 +0300 Subject: [PATCH 0562/1167] qedr: Add support for RoCE HW init Allocate and setup RoCE resources, interrupts and completion queues. Adds device attributes. Signed-off-by: Rajesh Borundia Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/main.c | 418 ++++++++++++++++++++- drivers/infiniband/hw/qedr/qedr.h | 123 ++++++ drivers/infiniband/hw/qedr/qedr_hsi.h | 56 +++ drivers/infiniband/hw/qedr/qedr_hsi_rdma.h | 96 +++++ 4 files changed, 691 insertions(+), 2 deletions(-) create mode 100644 drivers/infiniband/hw/qedr/qedr_hsi.h create mode 100644 drivers/infiniband/hw/qedr/qedr_hsi_rdma.h diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 7387d029a35b6..67805941d138a 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include "qedr.h" MODULE_DESCRIPTION("QLogic 40G/100G ROCE Driver"); @@ -61,6 +63,17 @@ static enum rdma_link_layer qedr_link_layer(struct ib_device *device, return IB_LINK_LAYER_ETHERNET; } +static void qedr_get_dev_fw_str(struct ib_device *ibdev, char *str, + size_t str_len) +{ + struct qedr_dev *qedr = get_qedr_dev(ibdev); + u32 fw_ver = (u32)qedr->attr.fw_ver; + + snprintf(str, str_len, "%d. %d. %d. %d", + (fw_ver >> 24) & 0xFF, (fw_ver >> 16) & 0xFF, + (fw_ver >> 8) & 0xFF, fw_ver & 0xFF); +} + static int qedr_register_device(struct qedr_dev *dev) { strlcpy(dev->ibdev.name, "qedr%d", IB_DEVICE_NAME_MAX); @@ -69,10 +82,139 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.owner = THIS_MODULE; dev->ibdev.get_link_layer = qedr_link_layer; + dev->ibdev.get_dev_fw_str = qedr_get_dev_fw_str; return 0; } +/* This function allocates fast-path status block memory */ +static int qedr_alloc_mem_sb(struct qedr_dev *dev, + struct qed_sb_info *sb_info, u16 sb_id) +{ + struct status_block *sb_virt; + dma_addr_t sb_phys; + int rc; + + sb_virt = dma_alloc_coherent(&dev->pdev->dev, + sizeof(*sb_virt), &sb_phys, GFP_KERNEL); + if (!sb_virt) + return -ENOMEM; + + rc = dev->ops->common->sb_init(dev->cdev, sb_info, + sb_virt, sb_phys, sb_id, + QED_SB_TYPE_CNQ); + if (rc) { + pr_err("Status block initialization failed\n"); + dma_free_coherent(&dev->pdev->dev, sizeof(*sb_virt), + sb_virt, sb_phys); + return rc; + } + + return 0; +} + +static void qedr_free_mem_sb(struct qedr_dev *dev, + struct qed_sb_info *sb_info, int sb_id) +{ + if (sb_info->sb_virt) { + dev->ops->common->sb_release(dev->cdev, sb_info, sb_id); + dma_free_coherent(&dev->pdev->dev, sizeof(*sb_info->sb_virt), + (void *)sb_info->sb_virt, sb_info->sb_phys); + } +} + +static void qedr_free_resources(struct qedr_dev *dev) +{ + int i; + + for (i = 0; i < dev->num_cnq; i++) { + qedr_free_mem_sb(dev, &dev->sb_array[i], dev->sb_start + i); + dev->ops->common->chain_free(dev->cdev, &dev->cnq_array[i].pbl); + } + + kfree(dev->cnq_array); + kfree(dev->sb_array); + kfree(dev->sgid_tbl); +} + +static int qedr_alloc_resources(struct qedr_dev *dev) +{ + struct qedr_cnq *cnq; + __le16 *cons_pi; + u16 n_entries; + int i, rc; + + dev->sgid_tbl = kzalloc(sizeof(union ib_gid) * + QEDR_MAX_SGID, GFP_KERNEL); + if (!dev->sgid_tbl) + return -ENOMEM; + + spin_lock_init(&dev->sgid_lock); + + /* Allocate Status blocks for CNQ */ + dev->sb_array = kcalloc(dev->num_cnq, sizeof(*dev->sb_array), + GFP_KERNEL); + if (!dev->sb_array) { + rc = -ENOMEM; + goto err1; + } + + dev->cnq_array = kcalloc(dev->num_cnq, + sizeof(*dev->cnq_array), GFP_KERNEL); + if (!dev->cnq_array) { + rc = -ENOMEM; + goto err2; + } + + dev->sb_start = dev->ops->rdma_get_start_sb(dev->cdev); + + /* Allocate CNQ PBLs */ + n_entries = min_t(u32, QED_RDMA_MAX_CNQ_SIZE, QEDR_ROCE_MAX_CNQ_SIZE); + for (i = 0; i < dev->num_cnq; i++) { + cnq = &dev->cnq_array[i]; + + rc = qedr_alloc_mem_sb(dev, &dev->sb_array[i], + dev->sb_start + i); + if (rc) + goto err3; + + rc = dev->ops->common->chain_alloc(dev->cdev, + QED_CHAIN_USE_TO_CONSUME, + QED_CHAIN_MODE_PBL, + QED_CHAIN_CNT_TYPE_U16, + n_entries, + sizeof(struct regpair *), + &cnq->pbl); + if (rc) + goto err4; + + cnq->dev = dev; + cnq->sb = &dev->sb_array[i]; + cons_pi = dev->sb_array[i].sb_virt->pi_array; + cnq->hw_cons_ptr = &cons_pi[QED_ROCE_PROTOCOL_INDEX]; + cnq->index = i; + sprintf(cnq->name, "qedr%d@pci:%s", i, pci_name(dev->pdev)); + + DP_DEBUG(dev, QEDR_MSG_INIT, "cnq[%d].cons=%d\n", + i, qed_chain_get_cons_idx(&cnq->pbl)); + } + + return 0; +err4: + qedr_free_mem_sb(dev, &dev->sb_array[i], dev->sb_start + i); +err3: + for (--i; i >= 0; i--) { + dev->ops->common->chain_free(dev->cdev, &dev->cnq_array[i].pbl); + qedr_free_mem_sb(dev, &dev->sb_array[i], dev->sb_start + i); + } + kfree(dev->cnq_array); +err2: + kfree(dev->sb_array); +err1: + kfree(dev->sgid_tbl); + return rc; +} + /* QEDR sysfs interface */ static ssize_t show_rev(struct device *device, struct device_attribute *attr, char *buf) @@ -146,9 +288,240 @@ static void qedr_pci_set_atomic(struct qedr_dev *dev, struct pci_dev *pdev) } } +static const struct qed_rdma_ops *qed_ops; + +#define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo)) + +static irqreturn_t qedr_irq_handler(int irq, void *handle) +{ + u16 hw_comp_cons, sw_comp_cons; + struct qedr_cnq *cnq = handle; + + qed_sb_ack(cnq->sb, IGU_INT_DISABLE, 0); + + qed_sb_update_sb_idx(cnq->sb); + + hw_comp_cons = le16_to_cpu(*cnq->hw_cons_ptr); + sw_comp_cons = qed_chain_get_cons_idx(&cnq->pbl); + + /* Align protocol-index and chain reads */ + rmb(); + + while (sw_comp_cons != hw_comp_cons) { + sw_comp_cons = qed_chain_get_cons_idx(&cnq->pbl); + cnq->n_comp++; + } + + qed_ops->rdma_cnq_prod_update(cnq->dev->rdma_ctx, cnq->index, + sw_comp_cons); + + qed_sb_ack(cnq->sb, IGU_INT_ENABLE, 1); + + return IRQ_HANDLED; +} + +static void qedr_sync_free_irqs(struct qedr_dev *dev) +{ + u32 vector; + int i; + + for (i = 0; i < dev->int_info.used_cnt; i++) { + if (dev->int_info.msix_cnt) { + vector = dev->int_info.msix[i * dev->num_hwfns].vector; + synchronize_irq(vector); + free_irq(vector, &dev->cnq_array[i]); + } + } + + dev->int_info.used_cnt = 0; +} + +static int qedr_req_msix_irqs(struct qedr_dev *dev) +{ + int i, rc = 0; + + if (dev->num_cnq > dev->int_info.msix_cnt) { + DP_ERR(dev, + "Interrupt mismatch: %d CNQ queues > %d MSI-x vectors\n", + dev->num_cnq, dev->int_info.msix_cnt); + return -EINVAL; + } + + for (i = 0; i < dev->num_cnq; i++) { + rc = request_irq(dev->int_info.msix[i * dev->num_hwfns].vector, + qedr_irq_handler, 0, dev->cnq_array[i].name, + &dev->cnq_array[i]); + if (rc) { + DP_ERR(dev, "Request cnq %d irq failed\n", i); + qedr_sync_free_irqs(dev); + } else { + DP_DEBUG(dev, QEDR_MSG_INIT, + "Requested cnq irq for %s [entry %d]. Cookie is at %p\n", + dev->cnq_array[i].name, i, + &dev->cnq_array[i]); + dev->int_info.used_cnt++; + } + } + + return rc; +} + +static int qedr_setup_irqs(struct qedr_dev *dev) +{ + int rc; + + DP_DEBUG(dev, QEDR_MSG_INIT, "qedr_setup_irqs\n"); + + /* Learn Interrupt configuration */ + rc = dev->ops->rdma_set_rdma_int(dev->cdev, dev->num_cnq); + if (rc < 0) + return rc; + + rc = dev->ops->rdma_get_rdma_int(dev->cdev, &dev->int_info); + if (rc) { + DP_DEBUG(dev, QEDR_MSG_INIT, "get_rdma_int failed\n"); + return rc; + } + + if (dev->int_info.msix_cnt) { + DP_DEBUG(dev, QEDR_MSG_INIT, "rdma msix_cnt = %d\n", + dev->int_info.msix_cnt); + rc = qedr_req_msix_irqs(dev); + if (rc) + return rc; + } + + DP_DEBUG(dev, QEDR_MSG_INIT, "qedr_setup_irqs succeeded\n"); + + return 0; +} + +static int qedr_set_device_attr(struct qedr_dev *dev) +{ + struct qed_rdma_device *qed_attr; + struct qedr_device_attr *attr; + u32 page_size; + + /* Part 1 - query core capabilities */ + qed_attr = dev->ops->rdma_query_device(dev->rdma_ctx); + + /* Part 2 - check capabilities */ + page_size = ~dev->attr.page_size_caps + 1; + if (page_size > PAGE_SIZE) { + DP_ERR(dev, + "Kernel PAGE_SIZE is %ld which is smaller than minimum page size (%d) required by qedr\n", + PAGE_SIZE, page_size); + return -ENODEV; + } + + /* Part 3 - copy and update capabilities */ + attr = &dev->attr; + attr->vendor_id = qed_attr->vendor_id; + attr->vendor_part_id = qed_attr->vendor_part_id; + attr->hw_ver = qed_attr->hw_ver; + attr->fw_ver = qed_attr->fw_ver; + attr->node_guid = qed_attr->node_guid; + attr->sys_image_guid = qed_attr->sys_image_guid; + attr->max_cnq = qed_attr->max_cnq; + attr->max_sge = qed_attr->max_sge; + attr->max_inline = qed_attr->max_inline; + attr->max_sqe = min_t(u32, qed_attr->max_wqe, QEDR_MAX_SQE); + attr->max_rqe = min_t(u32, qed_attr->max_wqe, QEDR_MAX_RQE); + attr->max_qp_resp_rd_atomic_resc = qed_attr->max_qp_resp_rd_atomic_resc; + attr->max_qp_req_rd_atomic_resc = qed_attr->max_qp_req_rd_atomic_resc; + attr->max_dev_resp_rd_atomic_resc = + qed_attr->max_dev_resp_rd_atomic_resc; + attr->max_cq = qed_attr->max_cq; + attr->max_qp = qed_attr->max_qp; + attr->max_mr = qed_attr->max_mr; + attr->max_mr_size = qed_attr->max_mr_size; + attr->max_cqe = min_t(u64, qed_attr->max_cqe, QEDR_MAX_CQES); + attr->max_mw = qed_attr->max_mw; + attr->max_fmr = qed_attr->max_fmr; + attr->max_mr_mw_fmr_pbl = qed_attr->max_mr_mw_fmr_pbl; + attr->max_mr_mw_fmr_size = qed_attr->max_mr_mw_fmr_size; + attr->max_pd = qed_attr->max_pd; + attr->max_ah = qed_attr->max_ah; + attr->max_pkey = qed_attr->max_pkey; + attr->max_srq = qed_attr->max_srq; + attr->max_srq_wr = qed_attr->max_srq_wr; + attr->dev_caps = qed_attr->dev_caps; + attr->page_size_caps = qed_attr->page_size_caps; + attr->dev_ack_delay = qed_attr->dev_ack_delay; + attr->reserved_lkey = qed_attr->reserved_lkey; + attr->bad_pkey_counter = qed_attr->bad_pkey_counter; + attr->max_stats_queues = qed_attr->max_stats_queues; + + return 0; +} + +static int qedr_init_hw(struct qedr_dev *dev) +{ + struct qed_rdma_add_user_out_params out_params; + struct qed_rdma_start_in_params *in_params; + struct qed_rdma_cnq_params *cur_pbl; + struct qed_rdma_events events; + dma_addr_t p_phys_table; + u32 page_cnt; + int rc = 0; + int i; + + in_params = kzalloc(sizeof(*in_params), GFP_KERNEL); + if (!in_params) { + rc = -ENOMEM; + goto out; + } + + in_params->desired_cnq = dev->num_cnq; + for (i = 0; i < dev->num_cnq; i++) { + cur_pbl = &in_params->cnq_pbl_list[i]; + + page_cnt = qed_chain_get_page_cnt(&dev->cnq_array[i].pbl); + cur_pbl->num_pbl_pages = page_cnt; + + p_phys_table = qed_chain_get_pbl_phys(&dev->cnq_array[i].pbl); + cur_pbl->pbl_ptr = (u64)p_phys_table; + } + + events.context = dev; + + in_params->events = &events; + in_params->cq_mode = QED_RDMA_CQ_MODE_32_BITS; + in_params->max_mtu = dev->ndev->mtu; + ether_addr_copy(&in_params->mac_addr[0], dev->ndev->dev_addr); + + rc = dev->ops->rdma_init(dev->cdev, in_params); + if (rc) + goto out; + + rc = dev->ops->rdma_add_user(dev->rdma_ctx, &out_params); + if (rc) + goto out; + + dev->db_addr = (void *)(uintptr_t)out_params.dpi_addr; + dev->db_phys_addr = out_params.dpi_phys_addr; + dev->db_size = out_params.dpi_size; + dev->dpi = out_params.dpi; + + rc = qedr_set_device_attr(dev); +out: + kfree(in_params); + if (rc) + DP_ERR(dev, "Init HW Failed rc = %d\n", rc); + + return rc; +} + +void qedr_stop_hw(struct qedr_dev *dev) +{ + dev->ops->rdma_remove_user(dev->rdma_ctx, dev->dpi); + dev->ops->rdma_stop(dev->rdma_ctx); +} + static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, struct net_device *ndev) { + struct qed_dev_rdma_info dev_info; struct qedr_dev *dev; int rc = 0, i; @@ -164,21 +537,59 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, dev->ndev = ndev; dev->cdev = cdev; + qed_ops = qed_get_rdma_ops(); + if (!qed_ops) { + DP_ERR(dev, "Failed to get qed roce operations\n"); + goto init_err; + } + + dev->ops = qed_ops; + rc = qed_ops->fill_dev_info(cdev, &dev_info); + if (rc) + goto init_err; + + dev->num_hwfns = dev_info.common.num_hwfns; + dev->rdma_ctx = dev->ops->rdma_get_rdma_ctx(cdev); + + dev->num_cnq = dev->ops->rdma_get_min_cnq_msix(cdev); + if (!dev->num_cnq) { + DP_ERR(dev, "not enough CNQ resources.\n"); + goto init_err; + } + qedr_pci_set_atomic(dev, pdev); + rc = qedr_alloc_resources(dev); + if (rc) + goto init_err; + + rc = qedr_init_hw(dev); + if (rc) + goto alloc_err; + + rc = qedr_setup_irqs(dev); + if (rc) + goto irq_err; + rc = qedr_register_device(dev); if (rc) { DP_ERR(dev, "Unable to allocate register device\n"); - goto init_err; + goto reg_err; } for (i = 0; i < ARRAY_SIZE(qedr_attributes); i++) if (device_create_file(&dev->ibdev.dev, qedr_attributes[i])) - goto init_err; + goto reg_err; DP_DEBUG(dev, QEDR_MSG_INIT, "qedr driver loaded successfully\n"); return dev; +reg_err: + qedr_sync_free_irqs(dev); +irq_err: + qedr_stop_hw(dev); +alloc_err: + qedr_free_resources(dev); init_err: ib_dealloc_device(&dev->ibdev); DP_ERR(dev, "qedr driver load failed rc=%d\n", rc); @@ -193,6 +604,9 @@ static void qedr_remove(struct qedr_dev *dev) */ qedr_remove_sysfiles(dev); + qedr_stop_hw(dev); + qedr_sync_free_irqs(dev); + qedr_free_resources(dev); ib_dealloc_device(&dev->ibdev); } diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 801417080f114..1adbebb887eb3 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -35,7 +35,10 @@ #include #include #include +#include +#include #include +#include "qedr_hsi.h" #define QEDR_MODULE_VERSION "8.10.10.0" #define QEDR_NODE_DESC "QLogic 579xx RoCE HCA" @@ -47,6 +50,60 @@ #define QEDR_MSG_INIT "INIT" +struct qedr_dev; + +struct qedr_cnq { + struct qedr_dev *dev; + struct qed_chain pbl; + struct qed_sb_info *sb; + char name[32]; + u64 n_comp; + __le16 *hw_cons_ptr; + u8 index; +}; + +#define QEDR_MAX_SGID 128 + +struct qedr_device_attr { + u32 vendor_id; + u32 vendor_part_id; + u32 hw_ver; + u64 fw_ver; + u64 node_guid; + u64 sys_image_guid; + u8 max_cnq; + u8 max_sge; + u16 max_inline; + u32 max_sqe; + u32 max_rqe; + u8 max_qp_resp_rd_atomic_resc; + u8 max_qp_req_rd_atomic_resc; + u64 max_dev_resp_rd_atomic_resc; + u32 max_cq; + u32 max_qp; + u32 max_mr; + u64 max_mr_size; + u32 max_cqe; + u32 max_mw; + u32 max_fmr; + u32 max_mr_mw_fmr_pbl; + u64 max_mr_mw_fmr_size; + u32 max_pd; + u32 max_ah; + u8 max_pkey; + u32 max_srq; + u32 max_srq_wr; + u8 max_srq_sge; + u8 max_stats_queues; + u32 dev_caps; + + u64 page_size_caps; + u8 dev_ack_delay; + u32 reserved_lkey; + u32 bad_pkey_counter; + struct qed_rdma_events events; +}; + struct qedr_dev { struct ib_device ibdev; struct qed_dev *cdev; @@ -55,7 +112,73 @@ struct qedr_dev { enum ib_atomic_cap atomic_cap; + void *rdma_ctx; + struct qedr_device_attr attr; + + const struct qed_rdma_ops *ops; + struct qed_int_info int_info; + + struct qed_sb_info *sb_array; + struct qedr_cnq *cnq_array; + int num_cnq; + int sb_start; + + void __iomem *db_addr; + u64 db_phys_addr; + u32 db_size; + u16 dpi; + + union ib_gid *sgid_tbl; + + /* Lock for sgid table */ + spinlock_t sgid_lock; + + u64 guid; + u32 dp_module; u8 dp_level; + u8 num_hwfns; }; + +#define QEDR_MAX_SQ_PBL (0x8000) +#define QEDR_MAX_SQ_PBL_ENTRIES (0x10000 / sizeof(void *)) +#define QEDR_SQE_ELEMENT_SIZE (sizeof(struct rdma_sq_sge)) +#define QEDR_MAX_SQE_ELEMENTS_PER_SQE (ROCE_REQ_MAX_SINGLE_SQ_WQE_SIZE / \ + QEDR_SQE_ELEMENT_SIZE) +#define QEDR_MAX_SQE_ELEMENTS_PER_PAGE ((RDMA_RING_PAGE_SIZE) / \ + QEDR_SQE_ELEMENT_SIZE) +#define QEDR_MAX_SQE ((QEDR_MAX_SQ_PBL_ENTRIES) *\ + (RDMA_RING_PAGE_SIZE) / \ + (QEDR_SQE_ELEMENT_SIZE) /\ + (QEDR_MAX_SQE_ELEMENTS_PER_SQE)) +/* RQ */ +#define QEDR_MAX_RQ_PBL (0x2000) +#define QEDR_MAX_RQ_PBL_ENTRIES (0x10000 / sizeof(void *)) +#define QEDR_RQE_ELEMENT_SIZE (sizeof(struct rdma_rq_sge)) +#define QEDR_MAX_RQE_ELEMENTS_PER_RQE (RDMA_MAX_SGE_PER_RQ_WQE) +#define QEDR_MAX_RQE_ELEMENTS_PER_PAGE ((RDMA_RING_PAGE_SIZE) / \ + QEDR_RQE_ELEMENT_SIZE) +#define QEDR_MAX_RQE ((QEDR_MAX_RQ_PBL_ENTRIES) *\ + (RDMA_RING_PAGE_SIZE) / \ + (QEDR_RQE_ELEMENT_SIZE) /\ + (QEDR_MAX_RQE_ELEMENTS_PER_RQE)) + +#define QEDR_CQE_SIZE (sizeof(union rdma_cqe)) +#define QEDR_MAX_CQE_PBL_SIZE (512 * 1024) +#define QEDR_MAX_CQE_PBL_ENTRIES (((QEDR_MAX_CQE_PBL_SIZE) / \ + sizeof(u64)) - 1) +#define QEDR_MAX_CQES ((u32)((QEDR_MAX_CQE_PBL_ENTRIES) * \ + (QED_CHAIN_PAGE_SIZE) / QEDR_CQE_SIZE)) + +#define QEDR_ROCE_MAX_CNQ_SIZE (0x4000) + +#define QEDR_MAX_PORT (1) + +#define QEDR_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME) + +static inline struct qedr_dev *get_qedr_dev(struct ib_device *ibdev) +{ + return container_of(ibdev, struct qedr_dev, ibdev); +} + #endif diff --git a/drivers/infiniband/hw/qedr/qedr_hsi.h b/drivers/infiniband/hw/qedr/qedr_hsi.h new file mode 100644 index 0000000000000..66d27521373f2 --- /dev/null +++ b/drivers/infiniband/hw/qedr/qedr_hsi.h @@ -0,0 +1,56 @@ +/* QLogic qedr NIC Driver + * Copyright (c) 2015-2016 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __QED_HSI_ROCE__ +#define __QED_HSI_ROCE__ + +#include +#include +#include "qedr_hsi_rdma.h" + +/* Affiliated asynchronous events / errors enumeration */ +enum roce_async_events_type { + ROCE_ASYNC_EVENT_NONE = 0, + ROCE_ASYNC_EVENT_COMM_EST = 1, + ROCE_ASYNC_EVENT_SQ_DRAINED, + ROCE_ASYNC_EVENT_SRQ_LIMIT, + ROCE_ASYNC_EVENT_LAST_WQE_REACHED, + ROCE_ASYNC_EVENT_CQ_ERR, + ROCE_ASYNC_EVENT_LOCAL_INVALID_REQUEST_ERR, + ROCE_ASYNC_EVENT_LOCAL_CATASTROPHIC_ERR, + ROCE_ASYNC_EVENT_LOCAL_ACCESS_ERR, + ROCE_ASYNC_EVENT_QP_CATASTROPHIC_ERR, + ROCE_ASYNC_EVENT_CQ_OVERFLOW_ERR, + ROCE_ASYNC_EVENT_SRQ_EMPTY, + MAX_ROCE_ASYNC_EVENTS_TYPE +}; + +#endif /* __QED_HSI_ROCE__ */ diff --git a/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h b/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h new file mode 100644 index 0000000000000..3e508fbd5e78f --- /dev/null +++ b/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h @@ -0,0 +1,96 @@ +/* QLogic qedr NIC Driver + * Copyright (c) 2015-2016 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __QED_HSI_RDMA__ +#define __QED_HSI_RDMA__ + +#include + +/* rdma completion notification queue element */ +struct rdma_cnqe { + struct regpair cq_handle; +}; + +struct rdma_cqe_responder { + struct regpair srq_wr_id; + struct regpair qp_handle; + __le32 imm_data_or_inv_r_Key; + __le32 length; + __le32 imm_data_hi; + __le16 rq_cons; + u8 flags; +}; + +struct rdma_cqe_requester { + __le16 sq_cons; + __le16 reserved0; + __le32 reserved1; + struct regpair qp_handle; + struct regpair reserved2; + __le32 reserved3; + __le16 reserved4; + u8 flags; + u8 status; +}; + +struct rdma_cqe_common { + struct regpair reserved0; + struct regpair qp_handle; + __le16 reserved1[7]; + u8 flags; + u8 status; +}; + +/* rdma completion queue element */ +union rdma_cqe { + struct rdma_cqe_responder resp; + struct rdma_cqe_requester req; + struct rdma_cqe_common cmn; +}; + +struct rdma_sq_sge { + __le32 length; + struct regpair addr; + __le32 l_key; +}; + +struct rdma_rq_sge { + struct regpair addr; + __le32 length; + __le32 flags; +}; + +struct rdma_srq_sge { + struct regpair addr; + __le32 length; + __le32 l_key; +}; +#endif /* __QED_HSI_RDMA__ */ -- GitLab From ac1b36e55a5137e2f146e60be36d0cc81069feb6 Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 10 Oct 2016 13:15:32 +0300 Subject: [PATCH 0563/1167] qedr: Add support for user context verbs Add support for ucontext, query port, add and del gid verbs. Signed-off-by: Rajesh Borundia Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/Makefile | 2 +- drivers/infiniband/hw/qedr/main.c | 26 ++ drivers/infiniband/hw/qedr/qedr.h | 34 +++ drivers/infiniband/hw/qedr/verbs.c | 456 ++++++++++++++++++++++++++++ drivers/infiniband/hw/qedr/verbs.h | 52 ++++ include/uapi/rdma/qedr-abi.h | 53 ++++ 6 files changed, 622 insertions(+), 1 deletion(-) create mode 100644 drivers/infiniband/hw/qedr/verbs.c create mode 100644 drivers/infiniband/hw/qedr/verbs.h create mode 100644 include/uapi/rdma/qedr-abi.h diff --git a/drivers/infiniband/hw/qedr/Makefile b/drivers/infiniband/hw/qedr/Makefile index 3a5b7a2882814..b10f2b17ada5c 100644 --- a/drivers/infiniband/hw/qedr/Makefile +++ b/drivers/infiniband/hw/qedr/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_INFINIBAND_QEDR) := qedr.o -qedr-y := main.o +qedr-y := main.o verbs.o diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 67805941d138a..55c4f565c214b 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,8 @@ #include #include #include "qedr.h" +#include "verbs.h" +#include MODULE_DESCRIPTION("QLogic 40G/100G ROCE Driver"); MODULE_AUTHOR("QLogic Corporation"); @@ -80,6 +83,29 @@ static int qedr_register_device(struct qedr_dev *dev) memcpy(dev->ibdev.node_desc, QEDR_NODE_DESC, sizeof(QEDR_NODE_DESC)); dev->ibdev.owner = THIS_MODULE; + dev->ibdev.uverbs_abi_ver = QEDR_ABI_VERSION; + + dev->ibdev.uverbs_cmd_mask = QEDR_UVERBS(GET_CONTEXT) | + QEDR_UVERBS(QUERY_DEVICE) | + QEDR_UVERBS(QUERY_PORT); + + dev->ibdev.phys_port_cnt = 1; + dev->ibdev.num_comp_vectors = dev->num_cnq; + dev->ibdev.node_type = RDMA_NODE_IB_CA; + + dev->ibdev.query_device = qedr_query_device; + dev->ibdev.query_port = qedr_query_port; + dev->ibdev.modify_port = qedr_modify_port; + + dev->ibdev.query_gid = qedr_query_gid; + dev->ibdev.add_gid = qedr_add_gid; + dev->ibdev.del_gid = qedr_del_gid; + + dev->ibdev.alloc_ucontext = qedr_alloc_ucontext; + dev->ibdev.dealloc_ucontext = qedr_dealloc_ucontext; + dev->ibdev.mmap = qedr_mmap; + + dev->ibdev.dma_device = &dev->pdev->dev; dev->ibdev.get_link_layer = qedr_link_layer; dev->ibdev.get_dev_fw_str = qedr_get_dev_fw_str; diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 1adbebb887eb3..2091c0d6e67d4 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -49,6 +49,7 @@ DP_NAME(dev) ? DP_NAME(dev) : "", ## __VA_ARGS__) #define QEDR_MSG_INIT "INIT" +#define QEDR_MSG_MISC "MISC" struct qedr_dev; @@ -176,6 +177,39 @@ struct qedr_dev { #define QEDR_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME) +#define QEDR_ROCE_PKEY_MAX 1 +#define QEDR_ROCE_PKEY_TABLE_LEN 1 +#define QEDR_ROCE_PKEY_DEFAULT 0xffff + +struct qedr_ucontext { + struct ib_ucontext ibucontext; + struct qedr_dev *dev; + struct qedr_pd *pd; + u64 dpi_addr; + u64 dpi_phys_addr; + u32 dpi_size; + u16 dpi; + + struct list_head mm_head; + + /* Lock to protect mm list */ + struct mutex mm_list_lock; +}; + +struct qedr_mm { + struct { + u64 phy_addr; + unsigned long len; + } key; + struct list_head entry; +}; + +static inline +struct qedr_ucontext *get_qedr_ucontext(struct ib_ucontext *ibucontext) +{ + return container_of(ibucontext, struct qedr_ucontext, ibucontext); +} + static inline struct qedr_dev *get_qedr_dev(struct ib_device *ibdev) { return container_of(ibdev, struct qedr_dev, ibdev); diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c new file mode 100644 index 0000000000000..b9dcade1cb9f7 --- /dev/null +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -0,0 +1,456 @@ +/* QLogic qedr NIC Driver + * Copyright (c) 2015-2016 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "qedr_hsi.h" +#include +#include "qedr.h" +#include "verbs.h" +#include + +int qedr_query_gid(struct ib_device *ibdev, u8 port, int index, + union ib_gid *sgid) +{ + struct qedr_dev *dev = get_qedr_dev(ibdev); + int rc = 0; + + if (!rdma_cap_roce_gid_table(ibdev, port)) + return -ENODEV; + + rc = ib_get_cached_gid(ibdev, port, index, sgid, NULL); + if (rc == -EAGAIN) { + memcpy(sgid, &zgid, sizeof(*sgid)); + return 0; + } + + DP_DEBUG(dev, QEDR_MSG_INIT, "query gid: index=%d %llx:%llx\n", index, + sgid->global.interface_id, sgid->global.subnet_prefix); + + return rc; +} + +int qedr_add_gid(struct ib_device *device, u8 port_num, + unsigned int index, const union ib_gid *gid, + const struct ib_gid_attr *attr, void **context) +{ + if (!rdma_cap_roce_gid_table(device, port_num)) + return -EINVAL; + + if (port_num > QEDR_MAX_PORT) + return -EINVAL; + + if (!context) + return -EINVAL; + + return 0; +} + +int qedr_del_gid(struct ib_device *device, u8 port_num, + unsigned int index, void **context) +{ + if (!rdma_cap_roce_gid_table(device, port_num)) + return -EINVAL; + + if (port_num > QEDR_MAX_PORT) + return -EINVAL; + + if (!context) + return -EINVAL; + + return 0; +} + +int qedr_query_device(struct ib_device *ibdev, + struct ib_device_attr *attr, struct ib_udata *udata) +{ + struct qedr_dev *dev = get_qedr_dev(ibdev); + struct qedr_device_attr *qattr = &dev->attr; + + if (!dev->rdma_ctx) { + DP_ERR(dev, + "qedr_query_device called with invalid params rdma_ctx=%p\n", + dev->rdma_ctx); + return -EINVAL; + } + + memset(attr, 0, sizeof(*attr)); + + attr->fw_ver = qattr->fw_ver; + attr->sys_image_guid = qattr->sys_image_guid; + attr->max_mr_size = qattr->max_mr_size; + attr->page_size_cap = qattr->page_size_caps; + attr->vendor_id = qattr->vendor_id; + attr->vendor_part_id = qattr->vendor_part_id; + attr->hw_ver = qattr->hw_ver; + attr->max_qp = qattr->max_qp; + attr->max_qp_wr = max_t(u32, qattr->max_sqe, qattr->max_rqe); + attr->device_cap_flags = IB_DEVICE_CURR_QP_STATE_MOD | + IB_DEVICE_RC_RNR_NAK_GEN | + IB_DEVICE_LOCAL_DMA_LKEY | IB_DEVICE_MEM_MGT_EXTENSIONS; + + attr->max_sge = qattr->max_sge; + attr->max_sge_rd = qattr->max_sge; + attr->max_cq = qattr->max_cq; + attr->max_cqe = qattr->max_cqe; + attr->max_mr = qattr->max_mr; + attr->max_mw = qattr->max_mw; + attr->max_pd = qattr->max_pd; + attr->atomic_cap = dev->atomic_cap; + attr->max_fmr = qattr->max_fmr; + attr->max_map_per_fmr = 16; + attr->max_qp_init_rd_atom = + 1 << (fls(qattr->max_qp_req_rd_atomic_resc) - 1); + attr->max_qp_rd_atom = + min(1 << (fls(qattr->max_qp_resp_rd_atomic_resc) - 1), + attr->max_qp_init_rd_atom); + + attr->max_srq = qattr->max_srq; + attr->max_srq_sge = qattr->max_srq_sge; + attr->max_srq_wr = qattr->max_srq_wr; + + attr->local_ca_ack_delay = qattr->dev_ack_delay; + attr->max_fast_reg_page_list_len = qattr->max_mr / 8; + attr->max_pkeys = QEDR_ROCE_PKEY_MAX; + attr->max_ah = qattr->max_ah; + + return 0; +} + +#define QEDR_SPEED_SDR (1) +#define QEDR_SPEED_DDR (2) +#define QEDR_SPEED_QDR (4) +#define QEDR_SPEED_FDR10 (8) +#define QEDR_SPEED_FDR (16) +#define QEDR_SPEED_EDR (32) + +static inline void get_link_speed_and_width(int speed, u8 *ib_speed, + u8 *ib_width) +{ + switch (speed) { + case 1000: + *ib_speed = QEDR_SPEED_SDR; + *ib_width = IB_WIDTH_1X; + break; + case 10000: + *ib_speed = QEDR_SPEED_QDR; + *ib_width = IB_WIDTH_1X; + break; + + case 20000: + *ib_speed = QEDR_SPEED_DDR; + *ib_width = IB_WIDTH_4X; + break; + + case 25000: + *ib_speed = QEDR_SPEED_EDR; + *ib_width = IB_WIDTH_1X; + break; + + case 40000: + *ib_speed = QEDR_SPEED_QDR; + *ib_width = IB_WIDTH_4X; + break; + + case 50000: + *ib_speed = QEDR_SPEED_QDR; + *ib_width = IB_WIDTH_4X; + break; + + case 100000: + *ib_speed = QEDR_SPEED_EDR; + *ib_width = IB_WIDTH_4X; + break; + + default: + /* Unsupported */ + *ib_speed = QEDR_SPEED_SDR; + *ib_width = IB_WIDTH_1X; + } +} + +int qedr_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *attr) +{ + struct qedr_dev *dev; + struct qed_rdma_port *rdma_port; + + dev = get_qedr_dev(ibdev); + if (port > 1) { + DP_ERR(dev, "invalid_port=0x%x\n", port); + return -EINVAL; + } + + if (!dev->rdma_ctx) { + DP_ERR(dev, "rdma_ctx is NULL\n"); + return -EINVAL; + } + + rdma_port = dev->ops->rdma_query_port(dev->rdma_ctx); + memset(attr, 0, sizeof(*attr)); + + if (rdma_port->port_state == QED_RDMA_PORT_UP) { + attr->state = IB_PORT_ACTIVE; + attr->phys_state = 5; + } else { + attr->state = IB_PORT_DOWN; + attr->phys_state = 3; + } + attr->max_mtu = IB_MTU_4096; + attr->active_mtu = iboe_get_mtu(dev->ndev->mtu); + attr->lid = 0; + attr->lmc = 0; + attr->sm_lid = 0; + attr->sm_sl = 0; + attr->port_cap_flags = IB_PORT_IP_BASED_GIDS; + attr->gid_tbl_len = QEDR_MAX_SGID; + attr->pkey_tbl_len = QEDR_ROCE_PKEY_TABLE_LEN; + attr->bad_pkey_cntr = rdma_port->pkey_bad_counter; + attr->qkey_viol_cntr = 0; + get_link_speed_and_width(rdma_port->link_speed, + &attr->active_speed, &attr->active_width); + attr->max_msg_sz = rdma_port->max_msg_size; + attr->max_vl_num = 4; + + return 0; +} + +int qedr_modify_port(struct ib_device *ibdev, u8 port, int mask, + struct ib_port_modify *props) +{ + struct qedr_dev *dev; + + dev = get_qedr_dev(ibdev); + if (port > 1) { + DP_ERR(dev, "invalid_port=0x%x\n", port); + return -EINVAL; + } + + return 0; +} + +static int qedr_add_mmap(struct qedr_ucontext *uctx, u64 phy_addr, + unsigned long len) +{ + struct qedr_mm *mm; + + mm = kzalloc(sizeof(*mm), GFP_KERNEL); + if (!mm) + return -ENOMEM; + + mm->key.phy_addr = phy_addr; + /* This function might be called with a length which is not a multiple + * of PAGE_SIZE, while the mapping is PAGE_SIZE grained and the kernel + * forces this granularity by increasing the requested size if needed. + * When qedr_mmap is called, it will search the list with the updated + * length as a key. To prevent search failures, the length is rounded up + * in advance to PAGE_SIZE. + */ + mm->key.len = roundup(len, PAGE_SIZE); + INIT_LIST_HEAD(&mm->entry); + + mutex_lock(&uctx->mm_list_lock); + list_add(&mm->entry, &uctx->mm_head); + mutex_unlock(&uctx->mm_list_lock); + + DP_DEBUG(uctx->dev, QEDR_MSG_MISC, + "added (addr=0x%llx,len=0x%lx) for ctx=%p\n", + (unsigned long long)mm->key.phy_addr, + (unsigned long)mm->key.len, uctx); + + return 0; +} + +static bool qedr_search_mmap(struct qedr_ucontext *uctx, u64 phy_addr, + unsigned long len) +{ + bool found = false; + struct qedr_mm *mm; + + mutex_lock(&uctx->mm_list_lock); + list_for_each_entry(mm, &uctx->mm_head, entry) { + if (len != mm->key.len || phy_addr != mm->key.phy_addr) + continue; + + found = true; + break; + } + mutex_unlock(&uctx->mm_list_lock); + DP_DEBUG(uctx->dev, QEDR_MSG_MISC, + "searched for (addr=0x%llx,len=0x%lx) for ctx=%p, result=%d\n", + mm->key.phy_addr, mm->key.len, uctx, found); + + return found; +} + +struct ib_ucontext *qedr_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata) +{ + int rc; + struct qedr_ucontext *ctx; + struct qedr_alloc_ucontext_resp uresp; + struct qedr_dev *dev = get_qedr_dev(ibdev); + struct qed_rdma_add_user_out_params oparams; + + if (!udata) + return ERR_PTR(-EFAULT); + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + rc = dev->ops->rdma_add_user(dev->rdma_ctx, &oparams); + if (rc) { + DP_ERR(dev, + "failed to allocate a DPI for a new RoCE application, rc=%d. To overcome this consider to increase the number of DPIs, increase the doorbell BAR size or just close unnecessary RoCE applications. In order to increase the number of DPIs consult the qedr readme\n", + rc); + goto err; + } + + ctx->dpi = oparams.dpi; + ctx->dpi_addr = oparams.dpi_addr; + ctx->dpi_phys_addr = oparams.dpi_phys_addr; + ctx->dpi_size = oparams.dpi_size; + INIT_LIST_HEAD(&ctx->mm_head); + mutex_init(&ctx->mm_list_lock); + + memset(&uresp, 0, sizeof(uresp)); + + uresp.db_pa = ctx->dpi_phys_addr; + uresp.db_size = ctx->dpi_size; + uresp.max_send_wr = dev->attr.max_sqe; + uresp.max_recv_wr = dev->attr.max_rqe; + uresp.max_srq_wr = dev->attr.max_srq_wr; + uresp.sges_per_send_wr = QEDR_MAX_SQE_ELEMENTS_PER_SQE; + uresp.sges_per_recv_wr = QEDR_MAX_RQE_ELEMENTS_PER_RQE; + uresp.sges_per_srq_wr = dev->attr.max_srq_sge; + uresp.max_cqes = QEDR_MAX_CQES; + + rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); + if (rc) + goto err; + + ctx->dev = dev; + + rc = qedr_add_mmap(ctx, ctx->dpi_phys_addr, ctx->dpi_size); + if (rc) + goto err; + + DP_DEBUG(dev, QEDR_MSG_INIT, "Allocating user context %p\n", + &ctx->ibucontext); + return &ctx->ibucontext; + +err: + kfree(ctx); + return ERR_PTR(rc); +} + +int qedr_dealloc_ucontext(struct ib_ucontext *ibctx) +{ + struct qedr_ucontext *uctx = get_qedr_ucontext(ibctx); + struct qedr_mm *mm, *tmp; + int status = 0; + + DP_DEBUG(uctx->dev, QEDR_MSG_INIT, "Deallocating user context %p\n", + uctx); + uctx->dev->ops->rdma_remove_user(uctx->dev->rdma_ctx, uctx->dpi); + + list_for_each_entry_safe(mm, tmp, &uctx->mm_head, entry) { + DP_DEBUG(uctx->dev, QEDR_MSG_MISC, + "deleted (addr=0x%llx,len=0x%lx) for ctx=%p\n", + mm->key.phy_addr, mm->key.len, uctx); + list_del(&mm->entry); + kfree(mm); + } + + kfree(uctx); + return status; +} + +int qedr_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) +{ + struct qedr_ucontext *ucontext = get_qedr_ucontext(context); + struct qedr_dev *dev = get_qedr_dev(context->device); + unsigned long vm_page = vma->vm_pgoff << PAGE_SHIFT; + u64 unmapped_db = dev->db_phys_addr; + unsigned long len = (vma->vm_end - vma->vm_start); + int rc = 0; + bool found; + + DP_DEBUG(dev, QEDR_MSG_INIT, + "qedr_mmap called vm_page=0x%lx vm_pgoff=0x%lx unmapped_db=0x%llx db_size=%x, len=%lx\n", + vm_page, vma->vm_pgoff, unmapped_db, dev->db_size, len); + if (vma->vm_start & (PAGE_SIZE - 1)) { + DP_ERR(dev, "Vma_start not page aligned = %ld\n", + vma->vm_start); + return -EINVAL; + } + + found = qedr_search_mmap(ucontext, vm_page, len); + if (!found) { + DP_ERR(dev, "Vma_pgoff not found in mapped array = %ld\n", + vma->vm_pgoff); + return -EINVAL; + } + + DP_DEBUG(dev, QEDR_MSG_INIT, "Mapping doorbell bar\n"); + + if ((vm_page >= unmapped_db) && (vm_page <= (unmapped_db + + dev->db_size))) { + DP_DEBUG(dev, QEDR_MSG_INIT, "Mapping doorbell bar\n"); + if (vma->vm_flags & VM_READ) { + DP_ERR(dev, "Trying to map doorbell bar for read\n"); + return -EPERM; + } + + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + rc = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + PAGE_SIZE, vma->vm_page_prot); + } else { + DP_DEBUG(dev, QEDR_MSG_INIT, "Mapping chains\n"); + rc = remap_pfn_range(vma, vma->vm_start, + vma->vm_pgoff, len, vma->vm_page_prot); + } + DP_DEBUG(dev, QEDR_MSG_INIT, "qedr_mmap return code: %d\n", rc); + return rc; +} diff --git a/drivers/infiniband/hw/qedr/verbs.h b/drivers/infiniband/hw/qedr/verbs.h new file mode 100644 index 0000000000000..9472044dd5873 --- /dev/null +++ b/drivers/infiniband/hw/qedr/verbs.h @@ -0,0 +1,52 @@ +/* QLogic qedr NIC Driver + * Copyright (c) 2015-2016 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __QEDR_VERBS_H__ +#define __QEDR_VERBS_H__ + +int qedr_query_device(struct ib_device *ibdev, + struct ib_device_attr *attr, struct ib_udata *udata); +int qedr_query_port(struct ib_device *, u8 port, struct ib_port_attr *props); +int qedr_modify_port(struct ib_device *, u8 port, int mask, + struct ib_port_modify *props); + +int qedr_query_gid(struct ib_device *, u8 port, int index, union ib_gid *gid); + +struct ib_ucontext *qedr_alloc_ucontext(struct ib_device *, struct ib_udata *); +int qedr_dealloc_ucontext(struct ib_ucontext *); + +int qedr_mmap(struct ib_ucontext *, struct vm_area_struct *vma); +int qedr_del_gid(struct ib_device *device, u8 port_num, + unsigned int index, void **context); +int qedr_add_gid(struct ib_device *device, u8 port_num, + unsigned int index, const union ib_gid *gid, + const struct ib_gid_attr *attr, void **context); +#endif diff --git a/include/uapi/rdma/qedr-abi.h b/include/uapi/rdma/qedr-abi.h new file mode 100644 index 0000000000000..f7c7fff7a8777 --- /dev/null +++ b/include/uapi/rdma/qedr-abi.h @@ -0,0 +1,53 @@ +/* QLogic qedr NIC Driver + * Copyright (c) 2015-2016 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __QEDR_USER_H__ +#define __QEDR_USER_H__ + +#include + +#define QEDR_ABI_VERSION (8) + +/* user kernel communication data structures. */ + +struct qedr_alloc_ucontext_resp { + __u64 db_pa; + __u32 db_size; + + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_srq_wr; + __u32 sges_per_send_wr; + __u32 sges_per_recv_wr; + __u32 sges_per_srq_wr; + __u32 max_cqes; +}; +#endif /* __QEDR_USER_H__ */ -- GitLab From a7efd7773e31b60f695816c27393fc717a9df127 Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 10 Oct 2016 13:15:33 +0300 Subject: [PATCH 0564/1167] qedr: Add support for PD,PKEY and CQ verbs Add support for protection domain and completion queue verbs. Signed-off-by: Rajesh Borundia Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/main.c | 49 +- drivers/infiniband/hw/qedr/qedr.h | 78 +++ drivers/infiniband/hw/qedr/qedr_hsi_rdma.h | 79 +++ drivers/infiniband/hw/qedr/verbs.c | 539 +++++++++++++++++++++ drivers/infiniband/hw/qedr/verbs.h | 14 + include/uapi/rdma/qedr-abi.h | 19 + 6 files changed, 777 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 55c4f565c214b..35928abb6b639 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -87,7 +87,14 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.uverbs_cmd_mask = QEDR_UVERBS(GET_CONTEXT) | QEDR_UVERBS(QUERY_DEVICE) | - QEDR_UVERBS(QUERY_PORT); + QEDR_UVERBS(QUERY_PORT) | + QEDR_UVERBS(ALLOC_PD) | + QEDR_UVERBS(DEALLOC_PD) | + QEDR_UVERBS(CREATE_COMP_CHANNEL) | + QEDR_UVERBS(CREATE_CQ) | + QEDR_UVERBS(RESIZE_CQ) | + QEDR_UVERBS(DESTROY_CQ) | + QEDR_UVERBS(REQ_NOTIFY_CQ); dev->ibdev.phys_port_cnt = 1; dev->ibdev.num_comp_vectors = dev->num_cnq; @@ -105,6 +112,16 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.dealloc_ucontext = qedr_dealloc_ucontext; dev->ibdev.mmap = qedr_mmap; + dev->ibdev.alloc_pd = qedr_alloc_pd; + dev->ibdev.dealloc_pd = qedr_dealloc_pd; + + dev->ibdev.create_cq = qedr_create_cq; + dev->ibdev.destroy_cq = qedr_destroy_cq; + dev->ibdev.resize_cq = qedr_resize_cq; + dev->ibdev.req_notify_cq = qedr_arm_cq; + + dev->ibdev.query_pkey = qedr_query_pkey; + dev->ibdev.dma_device = &dev->pdev->dev; dev->ibdev.get_link_layer = qedr_link_layer; @@ -322,6 +339,8 @@ static irqreturn_t qedr_irq_handler(int irq, void *handle) { u16 hw_comp_cons, sw_comp_cons; struct qedr_cnq *cnq = handle; + struct regpair *cq_handle; + struct qedr_cq *cq; qed_sb_ack(cnq->sb, IGU_INT_DISABLE, 0); @@ -334,8 +353,36 @@ static irqreturn_t qedr_irq_handler(int irq, void *handle) rmb(); while (sw_comp_cons != hw_comp_cons) { + cq_handle = (struct regpair *)qed_chain_consume(&cnq->pbl); + cq = (struct qedr_cq *)(uintptr_t)HILO_U64(cq_handle->hi, + cq_handle->lo); + + if (cq == NULL) { + DP_ERR(cnq->dev, + "Received NULL CQ cq_handle->hi=%d cq_handle->lo=%d sw_comp_cons=%d hw_comp_cons=%d\n", + cq_handle->hi, cq_handle->lo, sw_comp_cons, + hw_comp_cons); + + break; + } + + if (cq->sig != QEDR_CQ_MAGIC_NUMBER) { + DP_ERR(cnq->dev, + "Problem with cq signature, cq_handle->hi=%d ch_handle->lo=%d cq=%p\n", + cq_handle->hi, cq_handle->lo, cq); + break; + } + + cq->arm_flags = 0; + + if (cq->ibcq.comp_handler) + (*cq->ibcq.comp_handler) + (&cq->ibcq, cq->ibcq.cq_context); + sw_comp_cons = qed_chain_get_cons_idx(&cnq->pbl); + cnq->n_comp++; + } qed_ops->rdma_cnq_prod_update(cnq->dev->rdma_ctx, cnq->index, diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 2091c0d6e67d4..9e2846a599cea 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -50,6 +50,10 @@ #define QEDR_MSG_INIT "INIT" #define QEDR_MSG_MISC "MISC" +#define QEDR_MSG_CQ " CQ" +#define QEDR_MSG_MR " MR" + +#define QEDR_CQ_MAGIC_NUMBER (0x11223344) struct qedr_dev; @@ -181,6 +185,12 @@ struct qedr_dev { #define QEDR_ROCE_PKEY_TABLE_LEN 1 #define QEDR_ROCE_PKEY_DEFAULT 0xffff +struct qedr_pbl { + struct list_head list_entry; + void *va; + dma_addr_t pa; +}; + struct qedr_ucontext { struct ib_ucontext ibucontext; struct qedr_dev *dev; @@ -196,6 +206,64 @@ struct qedr_ucontext { struct mutex mm_list_lock; }; +union db_prod64 { + struct rdma_pwm_val32_data data; + u64 raw; +}; + +enum qedr_cq_type { + QEDR_CQ_TYPE_GSI, + QEDR_CQ_TYPE_KERNEL, + QEDR_CQ_TYPE_USER, +}; + +struct qedr_pbl_info { + u32 num_pbls; + u32 num_pbes; + u32 pbl_size; + u32 pbe_size; + bool two_layered; +}; + +struct qedr_userq { + struct ib_umem *umem; + struct qedr_pbl_info pbl_info; + struct qedr_pbl *pbl_tbl; + u64 buf_addr; + size_t buf_len; +}; + +struct qedr_cq { + struct ib_cq ibcq; + + enum qedr_cq_type cq_type; + u32 sig; + + u16 icid; + + /* Lock to protect multiplem CQ's */ + spinlock_t cq_lock; + u8 arm_flags; + struct qed_chain pbl; + + void __iomem *db_addr; + union db_prod64 db; + + u8 pbl_toggle; + union rdma_cqe *latest_cqe; + union rdma_cqe *toggle_cqe; + + u32 cq_cons; + + struct qedr_userq q; +}; + +struct qedr_pd { + struct ib_pd ibpd; + u32 pd_id; + struct qedr_ucontext *uctx; +}; + struct qedr_mm { struct { u64 phy_addr; @@ -215,4 +283,14 @@ static inline struct qedr_dev *get_qedr_dev(struct ib_device *ibdev) return container_of(ibdev, struct qedr_dev, ibdev); } +static inline struct qedr_pd *get_qedr_pd(struct ib_pd *ibpd) +{ + return container_of(ibpd, struct qedr_pd, ibpd); +} + +static inline struct qedr_cq *get_qedr_cq(struct ib_cq *ibcq) +{ + return container_of(ibcq, struct qedr_cq, ibcq); +} + #endif diff --git a/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h b/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h index 3e508fbd5e78f..84f6520107cc7 100644 --- a/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h +++ b/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h @@ -47,6 +47,19 @@ struct rdma_cqe_responder { __le32 imm_data_hi; __le16 rq_cons; u8 flags; +#define RDMA_CQE_RESPONDER_TOGGLE_BIT_MASK 0x1 +#define RDMA_CQE_RESPONDER_TOGGLE_BIT_SHIFT 0 +#define RDMA_CQE_RESPONDER_TYPE_MASK 0x3 +#define RDMA_CQE_RESPONDER_TYPE_SHIFT 1 +#define RDMA_CQE_RESPONDER_INV_FLG_MASK 0x1 +#define RDMA_CQE_RESPONDER_INV_FLG_SHIFT 3 +#define RDMA_CQE_RESPONDER_IMM_FLG_MASK 0x1 +#define RDMA_CQE_RESPONDER_IMM_FLG_SHIFT 4 +#define RDMA_CQE_RESPONDER_RDMA_FLG_MASK 0x1 +#define RDMA_CQE_RESPONDER_RDMA_FLG_SHIFT 5 +#define RDMA_CQE_RESPONDER_RESERVED2_MASK 0x3 +#define RDMA_CQE_RESPONDER_RESERVED2_SHIFT 6 + u8 status; }; struct rdma_cqe_requester { @@ -58,6 +71,12 @@ struct rdma_cqe_requester { __le32 reserved3; __le16 reserved4; u8 flags; +#define RDMA_CQE_REQUESTER_TOGGLE_BIT_MASK 0x1 +#define RDMA_CQE_REQUESTER_TOGGLE_BIT_SHIFT 0 +#define RDMA_CQE_REQUESTER_TYPE_MASK 0x3 +#define RDMA_CQE_REQUESTER_TYPE_SHIFT 1 +#define RDMA_CQE_REQUESTER_RESERVED5_MASK 0x1F +#define RDMA_CQE_REQUESTER_RESERVED5_SHIFT 3 u8 status; }; @@ -66,6 +85,12 @@ struct rdma_cqe_common { struct regpair qp_handle; __le16 reserved1[7]; u8 flags; +#define RDMA_CQE_COMMON_TOGGLE_BIT_MASK 0x1 +#define RDMA_CQE_COMMON_TOGGLE_BIT_SHIFT 0 +#define RDMA_CQE_COMMON_TYPE_MASK 0x3 +#define RDMA_CQE_COMMON_TYPE_SHIFT 1 +#define RDMA_CQE_COMMON_RESERVED2_MASK 0x1F +#define RDMA_CQE_COMMON_RESERVED2_SHIFT 3 u8 status; }; @@ -76,6 +101,45 @@ union rdma_cqe { struct rdma_cqe_common cmn; }; +/* * CQE requester status enumeration */ +enum rdma_cqe_requester_status_enum { + RDMA_CQE_REQ_STS_OK, + RDMA_CQE_REQ_STS_BAD_RESPONSE_ERR, + RDMA_CQE_REQ_STS_LOCAL_LENGTH_ERR, + RDMA_CQE_REQ_STS_LOCAL_QP_OPERATION_ERR, + RDMA_CQE_REQ_STS_LOCAL_PROTECTION_ERR, + RDMA_CQE_REQ_STS_MEMORY_MGT_OPERATION_ERR, + RDMA_CQE_REQ_STS_REMOTE_INVALID_REQUEST_ERR, + RDMA_CQE_REQ_STS_REMOTE_ACCESS_ERR, + RDMA_CQE_REQ_STS_REMOTE_OPERATION_ERR, + RDMA_CQE_REQ_STS_RNR_NAK_RETRY_CNT_ERR, + RDMA_CQE_REQ_STS_TRANSPORT_RETRY_CNT_ERR, + RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR, + MAX_RDMA_CQE_REQUESTER_STATUS_ENUM +}; + +/* CQE responder status enumeration */ +enum rdma_cqe_responder_status_enum { + RDMA_CQE_RESP_STS_OK, + RDMA_CQE_RESP_STS_LOCAL_ACCESS_ERR, + RDMA_CQE_RESP_STS_LOCAL_LENGTH_ERR, + RDMA_CQE_RESP_STS_LOCAL_QP_OPERATION_ERR, + RDMA_CQE_RESP_STS_LOCAL_PROTECTION_ERR, + RDMA_CQE_RESP_STS_MEMORY_MGT_OPERATION_ERR, + RDMA_CQE_RESP_STS_REMOTE_INVALID_REQUEST_ERR, + RDMA_CQE_RESP_STS_WORK_REQUEST_FLUSHED_ERR, + MAX_RDMA_CQE_RESPONDER_STATUS_ENUM +}; + +/* CQE type enumeration */ +enum rdma_cqe_type { + RDMA_CQE_TYPE_REQUESTER, + RDMA_CQE_TYPE_RESPONDER_RQ, + RDMA_CQE_TYPE_RESPONDER_SRQ, + RDMA_CQE_TYPE_INVALID, + MAX_RDMA_CQE_TYPE +}; + struct rdma_sq_sge { __le32 length; struct regpair addr; @@ -93,4 +157,19 @@ struct rdma_srq_sge { __le32 length; __le32 l_key; }; + +/* Rdma doorbell data for CQ */ +struct rdma_pwm_val32_data { + __le16 icid; + u8 agg_flags; + u8 params; +#define RDMA_PWM_VAL32_DATA_AGG_CMD_MASK 0x3 +#define RDMA_PWM_VAL32_DATA_AGG_CMD_SHIFT 0 +#define RDMA_PWM_VAL32_DATA_BYPASS_EN_MASK 0x1 +#define RDMA_PWM_VAL32_DATA_BYPASS_EN_SHIFT 2 +#define RDMA_PWM_VAL32_DATA_RESERVED_MASK 0x1F +#define RDMA_PWM_VAL32_DATA_RESERVED_SHIFT 3 + __le32 value; +}; + #endif /* __QED_HSI_RDMA__ */ diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index b9dcade1cb9f7..b525c6cf1df05 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -49,6 +49,17 @@ #include "verbs.h" #include +#define DB_ADDR_SHIFT(addr) ((addr) << DB_PWM_ADDR_OFFSET_SHIFT) + +int qedr_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) +{ + if (index > QEDR_ROCE_PKEY_TABLE_LEN) + return -EINVAL; + + *pkey = QEDR_ROCE_PKEY_DEFAULT; + return 0; +} + int qedr_query_gid(struct ib_device *ibdev, u8 port, int index, union ib_gid *sgid) { @@ -454,3 +465,531 @@ int qedr_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) DP_DEBUG(dev, QEDR_MSG_INIT, "qedr_mmap return code: %d\n", rc); return rc; } + +struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, struct ib_udata *udata) +{ + struct qedr_dev *dev = get_qedr_dev(ibdev); + struct qedr_ucontext *uctx = NULL; + struct qedr_alloc_pd_uresp uresp; + struct qedr_pd *pd; + u16 pd_id; + int rc; + + DP_DEBUG(dev, QEDR_MSG_INIT, "Function called from: %s\n", + (udata && context) ? "User Lib" : "Kernel"); + + if (!dev->rdma_ctx) { + DP_ERR(dev, "invlaid RDMA context\n"); + return ERR_PTR(-EINVAL); + } + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) + return ERR_PTR(-ENOMEM); + + dev->ops->rdma_alloc_pd(dev->rdma_ctx, &pd_id); + + uresp.pd_id = pd_id; + pd->pd_id = pd_id; + + if (udata && context) { + rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); + if (rc) + DP_ERR(dev, "copy error pd_id=0x%x.\n", pd_id); + uctx = get_qedr_ucontext(context); + uctx->pd = pd; + pd->uctx = uctx; + } + + return &pd->ibpd; +} + +int qedr_dealloc_pd(struct ib_pd *ibpd) +{ + struct qedr_dev *dev = get_qedr_dev(ibpd->device); + struct qedr_pd *pd = get_qedr_pd(ibpd); + + if (!pd) + pr_err("Invalid PD received in dealloc_pd\n"); + + DP_DEBUG(dev, QEDR_MSG_INIT, "Deallocating PD %d\n", pd->pd_id); + dev->ops->rdma_dealloc_pd(dev->rdma_ctx, pd->pd_id); + + kfree(pd); + + return 0; +} + +static void qedr_free_pbl(struct qedr_dev *dev, + struct qedr_pbl_info *pbl_info, struct qedr_pbl *pbl) +{ + struct pci_dev *pdev = dev->pdev; + int i; + + for (i = 0; i < pbl_info->num_pbls; i++) { + if (!pbl[i].va) + continue; + dma_free_coherent(&pdev->dev, pbl_info->pbl_size, + pbl[i].va, pbl[i].pa); + } + + kfree(pbl); +} + +#define MIN_FW_PBL_PAGE_SIZE (4 * 1024) +#define MAX_FW_PBL_PAGE_SIZE (64 * 1024) + +#define NUM_PBES_ON_PAGE(_page_size) (_page_size / sizeof(u64)) +#define MAX_PBES_ON_PAGE NUM_PBES_ON_PAGE(MAX_FW_PBL_PAGE_SIZE) +#define MAX_PBES_TWO_LAYER (MAX_PBES_ON_PAGE * MAX_PBES_ON_PAGE) + +static struct qedr_pbl *qedr_alloc_pbl_tbl(struct qedr_dev *dev, + struct qedr_pbl_info *pbl_info, + gfp_t flags) +{ + struct pci_dev *pdev = dev->pdev; + struct qedr_pbl *pbl_table; + dma_addr_t *pbl_main_tbl; + dma_addr_t pa; + void *va; + int i; + + pbl_table = kcalloc(pbl_info->num_pbls, sizeof(*pbl_table), flags); + if (!pbl_table) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < pbl_info->num_pbls; i++) { + va = dma_alloc_coherent(&pdev->dev, pbl_info->pbl_size, + &pa, flags); + if (!va) + goto err; + + memset(va, 0, pbl_info->pbl_size); + pbl_table[i].va = va; + pbl_table[i].pa = pa; + } + + /* Two-Layer PBLs, if we have more than one pbl we need to initialize + * the first one with physical pointers to all of the rest + */ + pbl_main_tbl = (dma_addr_t *)pbl_table[0].va; + for (i = 0; i < pbl_info->num_pbls - 1; i++) + pbl_main_tbl[i] = pbl_table[i + 1].pa; + + return pbl_table; + +err: + for (i--; i >= 0; i--) + dma_free_coherent(&pdev->dev, pbl_info->pbl_size, + pbl_table[i].va, pbl_table[i].pa); + + qedr_free_pbl(dev, pbl_info, pbl_table); + + return ERR_PTR(-ENOMEM); +} + +static int qedr_prepare_pbl_tbl(struct qedr_dev *dev, + struct qedr_pbl_info *pbl_info, + u32 num_pbes, int two_layer_capable) +{ + u32 pbl_capacity; + u32 pbl_size; + u32 num_pbls; + + if ((num_pbes > MAX_PBES_ON_PAGE) && two_layer_capable) { + if (num_pbes > MAX_PBES_TWO_LAYER) { + DP_ERR(dev, "prepare pbl table: too many pages %d\n", + num_pbes); + return -EINVAL; + } + + /* calculate required pbl page size */ + pbl_size = MIN_FW_PBL_PAGE_SIZE; + pbl_capacity = NUM_PBES_ON_PAGE(pbl_size) * + NUM_PBES_ON_PAGE(pbl_size); + + while (pbl_capacity < num_pbes) { + pbl_size *= 2; + pbl_capacity = pbl_size / sizeof(u64); + pbl_capacity = pbl_capacity * pbl_capacity; + } + + num_pbls = DIV_ROUND_UP(num_pbes, NUM_PBES_ON_PAGE(pbl_size)); + num_pbls++; /* One for the layer0 ( points to the pbls) */ + pbl_info->two_layered = true; + } else { + /* One layered PBL */ + num_pbls = 1; + pbl_size = max_t(u32, MIN_FW_PBL_PAGE_SIZE, + roundup_pow_of_two((num_pbes * sizeof(u64)))); + pbl_info->two_layered = false; + } + + pbl_info->num_pbls = num_pbls; + pbl_info->pbl_size = pbl_size; + pbl_info->num_pbes = num_pbes; + + DP_DEBUG(dev, QEDR_MSG_MR, + "prepare pbl table: num_pbes=%d, num_pbls=%d, pbl_size=%d\n", + pbl_info->num_pbes, pbl_info->num_pbls, pbl_info->pbl_size); + + return 0; +} + +static void qedr_populate_pbls(struct qedr_dev *dev, struct ib_umem *umem, + struct qedr_pbl *pbl, + struct qedr_pbl_info *pbl_info) +{ + int shift, pg_cnt, pages, pbe_cnt, total_num_pbes = 0; + struct qedr_pbl *pbl_tbl; + struct scatterlist *sg; + struct regpair *pbe; + int entry; + u32 addr; + + if (!pbl_info->num_pbes) + return; + + /* If we have a two layered pbl, the first pbl points to the rest + * of the pbls and the first entry lays on the second pbl in the table + */ + if (pbl_info->two_layered) + pbl_tbl = &pbl[1]; + else + pbl_tbl = pbl; + + pbe = (struct regpair *)pbl_tbl->va; + if (!pbe) { + DP_ERR(dev, "cannot populate PBL due to a NULL PBE\n"); + return; + } + + pbe_cnt = 0; + + shift = ilog2(umem->page_size); + + for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) { + pages = sg_dma_len(sg) >> shift; + for (pg_cnt = 0; pg_cnt < pages; pg_cnt++) { + /* store the page address in pbe */ + pbe->lo = cpu_to_le32(sg_dma_address(sg) + + umem->page_size * pg_cnt); + addr = upper_32_bits(sg_dma_address(sg) + + umem->page_size * pg_cnt); + pbe->hi = cpu_to_le32(addr); + pbe_cnt++; + total_num_pbes++; + pbe++; + + if (total_num_pbes == pbl_info->num_pbes) + return; + + /* If the given pbl is full storing the pbes, + * move to next pbl. + */ + if (pbe_cnt == (pbl_info->pbl_size / sizeof(u64))) { + pbl_tbl++; + pbe = (struct regpair *)pbl_tbl->va; + pbe_cnt = 0; + } + } + } +} + +static int qedr_copy_cq_uresp(struct qedr_dev *dev, + struct qedr_cq *cq, struct ib_udata *udata) +{ + struct qedr_create_cq_uresp uresp; + int rc; + + memset(&uresp, 0, sizeof(uresp)); + + uresp.db_offset = DB_ADDR_SHIFT(DQ_PWM_OFFSET_UCM_RDMA_CQ_CONS_32BIT); + uresp.icid = cq->icid; + + rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); + if (rc) + DP_ERR(dev, "copy error cqid=0x%x.\n", cq->icid); + + return rc; +} + +static void consume_cqe(struct qedr_cq *cq) +{ + if (cq->latest_cqe == cq->toggle_cqe) + cq->pbl_toggle ^= RDMA_CQE_REQUESTER_TOGGLE_BIT_MASK; + + cq->latest_cqe = qed_chain_consume(&cq->pbl); +} + +static inline int qedr_align_cq_entries(int entries) +{ + u64 size, aligned_size; + + /* We allocate an extra entry that we don't report to the FW. */ + size = (entries + 1) * QEDR_CQE_SIZE; + aligned_size = ALIGN(size, PAGE_SIZE); + + return aligned_size / QEDR_CQE_SIZE; +} + +static inline int qedr_init_user_queue(struct ib_ucontext *ib_ctx, + struct qedr_dev *dev, + struct qedr_userq *q, + u64 buf_addr, size_t buf_len, + int access, int dmasync) +{ + int page_cnt; + int rc; + + q->buf_addr = buf_addr; + q->buf_len = buf_len; + q->umem = ib_umem_get(ib_ctx, q->buf_addr, q->buf_len, access, dmasync); + if (IS_ERR(q->umem)) { + DP_ERR(dev, "create user queue: failed ib_umem_get, got %ld\n", + PTR_ERR(q->umem)); + return PTR_ERR(q->umem); + } + + page_cnt = ib_umem_page_count(q->umem); + rc = qedr_prepare_pbl_tbl(dev, &q->pbl_info, page_cnt, 0); + if (rc) + goto err0; + + q->pbl_tbl = qedr_alloc_pbl_tbl(dev, &q->pbl_info, GFP_KERNEL); + if (IS_ERR_OR_NULL(q->pbl_tbl)) + goto err0; + + qedr_populate_pbls(dev, q->umem, q->pbl_tbl, &q->pbl_info); + + return 0; + +err0: + ib_umem_release(q->umem); + + return rc; +} + +static inline void qedr_init_cq_params(struct qedr_cq *cq, + struct qedr_ucontext *ctx, + struct qedr_dev *dev, int vector, + int chain_entries, int page_cnt, + u64 pbl_ptr, + struct qed_rdma_create_cq_in_params + *params) +{ + memset(params, 0, sizeof(*params)); + params->cq_handle_hi = upper_32_bits((uintptr_t)cq); + params->cq_handle_lo = lower_32_bits((uintptr_t)cq); + params->cnq_id = vector; + params->cq_size = chain_entries - 1; + params->dpi = (ctx) ? ctx->dpi : dev->dpi; + params->pbl_num_pages = page_cnt; + params->pbl_ptr = pbl_ptr; + params->pbl_two_level = 0; +} + +static void doorbell_cq(struct qedr_cq *cq, u32 cons, u8 flags) +{ + /* Flush data before signalling doorbell */ + wmb(); + cq->db.data.agg_flags = flags; + cq->db.data.value = cpu_to_le32(cons); + writeq(cq->db.raw, cq->db_addr); + + /* Make sure write would stick */ + mmiowb(); +} + +int qedr_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) +{ + struct qedr_cq *cq = get_qedr_cq(ibcq); + unsigned long sflags; + + if (cq->cq_type == QEDR_CQ_TYPE_GSI) + return 0; + + spin_lock_irqsave(&cq->cq_lock, sflags); + + cq->arm_flags = 0; + + if (flags & IB_CQ_SOLICITED) + cq->arm_flags |= DQ_UCM_ROCE_CQ_ARM_SE_CF_CMD; + + if (flags & IB_CQ_NEXT_COMP) + cq->arm_flags |= DQ_UCM_ROCE_CQ_ARM_CF_CMD; + + doorbell_cq(cq, cq->cq_cons - 1, cq->arm_flags); + + spin_unlock_irqrestore(&cq->cq_lock, sflags); + + return 0; +} + +struct ib_cq *qedr_create_cq(struct ib_device *ibdev, + const struct ib_cq_init_attr *attr, + struct ib_ucontext *ib_ctx, struct ib_udata *udata) +{ + struct qedr_ucontext *ctx = get_qedr_ucontext(ib_ctx); + struct qed_rdma_destroy_cq_out_params destroy_oparams; + struct qed_rdma_destroy_cq_in_params destroy_iparams; + struct qedr_dev *dev = get_qedr_dev(ibdev); + struct qed_rdma_create_cq_in_params params; + struct qedr_create_cq_ureq ureq; + int vector = attr->comp_vector; + int entries = attr->cqe; + struct qedr_cq *cq; + int chain_entries; + int page_cnt; + u64 pbl_ptr; + u16 icid; + int rc; + + DP_DEBUG(dev, QEDR_MSG_INIT, + "create_cq: called from %s. entries=%d, vector=%d\n", + udata ? "User Lib" : "Kernel", entries, vector); + + if (entries > QEDR_MAX_CQES) { + DP_ERR(dev, + "create cq: the number of entries %d is too high. Must be equal or below %d.\n", + entries, QEDR_MAX_CQES); + return ERR_PTR(-EINVAL); + } + + chain_entries = qedr_align_cq_entries(entries); + chain_entries = min_t(int, chain_entries, QEDR_MAX_CQES); + + cq = kzalloc(sizeof(*cq), GFP_KERNEL); + if (!cq) + return ERR_PTR(-ENOMEM); + + if (udata) { + memset(&ureq, 0, sizeof(ureq)); + if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) { + DP_ERR(dev, + "create cq: problem copying data from user space\n"); + goto err0; + } + + if (!ureq.len) { + DP_ERR(dev, + "create cq: cannot create a cq with 0 entries\n"); + goto err0; + } + + cq->cq_type = QEDR_CQ_TYPE_USER; + + rc = qedr_init_user_queue(ib_ctx, dev, &cq->q, ureq.addr, + ureq.len, IB_ACCESS_LOCAL_WRITE, 1); + if (rc) + goto err0; + + pbl_ptr = cq->q.pbl_tbl->pa; + page_cnt = cq->q.pbl_info.num_pbes; + } else { + cq->cq_type = QEDR_CQ_TYPE_KERNEL; + + rc = dev->ops->common->chain_alloc(dev->cdev, + QED_CHAIN_USE_TO_CONSUME, + QED_CHAIN_MODE_PBL, + QED_CHAIN_CNT_TYPE_U32, + chain_entries, + sizeof(union rdma_cqe), + &cq->pbl); + if (rc) + goto err1; + + page_cnt = qed_chain_get_page_cnt(&cq->pbl); + pbl_ptr = qed_chain_get_pbl_phys(&cq->pbl); + } + + qedr_init_cq_params(cq, ctx, dev, vector, chain_entries, page_cnt, + pbl_ptr, ¶ms); + + rc = dev->ops->rdma_create_cq(dev->rdma_ctx, ¶ms, &icid); + if (rc) + goto err2; + + cq->icid = icid; + cq->sig = QEDR_CQ_MAGIC_NUMBER; + spin_lock_init(&cq->cq_lock); + + if (ib_ctx) { + rc = qedr_copy_cq_uresp(dev, cq, udata); + if (rc) + goto err3; + } else { + /* Generate doorbell address. */ + cq->db_addr = dev->db_addr + + DB_ADDR_SHIFT(DQ_PWM_OFFSET_UCM_RDMA_CQ_CONS_32BIT); + cq->db.data.icid = cq->icid; + cq->db.data.params = DB_AGG_CMD_SET << + RDMA_PWM_VAL32_DATA_AGG_CMD_SHIFT; + + /* point to the very last element, passing it we will toggle */ + cq->toggle_cqe = qed_chain_get_last_elem(&cq->pbl); + cq->pbl_toggle = RDMA_CQE_REQUESTER_TOGGLE_BIT_MASK; + cq->latest_cqe = NULL; + consume_cqe(cq); + cq->cq_cons = qed_chain_get_cons_idx_u32(&cq->pbl); + } + + DP_DEBUG(dev, QEDR_MSG_CQ, + "create cq: icid=0x%0x, addr=%p, size(entries)=0x%0x\n", + cq->icid, cq, params.cq_size); + + return &cq->ibcq; + +err3: + destroy_iparams.icid = cq->icid; + dev->ops->rdma_destroy_cq(dev->rdma_ctx, &destroy_iparams, + &destroy_oparams); +err2: + if (udata) + qedr_free_pbl(dev, &cq->q.pbl_info, cq->q.pbl_tbl); + else + dev->ops->common->chain_free(dev->cdev, &cq->pbl); +err1: + if (udata) + ib_umem_release(cq->q.umem); +err0: + kfree(cq); + return ERR_PTR(-EINVAL); +} + +int qedr_resize_cq(struct ib_cq *ibcq, int new_cnt, struct ib_udata *udata) +{ + struct qedr_dev *dev = get_qedr_dev(ibcq->device); + struct qedr_cq *cq = get_qedr_cq(ibcq); + + DP_ERR(dev, "cq %p RESIZE NOT SUPPORTED\n", cq); + + return 0; +} + +int qedr_destroy_cq(struct ib_cq *ibcq) +{ + struct qedr_dev *dev = get_qedr_dev(ibcq->device); + struct qed_rdma_destroy_cq_out_params oparams; + struct qed_rdma_destroy_cq_in_params iparams; + struct qedr_cq *cq = get_qedr_cq(ibcq); + + DP_DEBUG(dev, QEDR_MSG_CQ, "destroy cq: cq_id %d", cq->icid); + + /* GSIs CQs are handled by driver, so they don't exist in the FW */ + if (cq->cq_type != QEDR_CQ_TYPE_GSI) { + iparams.icid = cq->icid; + dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams); + dev->ops->common->chain_free(dev->cdev, &cq->pbl); + } + + if (ibcq->uobject && ibcq->uobject->context) { + qedr_free_pbl(dev, &cq->q.pbl_info, cq->q.pbl_tbl); + ib_umem_release(cq->q.umem); + } + + kfree(cq); + + return 0; +} diff --git a/drivers/infiniband/hw/qedr/verbs.h b/drivers/infiniband/hw/qedr/verbs.h index 9472044dd5873..36c8a692f740a 100644 --- a/drivers/infiniband/hw/qedr/verbs.h +++ b/drivers/infiniband/hw/qedr/verbs.h @@ -40,6 +40,8 @@ int qedr_modify_port(struct ib_device *, u8 port, int mask, int qedr_query_gid(struct ib_device *, u8 port, int index, union ib_gid *gid); +int qedr_query_pkey(struct ib_device *, u8 port, u16 index, u16 *pkey); + struct ib_ucontext *qedr_alloc_ucontext(struct ib_device *, struct ib_udata *); int qedr_dealloc_ucontext(struct ib_ucontext *); @@ -49,4 +51,16 @@ int qedr_del_gid(struct ib_device *device, u8 port_num, int qedr_add_gid(struct ib_device *device, u8 port_num, unsigned int index, const union ib_gid *gid, const struct ib_gid_attr *attr, void **context); +struct ib_pd *qedr_alloc_pd(struct ib_device *, + struct ib_ucontext *, struct ib_udata *); +int qedr_dealloc_pd(struct ib_pd *pd); + +struct ib_cq *qedr_create_cq(struct ib_device *ibdev, + const struct ib_cq_init_attr *attr, + struct ib_ucontext *ib_ctx, + struct ib_udata *udata); +int qedr_resize_cq(struct ib_cq *, int cqe, struct ib_udata *); +int qedr_destroy_cq(struct ib_cq *); +int qedr_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags); + #endif diff --git a/include/uapi/rdma/qedr-abi.h b/include/uapi/rdma/qedr-abi.h index f7c7fff7a8777..b0fc5f2125e02 100644 --- a/include/uapi/rdma/qedr-abi.h +++ b/include/uapi/rdma/qedr-abi.h @@ -50,4 +50,23 @@ struct qedr_alloc_ucontext_resp { __u32 sges_per_srq_wr; __u32 max_cqes; }; + +struct qedr_alloc_pd_ureq { + __u64 rsvd1; +}; + +struct qedr_alloc_pd_uresp { + __u32 pd_id; +}; + +struct qedr_create_cq_ureq { + __u64 addr; + __u64 len; +}; + +struct qedr_create_cq_uresp { + __u32 db_offset; + __u16 icid; +}; + #endif /* __QEDR_USER_H__ */ -- GitLab From cecbcddf6461a11ce229e80bb3981415220c9763 Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 10 Oct 2016 13:15:34 +0300 Subject: [PATCH 0565/1167] qedr: Add support for QP verbs Add support for Queue Pair verbs which adds, deletes, modifies and queries Queue Pairs. Signed-off-by: Rajesh Borundia Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/main.c | 15 +- drivers/infiniband/hw/qedr/qedr.h | 125 +++ drivers/infiniband/hw/qedr/qedr_cm.h | 40 + drivers/infiniband/hw/qedr/qedr_hsi_rdma.h | 11 + drivers/infiniband/hw/qedr/verbs.c | 1089 ++++++++++++++++++++ drivers/infiniband/hw/qedr/verbs.h | 7 + include/uapi/rdma/qedr-abi.h | 34 + 7 files changed, 1320 insertions(+), 1 deletion(-) create mode 100644 drivers/infiniband/hw/qedr/qedr_cm.h diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 35928abb6b639..13ba47b7b99fd 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -48,6 +48,8 @@ MODULE_AUTHOR("QLogic Corporation"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(QEDR_MODULE_VERSION); +#define QEDR_WQ_MULTIPLIER_DFT (3) + void qedr_ib_dispatch_event(struct qedr_dev *dev, u8 port_num, enum ib_event_type type) { @@ -94,7 +96,11 @@ static int qedr_register_device(struct qedr_dev *dev) QEDR_UVERBS(CREATE_CQ) | QEDR_UVERBS(RESIZE_CQ) | QEDR_UVERBS(DESTROY_CQ) | - QEDR_UVERBS(REQ_NOTIFY_CQ); + QEDR_UVERBS(REQ_NOTIFY_CQ) | + QEDR_UVERBS(CREATE_QP) | + QEDR_UVERBS(MODIFY_QP) | + QEDR_UVERBS(QUERY_QP) | + QEDR_UVERBS(DESTROY_QP); dev->ibdev.phys_port_cnt = 1; dev->ibdev.num_comp_vectors = dev->num_cnq; @@ -120,6 +126,11 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.resize_cq = qedr_resize_cq; dev->ibdev.req_notify_cq = qedr_arm_cq; + dev->ibdev.create_qp = qedr_create_qp; + dev->ibdev.modify_qp = qedr_modify_qp; + dev->ibdev.query_qp = qedr_query_qp; + dev->ibdev.destroy_qp = qedr_destroy_qp; + dev->ibdev.query_pkey = qedr_query_pkey; dev->ibdev.dma_device = &dev->pdev->dev; @@ -630,6 +641,8 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, goto init_err; } + dev->wq_multiplier = QEDR_WQ_MULTIPLIER_DFT; + qedr_pci_set_atomic(dev, pdev); rc = qedr_alloc_resources(dev); diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 9e2846a599cea..e9fe941c48ad7 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -52,6 +52,9 @@ #define QEDR_MSG_MISC "MISC" #define QEDR_MSG_CQ " CQ" #define QEDR_MSG_MR " MR" +#define QEDR_MSG_RQ " RQ" +#define QEDR_MSG_SQ " SQ" +#define QEDR_MSG_QP " QP" #define QEDR_CQ_MAGIC_NUMBER (0x11223344) @@ -143,6 +146,8 @@ struct qedr_dev { u32 dp_module; u8 dp_level; u8 num_hwfns; + uint wq_multiplier; + }; #define QEDR_MAX_SQ_PBL (0x8000) @@ -272,6 +277,122 @@ struct qedr_mm { struct list_head entry; }; +union db_prod32 { + struct rdma_pwm_val16_data data; + u32 raw; +}; + +struct qedr_qp_hwq_info { + /* WQE Elements */ + struct qed_chain pbl; + u64 p_phys_addr_tbl; + u32 max_sges; + + /* WQE */ + u16 prod; + u16 cons; + u16 wqe_cons; + u16 max_wr; + + /* DB */ + void __iomem *db; + union db_prod32 db_data; +}; + +#define QEDR_INC_SW_IDX(p_info, index) \ + do { \ + p_info->index = (p_info->index + 1) & \ + qed_chain_get_capacity(p_info->pbl) \ + } while (0) + +enum qedr_qp_err_bitmap { + QEDR_QP_ERR_SQ_FULL = 1, + QEDR_QP_ERR_RQ_FULL = 2, + QEDR_QP_ERR_BAD_SR = 4, + QEDR_QP_ERR_BAD_RR = 8, + QEDR_QP_ERR_SQ_PBL_FULL = 16, + QEDR_QP_ERR_RQ_PBL_FULL = 32, +}; + +struct qedr_qp { + struct ib_qp ibqp; /* must be first */ + struct qedr_dev *dev; + + struct qedr_qp_hwq_info sq; + struct qedr_qp_hwq_info rq; + + u32 max_inline_data; + + /* Lock for QP's */ + spinlock_t q_lock; + struct qedr_cq *sq_cq; + struct qedr_cq *rq_cq; + struct qedr_srq *srq; + enum qed_roce_qp_state state; + u32 id; + struct qedr_pd *pd; + enum ib_qp_type qp_type; + struct qed_rdma_qp *qed_qp; + u32 qp_id; + u16 icid; + u16 mtu; + int sgid_idx; + u32 rq_psn; + u32 sq_psn; + u32 qkey; + u32 dest_qp_num; + + /* Relevant to qps created from kernel space only (ULPs) */ + u8 prev_wqe_size; + u16 wqe_cons; + u32 err_bitmap; + bool signaled; + + /* SQ shadow */ + struct { + u64 wr_id; + enum ib_wc_opcode opcode; + u32 bytes_len; + u8 wqe_size; + bool signaled; + dma_addr_t icrc_mapping; + u32 *icrc; + struct qedr_mr *mr; + } *wqe_wr_id; + + /* RQ shadow */ + struct { + u64 wr_id; + struct ib_sge sg_list[RDMA_MAX_SGE_PER_RQ_WQE]; + u8 wqe_size; + + u16 vlan_id; + int rc; + } *rqe_wr_id; + + /* Relevant to qps created from user space only (applications) */ + struct qedr_userq usq; + struct qedr_userq urq; +}; + +static inline int qedr_get_dmac(struct qedr_dev *dev, + struct ib_ah_attr *ah_attr, u8 *mac_addr) +{ + union ib_gid zero_sgid = { { 0 } }; + struct in6_addr in6; + + if (!memcmp(&ah_attr->grh.dgid, &zero_sgid, sizeof(union ib_gid))) { + DP_ERR(dev, "Local port GID not supported\n"); + eth_zero_addr(mac_addr); + return -EINVAL; + } + + memcpy(&in6, ah_attr->grh.dgid.raw, sizeof(in6)); + ether_addr_copy(mac_addr, ah_attr->dmac); + + return 0; +} + static inline struct qedr_ucontext *get_qedr_ucontext(struct ib_ucontext *ibucontext) { @@ -293,4 +414,8 @@ static inline struct qedr_cq *get_qedr_cq(struct ib_cq *ibcq) return container_of(ibcq, struct qedr_cq, ibcq); } +static inline struct qedr_qp *get_qedr_qp(struct ib_qp *ibqp) +{ + return container_of(ibqp, struct qedr_qp, ibqp); +} #endif diff --git a/drivers/infiniband/hw/qedr/qedr_cm.h b/drivers/infiniband/hw/qedr/qedr_cm.h new file mode 100644 index 0000000000000..b8a8b76d77b81 --- /dev/null +++ b/drivers/infiniband/hw/qedr/qedr_cm.h @@ -0,0 +1,40 @@ +/* QLogic qedr NIC Driver + * Copyright (c) 2015-2016 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef LINUX_QEDR_CM_H_ +#define LINUX_QEDR_CM_H_ + +static inline u32 qedr_get_ipv4_from_gid(u8 *gid) +{ + return *(u32 *)(void *)&gid[12]; +} + +#endif diff --git a/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h b/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h index 84f6520107cc7..47705598eec60 100644 --- a/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h +++ b/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h @@ -158,6 +158,17 @@ struct rdma_srq_sge { __le32 l_key; }; +/* Rdma doorbell data for SQ and RQ */ +struct rdma_pwm_val16_data { + __le16 icid; + __le16 value; +}; + +union rdma_pwm_val16_data_union { + struct rdma_pwm_val16_data as_struct; + __le32 as_dword; +}; + /* Rdma doorbell data for CQ */ struct rdma_pwm_val32_data { __le16 icid; diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index b525c6cf1df05..a0d1c5fffb632 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -48,6 +48,7 @@ #include "qedr.h" #include "verbs.h" #include +#include "qedr_cm.h" #define DB_ADDR_SHIFT(addr) ((addr) << DB_PWM_ADDR_OFFSET_SHIFT) @@ -993,3 +994,1091 @@ int qedr_destroy_cq(struct ib_cq *ibcq) return 0; } + +static inline int get_gid_info_from_table(struct ib_qp *ibqp, + struct ib_qp_attr *attr, + int attr_mask, + struct qed_rdma_modify_qp_in_params + *qp_params) +{ + enum rdma_network_type nw_type; + struct ib_gid_attr gid_attr; + union ib_gid gid; + u32 ipv4_addr; + int rc = 0; + int i; + + rc = ib_get_cached_gid(ibqp->device, attr->ah_attr.port_num, + attr->ah_attr.grh.sgid_index, &gid, &gid_attr); + if (rc) + return rc; + + if (!memcmp(&gid, &zgid, sizeof(gid))) + return -ENOENT; + + if (gid_attr.ndev) { + qp_params->vlan_id = rdma_vlan_dev_vlan_id(gid_attr.ndev); + + dev_put(gid_attr.ndev); + nw_type = ib_gid_to_network_type(gid_attr.gid_type, &gid); + switch (nw_type) { + case RDMA_NETWORK_IPV6: + memcpy(&qp_params->sgid.bytes[0], &gid.raw[0], + sizeof(qp_params->sgid)); + memcpy(&qp_params->dgid.bytes[0], + &attr->ah_attr.grh.dgid, + sizeof(qp_params->dgid)); + qp_params->roce_mode = ROCE_V2_IPV6; + SET_FIELD(qp_params->modify_flags, + QED_ROCE_MODIFY_QP_VALID_ROCE_MODE, 1); + break; + case RDMA_NETWORK_IB: + memcpy(&qp_params->sgid.bytes[0], &gid.raw[0], + sizeof(qp_params->sgid)); + memcpy(&qp_params->dgid.bytes[0], + &attr->ah_attr.grh.dgid, + sizeof(qp_params->dgid)); + qp_params->roce_mode = ROCE_V1; + break; + case RDMA_NETWORK_IPV4: + memset(&qp_params->sgid, 0, sizeof(qp_params->sgid)); + memset(&qp_params->dgid, 0, sizeof(qp_params->dgid)); + ipv4_addr = qedr_get_ipv4_from_gid(gid.raw); + qp_params->sgid.ipv4_addr = ipv4_addr; + ipv4_addr = + qedr_get_ipv4_from_gid(attr->ah_attr.grh.dgid.raw); + qp_params->dgid.ipv4_addr = ipv4_addr; + SET_FIELD(qp_params->modify_flags, + QED_ROCE_MODIFY_QP_VALID_ROCE_MODE, 1); + qp_params->roce_mode = ROCE_V2_IPV4; + break; + } + } + + for (i = 0; i < 4; i++) { + qp_params->sgid.dwords[i] = ntohl(qp_params->sgid.dwords[i]); + qp_params->dgid.dwords[i] = ntohl(qp_params->dgid.dwords[i]); + } + + if (qp_params->vlan_id >= VLAN_CFI_MASK) + qp_params->vlan_id = 0; + + return 0; +} + +static void qedr_cleanup_user_sq(struct qedr_dev *dev, struct qedr_qp *qp) +{ + qedr_free_pbl(dev, &qp->usq.pbl_info, qp->usq.pbl_tbl); + ib_umem_release(qp->usq.umem); +} + +static void qedr_cleanup_user_rq(struct qedr_dev *dev, struct qedr_qp *qp) +{ + qedr_free_pbl(dev, &qp->urq.pbl_info, qp->urq.pbl_tbl); + ib_umem_release(qp->urq.umem); +} + +static void qedr_cleanup_kernel_sq(struct qedr_dev *dev, struct qedr_qp *qp) +{ + dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl); + kfree(qp->wqe_wr_id); +} + +static void qedr_cleanup_kernel_rq(struct qedr_dev *dev, struct qedr_qp *qp) +{ + dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl); + kfree(qp->rqe_wr_id); +} + +static int qedr_check_qp_attrs(struct ib_pd *ibpd, struct qedr_dev *dev, + struct ib_qp_init_attr *attrs) +{ + struct qedr_device_attr *qattr = &dev->attr; + + /* QP0... attrs->qp_type == IB_QPT_GSI */ + if (attrs->qp_type != IB_QPT_RC && attrs->qp_type != IB_QPT_GSI) { + DP_DEBUG(dev, QEDR_MSG_QP, + "create qp: unsupported qp type=0x%x requested\n", + attrs->qp_type); + return -EINVAL; + } + + if (attrs->cap.max_send_wr > qattr->max_sqe) { + DP_ERR(dev, + "create qp: cannot create a SQ with %d elements (max_send_wr=0x%x)\n", + attrs->cap.max_send_wr, qattr->max_sqe); + return -EINVAL; + } + + if (attrs->cap.max_inline_data > qattr->max_inline) { + DP_ERR(dev, + "create qp: unsupported inline data size=0x%x requested (max_inline=0x%x)\n", + attrs->cap.max_inline_data, qattr->max_inline); + return -EINVAL; + } + + if (attrs->cap.max_send_sge > qattr->max_sge) { + DP_ERR(dev, + "create qp: unsupported send_sge=0x%x requested (max_send_sge=0x%x)\n", + attrs->cap.max_send_sge, qattr->max_sge); + return -EINVAL; + } + + if (attrs->cap.max_recv_sge > qattr->max_sge) { + DP_ERR(dev, + "create qp: unsupported recv_sge=0x%x requested (max_recv_sge=0x%x)\n", + attrs->cap.max_recv_sge, qattr->max_sge); + return -EINVAL; + } + + /* Unprivileged user space cannot create special QP */ + if (ibpd->uobject && attrs->qp_type == IB_QPT_GSI) { + DP_ERR(dev, + "create qp: userspace can't create special QPs of type=0x%x\n", + attrs->qp_type); + return -EINVAL; + } + + return 0; +} + +static void qedr_copy_rq_uresp(struct qedr_create_qp_uresp *uresp, + struct qedr_qp *qp) +{ + uresp->rq_db_offset = DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_ROCE_RQ_PROD); + uresp->rq_icid = qp->icid; +} + +static void qedr_copy_sq_uresp(struct qedr_create_qp_uresp *uresp, + struct qedr_qp *qp) +{ + uresp->sq_db_offset = DB_ADDR_SHIFT(DQ_PWM_OFFSET_XCM_RDMA_SQ_PROD); + uresp->sq_icid = qp->icid + 1; +} + +static int qedr_copy_qp_uresp(struct qedr_dev *dev, + struct qedr_qp *qp, struct ib_udata *udata) +{ + struct qedr_create_qp_uresp uresp; + int rc; + + memset(&uresp, 0, sizeof(uresp)); + qedr_copy_sq_uresp(&uresp, qp); + qedr_copy_rq_uresp(&uresp, qp); + + uresp.atomic_supported = dev->atomic_cap != IB_ATOMIC_NONE; + uresp.qp_id = qp->qp_id; + + rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); + if (rc) + DP_ERR(dev, + "create qp: failed a copy to user space with qp icid=0x%x.\n", + qp->icid); + + return rc; +} + +static void qedr_set_qp_init_params(struct qedr_dev *dev, + struct qedr_qp *qp, + struct qedr_pd *pd, + struct ib_qp_init_attr *attrs) +{ + qp->pd = pd; + + spin_lock_init(&qp->q_lock); + + qp->qp_type = attrs->qp_type; + qp->max_inline_data = attrs->cap.max_inline_data; + qp->sq.max_sges = attrs->cap.max_send_sge; + qp->state = QED_ROCE_QP_STATE_RESET; + qp->signaled = (attrs->sq_sig_type == IB_SIGNAL_ALL_WR) ? true : false; + qp->sq_cq = get_qedr_cq(attrs->send_cq); + qp->rq_cq = get_qedr_cq(attrs->recv_cq); + qp->dev = dev; + + DP_DEBUG(dev, QEDR_MSG_QP, + "QP params:\tpd = %d, qp_type = %d, max_inline_data = %d, state = %d, signaled = %d, use_srq=%d\n", + pd->pd_id, qp->qp_type, qp->max_inline_data, + qp->state, qp->signaled, (attrs->srq) ? 1 : 0); + DP_DEBUG(dev, QEDR_MSG_QP, + "SQ params:\tsq_max_sges = %d, sq_cq_id = %d\n", + qp->sq.max_sges, qp->sq_cq->icid); + qp->rq.max_sges = attrs->cap.max_recv_sge; + DP_DEBUG(dev, QEDR_MSG_QP, + "RQ params:\trq_max_sges = %d, rq_cq_id = %d\n", + qp->rq.max_sges, qp->rq_cq->icid); +} + +static inline void +qedr_init_qp_user_params(struct qed_rdma_create_qp_in_params *params, + struct qedr_create_qp_ureq *ureq) +{ + /* QP handle to be written in CQE */ + params->qp_handle_lo = ureq->qp_handle_lo; + params->qp_handle_hi = ureq->qp_handle_hi; +} + +static inline void +qedr_init_qp_kernel_doorbell_sq(struct qedr_dev *dev, struct qedr_qp *qp) +{ + qp->sq.db = dev->db_addr + + DB_ADDR_SHIFT(DQ_PWM_OFFSET_XCM_RDMA_SQ_PROD); + qp->sq.db_data.data.icid = qp->icid + 1; +} + +static inline void +qedr_init_qp_kernel_doorbell_rq(struct qedr_dev *dev, struct qedr_qp *qp) +{ + qp->rq.db = dev->db_addr + + DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_ROCE_RQ_PROD); + qp->rq.db_data.data.icid = qp->icid; +} + +static inline int +qedr_init_qp_kernel_params_rq(struct qedr_dev *dev, + struct qedr_qp *qp, struct ib_qp_init_attr *attrs) +{ + /* Allocate driver internal RQ array */ + qp->rqe_wr_id = kcalloc(qp->rq.max_wr, sizeof(*qp->rqe_wr_id), + GFP_KERNEL); + if (!qp->rqe_wr_id) + return -ENOMEM; + + DP_DEBUG(dev, QEDR_MSG_QP, "RQ max_wr set to %d.\n", qp->rq.max_wr); + + return 0; +} + +static inline int +qedr_init_qp_kernel_params_sq(struct qedr_dev *dev, + struct qedr_qp *qp, + struct ib_qp_init_attr *attrs, + struct qed_rdma_create_qp_in_params *params) +{ + u32 temp_max_wr; + + /* Allocate driver internal SQ array */ + temp_max_wr = attrs->cap.max_send_wr * dev->wq_multiplier; + temp_max_wr = min_t(u32, temp_max_wr, dev->attr.max_sqe); + + /* temp_max_wr < attr->max_sqe < u16 so the casting is safe */ + qp->sq.max_wr = (u16)temp_max_wr; + qp->wqe_wr_id = kcalloc(qp->sq.max_wr, sizeof(*qp->wqe_wr_id), + GFP_KERNEL); + if (!qp->wqe_wr_id) + return -ENOMEM; + + DP_DEBUG(dev, QEDR_MSG_QP, "SQ max_wr set to %d.\n", qp->sq.max_wr); + + /* QP handle to be written in CQE */ + params->qp_handle_lo = lower_32_bits((uintptr_t)qp); + params->qp_handle_hi = upper_32_bits((uintptr_t)qp); + + return 0; +} + +static inline int qedr_init_qp_kernel_sq(struct qedr_dev *dev, + struct qedr_qp *qp, + struct ib_qp_init_attr *attrs) +{ + u32 n_sq_elems, n_sq_entries; + int rc; + + /* A single work request may take up to QEDR_MAX_SQ_WQE_SIZE elements in + * the ring. The ring should allow at least a single WR, even if the + * user requested none, due to allocation issues. + */ + n_sq_entries = attrs->cap.max_send_wr; + n_sq_entries = min_t(u32, n_sq_entries, dev->attr.max_sqe); + n_sq_entries = max_t(u32, n_sq_entries, 1); + n_sq_elems = n_sq_entries * QEDR_MAX_SQE_ELEMENTS_PER_SQE; + rc = dev->ops->common->chain_alloc(dev->cdev, + QED_CHAIN_USE_TO_PRODUCE, + QED_CHAIN_MODE_PBL, + QED_CHAIN_CNT_TYPE_U32, + n_sq_elems, + QEDR_SQE_ELEMENT_SIZE, + &qp->sq.pbl); + if (rc) { + DP_ERR(dev, "failed to allocate QP %p SQ\n", qp); + return rc; + } + + DP_DEBUG(dev, QEDR_MSG_SQ, + "SQ Pbl base addr = %llx max_send_wr=%d max_wr=%d capacity=%d, rc=%d\n", + qed_chain_get_pbl_phys(&qp->sq.pbl), attrs->cap.max_send_wr, + n_sq_entries, qed_chain_get_capacity(&qp->sq.pbl), rc); + return 0; +} + +static inline int qedr_init_qp_kernel_rq(struct qedr_dev *dev, + struct qedr_qp *qp, + struct ib_qp_init_attr *attrs) +{ + u32 n_rq_elems, n_rq_entries; + int rc; + + /* A single work request may take up to QEDR_MAX_RQ_WQE_SIZE elements in + * the ring. There ring should allow at least a single WR, even if the + * user requested none, due to allocation issues. + */ + n_rq_entries = max_t(u32, attrs->cap.max_recv_wr, 1); + n_rq_elems = n_rq_entries * QEDR_MAX_RQE_ELEMENTS_PER_RQE; + rc = dev->ops->common->chain_alloc(dev->cdev, + QED_CHAIN_USE_TO_CONSUME_PRODUCE, + QED_CHAIN_MODE_PBL, + QED_CHAIN_CNT_TYPE_U32, + n_rq_elems, + QEDR_RQE_ELEMENT_SIZE, + &qp->rq.pbl); + + if (rc) { + DP_ERR(dev, "failed to allocate memory for QP %p RQ\n", qp); + return -ENOMEM; + } + + DP_DEBUG(dev, QEDR_MSG_RQ, + "RQ Pbl base addr = %llx max_recv_wr=%d max_wr=%d capacity=%d, rc=%d\n", + qed_chain_get_pbl_phys(&qp->rq.pbl), attrs->cap.max_recv_wr, + n_rq_entries, qed_chain_get_capacity(&qp->rq.pbl), rc); + + /* n_rq_entries < u16 so the casting is safe */ + qp->rq.max_wr = (u16)n_rq_entries; + + return 0; +} + +static inline void +qedr_init_qp_in_params_sq(struct qedr_dev *dev, + struct qedr_pd *pd, + struct qedr_qp *qp, + struct ib_qp_init_attr *attrs, + struct ib_udata *udata, + struct qed_rdma_create_qp_in_params *params) +{ + /* QP handle to be written in an async event */ + params->qp_handle_async_lo = lower_32_bits((uintptr_t)qp); + params->qp_handle_async_hi = upper_32_bits((uintptr_t)qp); + + params->signal_all = (attrs->sq_sig_type == IB_SIGNAL_ALL_WR); + params->fmr_and_reserved_lkey = !udata; + params->pd = pd->pd_id; + params->dpi = pd->uctx ? pd->uctx->dpi : dev->dpi; + params->sq_cq_id = get_qedr_cq(attrs->send_cq)->icid; + params->max_sq_sges = 0; + params->stats_queue = 0; + + if (udata) { + params->sq_num_pages = qp->usq.pbl_info.num_pbes; + params->sq_pbl_ptr = qp->usq.pbl_tbl->pa; + } else { + params->sq_num_pages = qed_chain_get_page_cnt(&qp->sq.pbl); + params->sq_pbl_ptr = qed_chain_get_pbl_phys(&qp->sq.pbl); + } +} + +static inline void +qedr_init_qp_in_params_rq(struct qedr_qp *qp, + struct ib_qp_init_attr *attrs, + struct ib_udata *udata, + struct qed_rdma_create_qp_in_params *params) +{ + params->rq_cq_id = get_qedr_cq(attrs->recv_cq)->icid; + params->srq_id = 0; + params->use_srq = false; + + if (udata) { + params->rq_num_pages = qp->urq.pbl_info.num_pbes; + params->rq_pbl_ptr = qp->urq.pbl_tbl->pa; + } else { + params->rq_num_pages = qed_chain_get_page_cnt(&qp->rq.pbl); + params->rq_pbl_ptr = qed_chain_get_pbl_phys(&qp->rq.pbl); + } +} + +static inline void qedr_qp_user_print(struct qedr_dev *dev, struct qedr_qp *qp) +{ + DP_DEBUG(dev, QEDR_MSG_QP, + "create qp: successfully created user QP. qp=%p, sq_addr=0x%llx, sq_len=%zd, rq_addr=0x%llx, rq_len=%zd\n", + qp, qp->usq.buf_addr, qp->usq.buf_len, qp->urq.buf_addr, + qp->urq.buf_len); +} + +static inline int qedr_init_user_qp(struct ib_ucontext *ib_ctx, + struct qedr_dev *dev, + struct qedr_qp *qp, + struct qedr_create_qp_ureq *ureq) +{ + int rc; + + /* SQ - read access only (0), dma sync not required (0) */ + rc = qedr_init_user_queue(ib_ctx, dev, &qp->usq, ureq->sq_addr, + ureq->sq_len, 0, 0); + if (rc) + return rc; + + /* RQ - read access only (0), dma sync not required (0) */ + rc = qedr_init_user_queue(ib_ctx, dev, &qp->urq, ureq->rq_addr, + ureq->rq_len, 0, 0); + + if (rc) + qedr_cleanup_user_sq(dev, qp); + return rc; +} + +static inline int +qedr_init_kernel_qp(struct qedr_dev *dev, + struct qedr_qp *qp, + struct ib_qp_init_attr *attrs, + struct qed_rdma_create_qp_in_params *params) +{ + int rc; + + rc = qedr_init_qp_kernel_sq(dev, qp, attrs); + if (rc) { + DP_ERR(dev, "failed to init kernel QP %p SQ\n", qp); + return rc; + } + + rc = qedr_init_qp_kernel_params_sq(dev, qp, attrs, params); + if (rc) { + dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl); + DP_ERR(dev, "failed to init kernel QP %p SQ params\n", qp); + return rc; + } + + rc = qedr_init_qp_kernel_rq(dev, qp, attrs); + if (rc) { + qedr_cleanup_kernel_sq(dev, qp); + DP_ERR(dev, "failed to init kernel QP %p RQ\n", qp); + return rc; + } + + rc = qedr_init_qp_kernel_params_rq(dev, qp, attrs); + if (rc) { + DP_ERR(dev, "failed to init kernel QP %p RQ params\n", qp); + qedr_cleanup_kernel_sq(dev, qp); + dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl); + return rc; + } + + return rc; +} + +struct ib_qp *qedr_create_qp(struct ib_pd *ibpd, + struct ib_qp_init_attr *attrs, + struct ib_udata *udata) +{ + struct qedr_dev *dev = get_qedr_dev(ibpd->device); + struct qed_rdma_create_qp_out_params out_params; + struct qed_rdma_create_qp_in_params in_params; + struct qedr_pd *pd = get_qedr_pd(ibpd); + struct ib_ucontext *ib_ctx = NULL; + struct qedr_ucontext *ctx = NULL; + struct qedr_create_qp_ureq ureq; + struct qedr_qp *qp; + int rc = 0; + + DP_DEBUG(dev, QEDR_MSG_QP, "create qp: called from %s, pd=%p\n", + udata ? "user library" : "kernel", pd); + + rc = qedr_check_qp_attrs(ibpd, dev, attrs); + if (rc) + return ERR_PTR(rc); + + qp = kzalloc(sizeof(*qp), GFP_KERNEL); + if (!qp) + return ERR_PTR(-ENOMEM); + + if (attrs->srq) + return ERR_PTR(-EINVAL); + + DP_DEBUG(dev, QEDR_MSG_QP, + "create qp: sq_cq=%p, sq_icid=%d, rq_cq=%p, rq_icid=%d\n", + get_qedr_cq(attrs->send_cq), + get_qedr_cq(attrs->send_cq)->icid, + get_qedr_cq(attrs->recv_cq), + get_qedr_cq(attrs->recv_cq)->icid); + + qedr_set_qp_init_params(dev, qp, pd, attrs); + + memset(&in_params, 0, sizeof(in_params)); + + if (udata) { + if (!(udata && ibpd->uobject && ibpd->uobject->context)) + goto err0; + + ib_ctx = ibpd->uobject->context; + ctx = get_qedr_ucontext(ib_ctx); + + memset(&ureq, 0, sizeof(ureq)); + if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) { + DP_ERR(dev, + "create qp: problem copying data from user space\n"); + goto err0; + } + + rc = qedr_init_user_qp(ib_ctx, dev, qp, &ureq); + if (rc) + goto err0; + + qedr_init_qp_user_params(&in_params, &ureq); + } else { + rc = qedr_init_kernel_qp(dev, qp, attrs, &in_params); + if (rc) + goto err0; + } + + qedr_init_qp_in_params_sq(dev, pd, qp, attrs, udata, &in_params); + qedr_init_qp_in_params_rq(qp, attrs, udata, &in_params); + + qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx, + &in_params, &out_params); + + if (!qp->qed_qp) + goto err1; + + qp->qp_id = out_params.qp_id; + qp->icid = out_params.icid; + qp->ibqp.qp_num = qp->qp_id; + + if (udata) { + rc = qedr_copy_qp_uresp(dev, qp, udata); + if (rc) + goto err2; + + qedr_qp_user_print(dev, qp); + } else { + qedr_init_qp_kernel_doorbell_sq(dev, qp); + qedr_init_qp_kernel_doorbell_rq(dev, qp); + } + + DP_DEBUG(dev, QEDR_MSG_QP, "created %s space QP %p\n", + udata ? "user" : "kernel", qp); + + return &qp->ibqp; + +err2: + rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp); + if (rc) + DP_ERR(dev, "create qp: fatal fault. rc=%d", rc); +err1: + if (udata) { + qedr_cleanup_user_sq(dev, qp); + qedr_cleanup_user_rq(dev, qp); + } else { + qedr_cleanup_kernel_sq(dev, qp); + qedr_cleanup_kernel_rq(dev, qp); + } + +err0: + kfree(qp); + + return ERR_PTR(-EFAULT); +} + +enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state) +{ + switch (qp_state) { + case QED_ROCE_QP_STATE_RESET: + return IB_QPS_RESET; + case QED_ROCE_QP_STATE_INIT: + return IB_QPS_INIT; + case QED_ROCE_QP_STATE_RTR: + return IB_QPS_RTR; + case QED_ROCE_QP_STATE_RTS: + return IB_QPS_RTS; + case QED_ROCE_QP_STATE_SQD: + return IB_QPS_SQD; + case QED_ROCE_QP_STATE_ERR: + return IB_QPS_ERR; + case QED_ROCE_QP_STATE_SQE: + return IB_QPS_SQE; + } + return IB_QPS_ERR; +} + +enum qed_roce_qp_state qedr_get_state_from_ibqp(enum ib_qp_state qp_state) +{ + switch (qp_state) { + case IB_QPS_RESET: + return QED_ROCE_QP_STATE_RESET; + case IB_QPS_INIT: + return QED_ROCE_QP_STATE_INIT; + case IB_QPS_RTR: + return QED_ROCE_QP_STATE_RTR; + case IB_QPS_RTS: + return QED_ROCE_QP_STATE_RTS; + case IB_QPS_SQD: + return QED_ROCE_QP_STATE_SQD; + case IB_QPS_ERR: + return QED_ROCE_QP_STATE_ERR; + default: + return QED_ROCE_QP_STATE_ERR; + } +} + +static void qedr_reset_qp_hwq_info(struct qedr_qp_hwq_info *qph) +{ + qed_chain_reset(&qph->pbl); + qph->prod = 0; + qph->cons = 0; + qph->wqe_cons = 0; + qph->db_data.data.value = cpu_to_le16(0); +} + +static int qedr_update_qp_state(struct qedr_dev *dev, + struct qedr_qp *qp, + enum qed_roce_qp_state new_state) +{ + int status = 0; + + if (new_state == qp->state) + return 1; + + switch (qp->state) { + case QED_ROCE_QP_STATE_RESET: + switch (new_state) { + case QED_ROCE_QP_STATE_INIT: + qp->prev_wqe_size = 0; + qedr_reset_qp_hwq_info(&qp->sq); + qedr_reset_qp_hwq_info(&qp->rq); + break; + default: + status = -EINVAL; + break; + }; + break; + case QED_ROCE_QP_STATE_INIT: + switch (new_state) { + case QED_ROCE_QP_STATE_RTR: + /* Update doorbell (in case post_recv was + * done before move to RTR) + */ + wmb(); + writel(qp->rq.db_data.raw, qp->rq.db); + /* Make sure write takes effect */ + mmiowb(); + break; + case QED_ROCE_QP_STATE_ERR: + break; + default: + /* Invalid state change. */ + status = -EINVAL; + break; + }; + break; + case QED_ROCE_QP_STATE_RTR: + /* RTR->XXX */ + switch (new_state) { + case QED_ROCE_QP_STATE_RTS: + break; + case QED_ROCE_QP_STATE_ERR: + break; + default: + /* Invalid state change. */ + status = -EINVAL; + break; + }; + break; + case QED_ROCE_QP_STATE_RTS: + /* RTS->XXX */ + switch (new_state) { + case QED_ROCE_QP_STATE_SQD: + break; + case QED_ROCE_QP_STATE_ERR: + break; + default: + /* Invalid state change. */ + status = -EINVAL; + break; + }; + break; + case QED_ROCE_QP_STATE_SQD: + /* SQD->XXX */ + switch (new_state) { + case QED_ROCE_QP_STATE_RTS: + case QED_ROCE_QP_STATE_ERR: + break; + default: + /* Invalid state change. */ + status = -EINVAL; + break; + }; + break; + case QED_ROCE_QP_STATE_ERR: + /* ERR->XXX */ + switch (new_state) { + case QED_ROCE_QP_STATE_RESET: + break; + default: + status = -EINVAL; + break; + }; + break; + default: + status = -EINVAL; + break; + }; + + return status; +} + +int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata) +{ + struct qedr_qp *qp = get_qedr_qp(ibqp); + struct qed_rdma_modify_qp_in_params qp_params = { 0 }; + struct qedr_dev *dev = get_qedr_dev(&qp->dev->ibdev); + enum ib_qp_state old_qp_state, new_qp_state; + int rc = 0; + + DP_DEBUG(dev, QEDR_MSG_QP, + "modify qp: qp %p attr_mask=0x%x, state=%d", qp, attr_mask, + attr->qp_state); + + old_qp_state = qedr_get_ibqp_state(qp->state); + if (attr_mask & IB_QP_STATE) + new_qp_state = attr->qp_state; + else + new_qp_state = old_qp_state; + + if (!ib_modify_qp_is_ok + (old_qp_state, new_qp_state, ibqp->qp_type, attr_mask, + IB_LINK_LAYER_ETHERNET)) { + DP_ERR(dev, + "modify qp: invalid attribute mask=0x%x specified for\n" + "qpn=0x%x of type=0x%x old_qp_state=0x%x, new_qp_state=0x%x\n", + attr_mask, qp->qp_id, ibqp->qp_type, old_qp_state, + new_qp_state); + rc = -EINVAL; + goto err; + } + + /* Translate the masks... */ + if (attr_mask & IB_QP_STATE) { + SET_FIELD(qp_params.modify_flags, + QED_RDMA_MODIFY_QP_VALID_NEW_STATE, 1); + qp_params.new_state = qedr_get_state_from_ibqp(attr->qp_state); + } + + if (attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) + qp_params.sqd_async = true; + + if (attr_mask & IB_QP_PKEY_INDEX) { + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_PKEY, 1); + if (attr->pkey_index >= QEDR_ROCE_PKEY_TABLE_LEN) { + rc = -EINVAL; + goto err; + } + + qp_params.pkey = QEDR_ROCE_PKEY_DEFAULT; + } + + if (attr_mask & IB_QP_QKEY) + qp->qkey = attr->qkey; + + if (attr_mask & IB_QP_ACCESS_FLAGS) { + SET_FIELD(qp_params.modify_flags, + QED_RDMA_MODIFY_QP_VALID_RDMA_OPS_EN, 1); + qp_params.incoming_rdma_read_en = attr->qp_access_flags & + IB_ACCESS_REMOTE_READ; + qp_params.incoming_rdma_write_en = attr->qp_access_flags & + IB_ACCESS_REMOTE_WRITE; + qp_params.incoming_atomic_en = attr->qp_access_flags & + IB_ACCESS_REMOTE_ATOMIC; + } + + if (attr_mask & (IB_QP_AV | IB_QP_PATH_MTU)) { + if (attr_mask & IB_QP_PATH_MTU) { + if (attr->path_mtu < IB_MTU_256 || + attr->path_mtu > IB_MTU_4096) { + pr_err("error: Only MTU sizes of 256, 512, 1024, 2048 and 4096 are supported by RoCE\n"); + rc = -EINVAL; + goto err; + } + qp->mtu = min(ib_mtu_enum_to_int(attr->path_mtu), + ib_mtu_enum_to_int(iboe_get_mtu + (dev->ndev->mtu))); + } + + if (!qp->mtu) { + qp->mtu = + ib_mtu_enum_to_int(iboe_get_mtu(dev->ndev->mtu)); + pr_err("Fixing zeroed MTU to qp->mtu = %d\n", qp->mtu); + } + + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_ADDRESS_VECTOR, 1); + + qp_params.traffic_class_tos = attr->ah_attr.grh.traffic_class; + qp_params.flow_label = attr->ah_attr.grh.flow_label; + qp_params.hop_limit_ttl = attr->ah_attr.grh.hop_limit; + + qp->sgid_idx = attr->ah_attr.grh.sgid_index; + + rc = get_gid_info_from_table(ibqp, attr, attr_mask, &qp_params); + if (rc) { + DP_ERR(dev, + "modify qp: problems with GID index %d (rc=%d)\n", + attr->ah_attr.grh.sgid_index, rc); + return rc; + } + + rc = qedr_get_dmac(dev, &attr->ah_attr, + qp_params.remote_mac_addr); + if (rc) + return rc; + + qp_params.use_local_mac = true; + ether_addr_copy(qp_params.local_mac_addr, dev->ndev->dev_addr); + + DP_DEBUG(dev, QEDR_MSG_QP, "dgid=%x:%x:%x:%x\n", + qp_params.dgid.dwords[0], qp_params.dgid.dwords[1], + qp_params.dgid.dwords[2], qp_params.dgid.dwords[3]); + DP_DEBUG(dev, QEDR_MSG_QP, "sgid=%x:%x:%x:%x\n", + qp_params.sgid.dwords[0], qp_params.sgid.dwords[1], + qp_params.sgid.dwords[2], qp_params.sgid.dwords[3]); + DP_DEBUG(dev, QEDR_MSG_QP, "remote_mac=[%pM]\n", + qp_params.remote_mac_addr); +; + + qp_params.mtu = qp->mtu; + qp_params.lb_indication = false; + } + + if (!qp_params.mtu) { + /* Stay with current MTU */ + if (qp->mtu) + qp_params.mtu = qp->mtu; + else + qp_params.mtu = + ib_mtu_enum_to_int(iboe_get_mtu(dev->ndev->mtu)); + } + + if (attr_mask & IB_QP_TIMEOUT) { + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT, 1); + + qp_params.ack_timeout = attr->timeout; + if (attr->timeout) { + u32 temp; + + temp = 4096 * (1UL << attr->timeout) / 1000 / 1000; + /* FW requires [msec] */ + qp_params.ack_timeout = temp; + } else { + /* Infinite */ + qp_params.ack_timeout = 0; + } + } + if (attr_mask & IB_QP_RETRY_CNT) { + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_RETRY_CNT, 1); + qp_params.retry_cnt = attr->retry_cnt; + } + + if (attr_mask & IB_QP_RNR_RETRY) { + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_RNR_RETRY_CNT, 1); + qp_params.rnr_retry_cnt = attr->rnr_retry; + } + + if (attr_mask & IB_QP_RQ_PSN) { + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_RQ_PSN, 1); + qp_params.rq_psn = attr->rq_psn; + qp->rq_psn = attr->rq_psn; + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { + if (attr->max_rd_atomic > dev->attr.max_qp_req_rd_atomic_resc) { + rc = -EINVAL; + DP_ERR(dev, + "unsupported max_rd_atomic=%d, supported=%d\n", + attr->max_rd_atomic, + dev->attr.max_qp_req_rd_atomic_resc); + goto err; + } + + SET_FIELD(qp_params.modify_flags, + QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_REQ, 1); + qp_params.max_rd_atomic_req = attr->max_rd_atomic; + } + + if (attr_mask & IB_QP_MIN_RNR_TIMER) { + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_MIN_RNR_NAK_TIMER, 1); + qp_params.min_rnr_nak_timer = attr->min_rnr_timer; + } + + if (attr_mask & IB_QP_SQ_PSN) { + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_SQ_PSN, 1); + qp_params.sq_psn = attr->sq_psn; + qp->sq_psn = attr->sq_psn; + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { + if (attr->max_dest_rd_atomic > + dev->attr.max_qp_resp_rd_atomic_resc) { + DP_ERR(dev, + "unsupported max_dest_rd_atomic=%d, supported=%d\n", + attr->max_dest_rd_atomic, + dev->attr.max_qp_resp_rd_atomic_resc); + + rc = -EINVAL; + goto err; + } + + SET_FIELD(qp_params.modify_flags, + QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_RESP, 1); + qp_params.max_rd_atomic_resp = attr->max_dest_rd_atomic; + } + + if (attr_mask & IB_QP_DEST_QPN) { + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_DEST_QP, 1); + + qp_params.dest_qp = attr->dest_qp_num; + qp->dest_qp_num = attr->dest_qp_num; + } + + if (qp->qp_type != IB_QPT_GSI) + rc = dev->ops->rdma_modify_qp(dev->rdma_ctx, + qp->qed_qp, &qp_params); + + if (attr_mask & IB_QP_STATE) { + if ((qp->qp_type != IB_QPT_GSI) && (!udata)) + qedr_update_qp_state(dev, qp, qp_params.new_state); + qp->state = qp_params.new_state; + } + +err: + return rc; +} + +static int qedr_to_ib_qp_acc_flags(struct qed_rdma_query_qp_out_params *params) +{ + int ib_qp_acc_flags = 0; + + if (params->incoming_rdma_write_en) + ib_qp_acc_flags |= IB_ACCESS_REMOTE_WRITE; + if (params->incoming_rdma_read_en) + ib_qp_acc_flags |= IB_ACCESS_REMOTE_READ; + if (params->incoming_atomic_en) + ib_qp_acc_flags |= IB_ACCESS_REMOTE_ATOMIC; + ib_qp_acc_flags |= IB_ACCESS_LOCAL_WRITE; + return ib_qp_acc_flags; +} + +int qedr_query_qp(struct ib_qp *ibqp, + struct ib_qp_attr *qp_attr, + int attr_mask, struct ib_qp_init_attr *qp_init_attr) +{ + struct qed_rdma_query_qp_out_params params; + struct qedr_qp *qp = get_qedr_qp(ibqp); + struct qedr_dev *dev = qp->dev; + int rc = 0; + + memset(¶ms, 0, sizeof(params)); + + rc = dev->ops->rdma_query_qp(dev->rdma_ctx, qp->qed_qp, ¶ms); + if (rc) + goto err; + + memset(qp_attr, 0, sizeof(*qp_attr)); + memset(qp_init_attr, 0, sizeof(*qp_init_attr)); + + qp_attr->qp_state = qedr_get_ibqp_state(params.state); + qp_attr->cur_qp_state = qedr_get_ibqp_state(params.state); + qp_attr->path_mtu = iboe_get_mtu(params.mtu); + qp_attr->path_mig_state = IB_MIG_MIGRATED; + qp_attr->rq_psn = params.rq_psn; + qp_attr->sq_psn = params.sq_psn; + qp_attr->dest_qp_num = params.dest_qp; + + qp_attr->qp_access_flags = qedr_to_ib_qp_acc_flags(¶ms); + + qp_attr->cap.max_send_wr = qp->sq.max_wr; + qp_attr->cap.max_recv_wr = qp->rq.max_wr; + qp_attr->cap.max_send_sge = qp->sq.max_sges; + qp_attr->cap.max_recv_sge = qp->rq.max_sges; + qp_attr->cap.max_inline_data = qp->max_inline_data; + qp_init_attr->cap = qp_attr->cap; + + memcpy(&qp_attr->ah_attr.grh.dgid.raw[0], ¶ms.dgid.bytes[0], + sizeof(qp_attr->ah_attr.grh.dgid.raw)); + + qp_attr->ah_attr.grh.flow_label = params.flow_label; + qp_attr->ah_attr.grh.sgid_index = qp->sgid_idx; + qp_attr->ah_attr.grh.hop_limit = params.hop_limit_ttl; + qp_attr->ah_attr.grh.traffic_class = params.traffic_class_tos; + + qp_attr->ah_attr.ah_flags = IB_AH_GRH; + qp_attr->ah_attr.port_num = 1; + qp_attr->ah_attr.sl = 0; + qp_attr->timeout = params.timeout; + qp_attr->rnr_retry = params.rnr_retry; + qp_attr->retry_cnt = params.retry_cnt; + qp_attr->min_rnr_timer = params.min_rnr_nak_timer; + qp_attr->pkey_index = params.pkey_index; + qp_attr->port_num = 1; + qp_attr->ah_attr.src_path_bits = 0; + qp_attr->ah_attr.static_rate = 0; + qp_attr->alt_pkey_index = 0; + qp_attr->alt_port_num = 0; + qp_attr->alt_timeout = 0; + memset(&qp_attr->alt_ah_attr, 0, sizeof(qp_attr->alt_ah_attr)); + + qp_attr->sq_draining = (params.state == QED_ROCE_QP_STATE_SQD) ? 1 : 0; + qp_attr->max_dest_rd_atomic = params.max_dest_rd_atomic; + qp_attr->max_rd_atomic = params.max_rd_atomic; + qp_attr->en_sqd_async_notify = (params.sqd_async) ? 1 : 0; + + DP_DEBUG(dev, QEDR_MSG_QP, "QEDR_QUERY_QP: max_inline_data=%d\n", + qp_attr->cap.max_inline_data); + +err: + return rc; +} + +int qedr_destroy_qp(struct ib_qp *ibqp) +{ + struct qedr_qp *qp = get_qedr_qp(ibqp); + struct qedr_dev *dev = qp->dev; + struct ib_qp_attr attr; + int attr_mask = 0; + int rc = 0; + + DP_DEBUG(dev, QEDR_MSG_QP, "destroy qp: destroying %p, qp type=%d\n", + qp, qp->qp_type); + + if (qp->state != (QED_ROCE_QP_STATE_RESET | QED_ROCE_QP_STATE_ERR | + QED_ROCE_QP_STATE_INIT)) { + attr.qp_state = IB_QPS_ERR; + attr_mask |= IB_QP_STATE; + + /* Change the QP state to ERROR */ + qedr_modify_qp(ibqp, &attr, attr_mask, NULL); + } + + if (qp->qp_type != IB_QPT_GSI) { + rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp); + if (rc) + return rc; + } + + if (ibqp->uobject && ibqp->uobject->context) { + qedr_cleanup_user_sq(dev, qp); + qedr_cleanup_user_rq(dev, qp); + } else { + qedr_cleanup_kernel_sq(dev, qp); + qedr_cleanup_kernel_rq(dev, qp); + } + + kfree(qp); + + return rc; +} diff --git a/drivers/infiniband/hw/qedr/verbs.h b/drivers/infiniband/hw/qedr/verbs.h index 36c8a692f740a..056d6cb31fa2c 100644 --- a/drivers/infiniband/hw/qedr/verbs.h +++ b/drivers/infiniband/hw/qedr/verbs.h @@ -62,5 +62,12 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, int qedr_resize_cq(struct ib_cq *, int cqe, struct ib_udata *); int qedr_destroy_cq(struct ib_cq *); int qedr_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags); +struct ib_qp *qedr_create_qp(struct ib_pd *, struct ib_qp_init_attr *attrs, + struct ib_udata *); +int qedr_modify_qp(struct ib_qp *, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata); +int qedr_query_qp(struct ib_qp *, struct ib_qp_attr *qp_attr, + int qp_attr_mask, struct ib_qp_init_attr *); +int qedr_destroy_qp(struct ib_qp *ibqp); #endif diff --git a/include/uapi/rdma/qedr-abi.h b/include/uapi/rdma/qedr-abi.h index b0fc5f2125e02..75c270d839c8d 100644 --- a/include/uapi/rdma/qedr-abi.h +++ b/include/uapi/rdma/qedr-abi.h @@ -69,4 +69,38 @@ struct qedr_create_cq_uresp { __u16 icid; }; +struct qedr_create_qp_ureq { + __u32 qp_handle_hi; + __u32 qp_handle_lo; + + /* SQ */ + /* user space virtual address of SQ buffer */ + __u64 sq_addr; + + /* length of SQ buffer */ + __u64 sq_len; + + /* RQ */ + /* user space virtual address of RQ buffer */ + __u64 rq_addr; + + /* length of RQ buffer */ + __u64 rq_len; +}; + +struct qedr_create_qp_uresp { + __u32 qp_id; + __u32 atomic_supported; + + /* SQ */ + __u32 sq_db_offset; + __u16 sq_icid; + + /* RQ */ + __u32 rq_db_offset; + __u16 rq_icid; + + __u32 rq_db2_offset; +}; + #endif /* __QEDR_USER_H__ */ -- GitLab From e0290cce6ac02f8e5ec501f25f6f6900f384550c Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 10 Oct 2016 13:15:35 +0300 Subject: [PATCH 0566/1167] qedr: Add support for memory registeration verbs Add support for user, dma and memory regions registration. Signed-off-by: Rajesh Borundia Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/main.c | 10 +- drivers/infiniband/hw/qedr/qedr.h | 40 ++++ drivers/infiniband/hw/qedr/verbs.c | 365 +++++++++++++++++++++++++++++ drivers/infiniband/hw/qedr/verbs.h | 11 + 4 files changed, 425 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 13ba47b7b99fd..bfc287c7d72ea 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -100,7 +100,9 @@ static int qedr_register_device(struct qedr_dev *dev) QEDR_UVERBS(CREATE_QP) | QEDR_UVERBS(MODIFY_QP) | QEDR_UVERBS(QUERY_QP) | - QEDR_UVERBS(DESTROY_QP); + QEDR_UVERBS(DESTROY_QP) | + QEDR_UVERBS(REG_MR) | + QEDR_UVERBS(DEREG_MR); dev->ibdev.phys_port_cnt = 1; dev->ibdev.num_comp_vectors = dev->num_cnq; @@ -133,6 +135,12 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.query_pkey = qedr_query_pkey; + dev->ibdev.get_dma_mr = qedr_get_dma_mr; + dev->ibdev.dereg_mr = qedr_dereg_mr; + dev->ibdev.reg_user_mr = qedr_reg_user_mr; + dev->ibdev.alloc_mr = qedr_alloc_mr; + dev->ibdev.map_mr_sg = qedr_map_mr_sg; + dev->ibdev.dma_device = &dev->pdev->dev; dev->ibdev.get_link_layer = qedr_link_layer; diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index e9fe941c48ad7..6559556979955 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -375,6 +375,41 @@ struct qedr_qp { struct qedr_userq urq; }; +struct qedr_ah { + struct ib_ah ibah; + struct ib_ah_attr attr; +}; + +enum qedr_mr_type { + QEDR_MR_USER, + QEDR_MR_KERNEL, + QEDR_MR_DMA, + QEDR_MR_FRMR, +}; + +struct mr_info { + struct qedr_pbl *pbl_table; + struct qedr_pbl_info pbl_info; + struct list_head free_pbl_list; + struct list_head inuse_pbl_list; + u32 completed; + u32 completed_handled; +}; + +struct qedr_mr { + struct ib_mr ibmr; + struct ib_umem *umem; + + struct qed_rdma_register_tid_in_params hw_mr; + enum qedr_mr_type type; + + struct qedr_dev *dev; + struct mr_info info; + + u64 *pages; + u32 npages; +}; + static inline int qedr_get_dmac(struct qedr_dev *dev, struct ib_ah_attr *ah_attr, u8 *mac_addr) { @@ -418,4 +453,9 @@ static inline struct qedr_qp *get_qedr_qp(struct ib_qp *ibqp) { return container_of(ibqp, struct qedr_qp, ibqp); } + +static inline struct qedr_mr *get_qedr_mr(struct ib_mr *ibmr) +{ + return container_of(ibmr, struct qedr_mr, ibmr); +} #endif diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index a0d1c5fffb632..e70e808e2b9b3 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -2082,3 +2082,368 @@ int qedr_destroy_qp(struct ib_qp *ibqp) return rc; } + +static void free_mr_info(struct qedr_dev *dev, struct mr_info *info) +{ + struct qedr_pbl *pbl, *tmp; + + if (info->pbl_table) + list_add_tail(&info->pbl_table->list_entry, + &info->free_pbl_list); + + if (!list_empty(&info->inuse_pbl_list)) + list_splice(&info->inuse_pbl_list, &info->free_pbl_list); + + list_for_each_entry_safe(pbl, tmp, &info->free_pbl_list, list_entry) { + list_del(&pbl->list_entry); + qedr_free_pbl(dev, &info->pbl_info, pbl); + } +} + +static int init_mr_info(struct qedr_dev *dev, struct mr_info *info, + size_t page_list_len, bool two_layered) +{ + struct qedr_pbl *tmp; + int rc; + + INIT_LIST_HEAD(&info->free_pbl_list); + INIT_LIST_HEAD(&info->inuse_pbl_list); + + rc = qedr_prepare_pbl_tbl(dev, &info->pbl_info, + page_list_len, two_layered); + if (rc) + goto done; + + info->pbl_table = qedr_alloc_pbl_tbl(dev, &info->pbl_info, GFP_KERNEL); + if (!info->pbl_table) { + rc = -ENOMEM; + goto done; + } + + DP_DEBUG(dev, QEDR_MSG_MR, "pbl_table_pa = %pa\n", + &info->pbl_table->pa); + + /* in usual case we use 2 PBLs, so we add one to free + * list and allocating another one + */ + tmp = qedr_alloc_pbl_tbl(dev, &info->pbl_info, GFP_KERNEL); + if (!tmp) { + DP_DEBUG(dev, QEDR_MSG_MR, "Extra PBL is not allocated\n"); + goto done; + } + + list_add_tail(&tmp->list_entry, &info->free_pbl_list); + + DP_DEBUG(dev, QEDR_MSG_MR, "extra pbl_table_pa = %pa\n", &tmp->pa); + +done: + if (rc) + free_mr_info(dev, info); + + return rc; +} + +struct ib_mr *qedr_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 len, + u64 usr_addr, int acc, struct ib_udata *udata) +{ + struct qedr_dev *dev = get_qedr_dev(ibpd->device); + struct qedr_mr *mr; + struct qedr_pd *pd; + int rc = -ENOMEM; + + pd = get_qedr_pd(ibpd); + DP_DEBUG(dev, QEDR_MSG_MR, + "qedr_register user mr pd = %d start = %lld, len = %lld, usr_addr = %lld, acc = %d\n", + pd->pd_id, start, len, usr_addr, acc); + + if (acc & IB_ACCESS_REMOTE_WRITE && !(acc & IB_ACCESS_LOCAL_WRITE)) + return ERR_PTR(-EINVAL); + + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) + return ERR_PTR(rc); + + mr->type = QEDR_MR_USER; + + mr->umem = ib_umem_get(ibpd->uobject->context, start, len, acc, 0); + if (IS_ERR(mr->umem)) { + rc = -EFAULT; + goto err0; + } + + rc = init_mr_info(dev, &mr->info, ib_umem_page_count(mr->umem), 1); + if (rc) + goto err1; + + qedr_populate_pbls(dev, mr->umem, mr->info.pbl_table, + &mr->info.pbl_info); + + rc = dev->ops->rdma_alloc_tid(dev->rdma_ctx, &mr->hw_mr.itid); + if (rc) { + DP_ERR(dev, "roce alloc tid returned an error %d\n", rc); + goto err1; + } + + /* Index only, 18 bit long, lkey = itid << 8 | key */ + mr->hw_mr.tid_type = QED_RDMA_TID_REGISTERED_MR; + mr->hw_mr.key = 0; + mr->hw_mr.pd = pd->pd_id; + mr->hw_mr.local_read = 1; + mr->hw_mr.local_write = (acc & IB_ACCESS_LOCAL_WRITE) ? 1 : 0; + mr->hw_mr.remote_read = (acc & IB_ACCESS_REMOTE_READ) ? 1 : 0; + mr->hw_mr.remote_write = (acc & IB_ACCESS_REMOTE_WRITE) ? 1 : 0; + mr->hw_mr.remote_atomic = (acc & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0; + mr->hw_mr.mw_bind = false; + mr->hw_mr.pbl_ptr = mr->info.pbl_table[0].pa; + mr->hw_mr.pbl_two_level = mr->info.pbl_info.two_layered; + mr->hw_mr.pbl_page_size_log = ilog2(mr->info.pbl_info.pbl_size); + mr->hw_mr.page_size_log = ilog2(mr->umem->page_size); + mr->hw_mr.fbo = ib_umem_offset(mr->umem); + mr->hw_mr.length = len; + mr->hw_mr.vaddr = usr_addr; + mr->hw_mr.zbva = false; + mr->hw_mr.phy_mr = false; + mr->hw_mr.dma_mr = false; + + rc = dev->ops->rdma_register_tid(dev->rdma_ctx, &mr->hw_mr); + if (rc) { + DP_ERR(dev, "roce register tid returned an error %d\n", rc); + goto err2; + } + + mr->ibmr.lkey = mr->hw_mr.itid << 8 | mr->hw_mr.key; + if (mr->hw_mr.remote_write || mr->hw_mr.remote_read || + mr->hw_mr.remote_atomic) + mr->ibmr.rkey = mr->hw_mr.itid << 8 | mr->hw_mr.key; + + DP_DEBUG(dev, QEDR_MSG_MR, "register user mr lkey: %x\n", + mr->ibmr.lkey); + return &mr->ibmr; + +err2: + dev->ops->rdma_free_tid(dev->rdma_ctx, mr->hw_mr.itid); +err1: + qedr_free_pbl(dev, &mr->info.pbl_info, mr->info.pbl_table); +err0: + kfree(mr); + return ERR_PTR(rc); +} + +int qedr_dereg_mr(struct ib_mr *ib_mr) +{ + struct qedr_mr *mr = get_qedr_mr(ib_mr); + struct qedr_dev *dev = get_qedr_dev(ib_mr->device); + int rc = 0; + + rc = dev->ops->rdma_deregister_tid(dev->rdma_ctx, mr->hw_mr.itid); + if (rc) + return rc; + + dev->ops->rdma_free_tid(dev->rdma_ctx, mr->hw_mr.itid); + + if ((mr->type != QEDR_MR_DMA) && (mr->type != QEDR_MR_FRMR)) + qedr_free_pbl(dev, &mr->info.pbl_info, mr->info.pbl_table); + + /* it could be user registered memory. */ + if (mr->umem) + ib_umem_release(mr->umem); + + kfree(mr); + + return rc; +} + +struct qedr_mr *__qedr_alloc_mr(struct ib_pd *ibpd, int max_page_list_len) +{ + struct qedr_pd *pd = get_qedr_pd(ibpd); + struct qedr_dev *dev = get_qedr_dev(ibpd->device); + struct qedr_mr *mr; + int rc = -ENOMEM; + + DP_DEBUG(dev, QEDR_MSG_MR, + "qedr_alloc_frmr pd = %d max_page_list_len= %d\n", pd->pd_id, + max_page_list_len); + + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) + return ERR_PTR(rc); + + mr->dev = dev; + mr->type = QEDR_MR_FRMR; + + rc = init_mr_info(dev, &mr->info, max_page_list_len, 1); + if (rc) + goto err0; + + rc = dev->ops->rdma_alloc_tid(dev->rdma_ctx, &mr->hw_mr.itid); + if (rc) { + DP_ERR(dev, "roce alloc tid returned an error %d\n", rc); + goto err0; + } + + /* Index only, 18 bit long, lkey = itid << 8 | key */ + mr->hw_mr.tid_type = QED_RDMA_TID_FMR; + mr->hw_mr.key = 0; + mr->hw_mr.pd = pd->pd_id; + mr->hw_mr.local_read = 1; + mr->hw_mr.local_write = 0; + mr->hw_mr.remote_read = 0; + mr->hw_mr.remote_write = 0; + mr->hw_mr.remote_atomic = 0; + mr->hw_mr.mw_bind = false; + mr->hw_mr.pbl_ptr = 0; + mr->hw_mr.pbl_two_level = mr->info.pbl_info.two_layered; + mr->hw_mr.pbl_page_size_log = ilog2(mr->info.pbl_info.pbl_size); + mr->hw_mr.fbo = 0; + mr->hw_mr.length = 0; + mr->hw_mr.vaddr = 0; + mr->hw_mr.zbva = false; + mr->hw_mr.phy_mr = true; + mr->hw_mr.dma_mr = false; + + rc = dev->ops->rdma_register_tid(dev->rdma_ctx, &mr->hw_mr); + if (rc) { + DP_ERR(dev, "roce register tid returned an error %d\n", rc); + goto err1; + } + + mr->ibmr.lkey = mr->hw_mr.itid << 8 | mr->hw_mr.key; + mr->ibmr.rkey = mr->ibmr.lkey; + + DP_DEBUG(dev, QEDR_MSG_MR, "alloc frmr: %x\n", mr->ibmr.lkey); + return mr; + +err1: + dev->ops->rdma_free_tid(dev->rdma_ctx, mr->hw_mr.itid); +err0: + kfree(mr); + return ERR_PTR(rc); +} + +struct ib_mr *qedr_alloc_mr(struct ib_pd *ibpd, + enum ib_mr_type mr_type, u32 max_num_sg) +{ + struct qedr_dev *dev; + struct qedr_mr *mr; + + if (mr_type != IB_MR_TYPE_MEM_REG) + return ERR_PTR(-EINVAL); + + mr = __qedr_alloc_mr(ibpd, max_num_sg); + + if (IS_ERR(mr)) + return ERR_PTR(-EINVAL); + + dev = mr->dev; + + return &mr->ibmr; +} + +static int qedr_set_page(struct ib_mr *ibmr, u64 addr) +{ + struct qedr_mr *mr = get_qedr_mr(ibmr); + struct qedr_pbl *pbl_table; + struct regpair *pbe; + u32 pbes_in_page; + + if (unlikely(mr->npages == mr->info.pbl_info.num_pbes)) { + DP_ERR(mr->dev, "qedr_set_page failes when %d\n", mr->npages); + return -ENOMEM; + } + + DP_DEBUG(mr->dev, QEDR_MSG_MR, "qedr_set_page pages[%d] = 0x%llx\n", + mr->npages, addr); + + pbes_in_page = mr->info.pbl_info.pbl_size / sizeof(u64); + pbl_table = mr->info.pbl_table + (mr->npages / pbes_in_page); + pbe = (struct regpair *)pbl_table->va; + pbe += mr->npages % pbes_in_page; + pbe->lo = cpu_to_le32((u32)addr); + pbe->hi = cpu_to_le32((u32)upper_32_bits(addr)); + + mr->npages++; + + return 0; +} + +static void handle_completed_mrs(struct qedr_dev *dev, struct mr_info *info) +{ + int work = info->completed - info->completed_handled - 1; + + DP_DEBUG(dev, QEDR_MSG_MR, "Special FMR work = %d\n", work); + while (work-- > 0 && !list_empty(&info->inuse_pbl_list)) { + struct qedr_pbl *pbl; + + /* Free all the page list that are possible to be freed + * (all the ones that were invalidated), under the assumption + * that if an FMR was completed successfully that means that + * if there was an invalidate operation before it also ended + */ + pbl = list_first_entry(&info->inuse_pbl_list, + struct qedr_pbl, list_entry); + list_del(&pbl->list_entry); + list_add_tail(&pbl->list_entry, &info->free_pbl_list); + info->completed_handled++; + } +} + +int qedr_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, + int sg_nents, unsigned int *sg_offset) +{ + struct qedr_mr *mr = get_qedr_mr(ibmr); + + mr->npages = 0; + + handle_completed_mrs(mr->dev, &mr->info); + return ib_sg_to_pages(ibmr, sg, sg_nents, NULL, qedr_set_page); +} + +struct ib_mr *qedr_get_dma_mr(struct ib_pd *ibpd, int acc) +{ + struct qedr_dev *dev = get_qedr_dev(ibpd->device); + struct qedr_pd *pd = get_qedr_pd(ibpd); + struct qedr_mr *mr; + int rc; + + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + mr->type = QEDR_MR_DMA; + + rc = dev->ops->rdma_alloc_tid(dev->rdma_ctx, &mr->hw_mr.itid); + if (rc) { + DP_ERR(dev, "roce alloc tid returned an error %d\n", rc); + goto err1; + } + + /* index only, 18 bit long, lkey = itid << 8 | key */ + mr->hw_mr.tid_type = QED_RDMA_TID_REGISTERED_MR; + mr->hw_mr.pd = pd->pd_id; + mr->hw_mr.local_read = 1; + mr->hw_mr.local_write = (acc & IB_ACCESS_LOCAL_WRITE) ? 1 : 0; + mr->hw_mr.remote_read = (acc & IB_ACCESS_REMOTE_READ) ? 1 : 0; + mr->hw_mr.remote_write = (acc & IB_ACCESS_REMOTE_WRITE) ? 1 : 0; + mr->hw_mr.remote_atomic = (acc & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0; + mr->hw_mr.dma_mr = true; + + rc = dev->ops->rdma_register_tid(dev->rdma_ctx, &mr->hw_mr); + if (rc) { + DP_ERR(dev, "roce register tid returned an error %d\n", rc); + goto err2; + } + + mr->ibmr.lkey = mr->hw_mr.itid << 8 | mr->hw_mr.key; + if (mr->hw_mr.remote_write || mr->hw_mr.remote_read || + mr->hw_mr.remote_atomic) + mr->ibmr.rkey = mr->hw_mr.itid << 8 | mr->hw_mr.key; + + DP_DEBUG(dev, QEDR_MSG_MR, "get dma mr: lkey = %x\n", mr->ibmr.lkey); + return &mr->ibmr; + +err2: + dev->ops->rdma_free_tid(dev->rdma_ctx, mr->hw_mr.itid); +err1: + kfree(mr); + return ERR_PTR(rc); +} diff --git a/drivers/infiniband/hw/qedr/verbs.h b/drivers/infiniband/hw/qedr/verbs.h index 056d6cb31fa2c..4853f4af99837 100644 --- a/drivers/infiniband/hw/qedr/verbs.h +++ b/drivers/infiniband/hw/qedr/verbs.h @@ -70,4 +70,15 @@ int qedr_query_qp(struct ib_qp *, struct ib_qp_attr *qp_attr, int qp_attr_mask, struct ib_qp_init_attr *); int qedr_destroy_qp(struct ib_qp *ibqp); +int qedr_dereg_mr(struct ib_mr *); +struct ib_mr *qedr_get_dma_mr(struct ib_pd *, int acc); + +struct ib_mr *qedr_reg_user_mr(struct ib_pd *, u64 start, u64 length, + u64 virt, int acc, struct ib_udata *); + +int qedr_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, + int sg_nents, unsigned int *sg_offset); + +struct ib_mr *qedr_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, + u32 max_num_sg); #endif -- GitLab From afa0e13be754307a9ed7ad31fe42b5ec97948c49 Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 10 Oct 2016 13:15:36 +0300 Subject: [PATCH 0567/1167] qedr: Add support for data path Implement fastpath verbs like ib_send_post, ib_post_recv and ib_poll_cq. Signed-off-by: Rajesh Borundia Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/main.c | 9 +- drivers/infiniband/hw/qedr/qedr.h | 19 + drivers/infiniband/hw/qedr/qedr_hsi_rdma.h | 562 +++++++++++ drivers/infiniband/hw/qedr/verbs.c | 1020 ++++++++++++++++++++ drivers/infiniband/hw/qedr/verbs.h | 5 + 5 files changed, 1614 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index bfc287c7d72ea..858cc354153dd 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -102,7 +102,10 @@ static int qedr_register_device(struct qedr_dev *dev) QEDR_UVERBS(QUERY_QP) | QEDR_UVERBS(DESTROY_QP) | QEDR_UVERBS(REG_MR) | - QEDR_UVERBS(DEREG_MR); + QEDR_UVERBS(DEREG_MR) | + QEDR_UVERBS(POLL_CQ) | + QEDR_UVERBS(POST_SEND) | + QEDR_UVERBS(POST_RECV); dev->ibdev.phys_port_cnt = 1; dev->ibdev.num_comp_vectors = dev->num_cnq; @@ -141,6 +144,10 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.alloc_mr = qedr_alloc_mr; dev->ibdev.map_mr_sg = qedr_map_mr_sg; + dev->ibdev.poll_cq = qedr_poll_cq; + dev->ibdev.post_send = qedr_post_send; + dev->ibdev.post_recv = qedr_post_recv; + dev->ibdev.dma_device = &dev->pdev->dev; dev->ibdev.get_link_layer = qedr_link_layer; diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 6559556979955..775dbf16fdf28 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -410,6 +410,25 @@ struct qedr_mr { u32 npages; }; +#define SET_FIELD2(value, name, flag) ((value) |= ((flag) << (name ## _SHIFT))) + +#define QEDR_RESP_IMM (RDMA_CQE_RESPONDER_IMM_FLG_MASK << \ + RDMA_CQE_RESPONDER_IMM_FLG_SHIFT) +#define QEDR_RESP_RDMA (RDMA_CQE_RESPONDER_RDMA_FLG_MASK << \ + RDMA_CQE_RESPONDER_RDMA_FLG_SHIFT) +#define QEDR_RESP_RDMA_IMM (QEDR_RESP_IMM | QEDR_RESP_RDMA) + +static inline void qedr_inc_sw_cons(struct qedr_qp_hwq_info *info) +{ + info->cons = (info->cons + 1) % info->max_wr; + info->wqe_cons++; +} + +static inline void qedr_inc_sw_prod(struct qedr_qp_hwq_info *info) +{ + info->prod = (info->prod + 1) % info->max_wr; +} + static inline int qedr_get_dmac(struct qedr_dev *dev, struct ib_ah_attr *ah_attr, u8 *mac_addr) { diff --git a/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h b/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h index 47705598eec60..5c98d2055cadf 100644 --- a/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h +++ b/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h @@ -150,6 +150,12 @@ struct rdma_rq_sge { struct regpair addr; __le32 length; __le32 flags; +#define RDMA_RQ_SGE_L_KEY_MASK 0x3FFFFFF +#define RDMA_RQ_SGE_L_KEY_SHIFT 0 +#define RDMA_RQ_SGE_NUM_SGES_MASK 0x7 +#define RDMA_RQ_SGE_NUM_SGES_SHIFT 26 +#define RDMA_RQ_SGE_RESERVED0_MASK 0x7 +#define RDMA_RQ_SGE_RESERVED0_SHIFT 29 }; struct rdma_srq_sge { @@ -183,4 +189,560 @@ struct rdma_pwm_val32_data { __le32 value; }; +/* DIF Block size options */ +enum rdma_dif_block_size { + RDMA_DIF_BLOCK_512 = 0, + RDMA_DIF_BLOCK_4096 = 1, + MAX_RDMA_DIF_BLOCK_SIZE +}; + +/* DIF CRC initial value */ +enum rdma_dif_crc_seed { + RDMA_DIF_CRC_SEED_0000 = 0, + RDMA_DIF_CRC_SEED_FFFF = 1, + MAX_RDMA_DIF_CRC_SEED +}; + +/* RDMA DIF Error Result Structure */ +struct rdma_dif_error_result { + __le32 error_intervals; + __le32 dif_error_1st_interval; + u8 flags; +#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_CRC_MASK 0x1 +#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_CRC_SHIFT 0 +#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_APP_TAG_MASK 0x1 +#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_APP_TAG_SHIFT 1 +#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_REF_TAG_MASK 0x1 +#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_REF_TAG_SHIFT 2 +#define RDMA_DIF_ERROR_RESULT_RESERVED0_MASK 0xF +#define RDMA_DIF_ERROR_RESULT_RESERVED0_SHIFT 3 +#define RDMA_DIF_ERROR_RESULT_TOGGLE_BIT_MASK 0x1 +#define RDMA_DIF_ERROR_RESULT_TOGGLE_BIT_SHIFT 7 + u8 reserved1[55]; +}; + +/* DIF IO direction */ +enum rdma_dif_io_direction_flg { + RDMA_DIF_DIR_RX = 0, + RDMA_DIF_DIR_TX = 1, + MAX_RDMA_DIF_IO_DIRECTION_FLG +}; + +/* RDMA DIF Runt Result Structure */ +struct rdma_dif_runt_result { + __le16 guard_tag; + __le16 reserved[3]; +}; + +/* Memory window type enumeration */ +enum rdma_mw_type { + RDMA_MW_TYPE_1, + RDMA_MW_TYPE_2A, + MAX_RDMA_MW_TYPE +}; + +struct rdma_sq_atomic_wqe { + __le32 reserved1; + __le32 length; + __le32 xrc_srq; + u8 req_type; + u8 flags; +#define RDMA_SQ_ATOMIC_WQE_COMP_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_COMP_FLG_SHIFT 0 +#define RDMA_SQ_ATOMIC_WQE_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_ATOMIC_WQE_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_ATOMIC_WQE_SE_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_SE_FLG_SHIFT 3 +#define RDMA_SQ_ATOMIC_WQE_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_ATOMIC_WQE_DIF_ON_HOST_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_DIF_ON_HOST_FLG_SHIFT 5 +#define RDMA_SQ_ATOMIC_WQE_RESERVED0_MASK 0x3 +#define RDMA_SQ_ATOMIC_WQE_RESERVED0_SHIFT 6 + u8 wqe_size; + u8 prev_wqe_size; + struct regpair remote_va; + __le32 r_key; + __le32 reserved2; + struct regpair cmp_data; + struct regpair swap_data; +}; + +/* First element (16 bytes) of atomic wqe */ +struct rdma_sq_atomic_wqe_1st { + __le32 reserved1; + __le32 length; + __le32 xrc_srq; + u8 req_type; + u8 flags; +#define RDMA_SQ_ATOMIC_WQE_1ST_COMP_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_1ST_COMP_FLG_SHIFT 0 +#define RDMA_SQ_ATOMIC_WQE_1ST_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_1ST_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_ATOMIC_WQE_1ST_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_1ST_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_ATOMIC_WQE_1ST_SE_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_1ST_SE_FLG_SHIFT 3 +#define RDMA_SQ_ATOMIC_WQE_1ST_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_ATOMIC_WQE_1ST_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_ATOMIC_WQE_1ST_RESERVED0_MASK 0x7 +#define RDMA_SQ_ATOMIC_WQE_1ST_RESERVED0_SHIFT 5 + u8 wqe_size; + u8 prev_wqe_size; +}; + +/* Second element (16 bytes) of atomic wqe */ +struct rdma_sq_atomic_wqe_2nd { + struct regpair remote_va; + __le32 r_key; + __le32 reserved2; +}; + +/* Third element (16 bytes) of atomic wqe */ +struct rdma_sq_atomic_wqe_3rd { + struct regpair cmp_data; + struct regpair swap_data; +}; + +struct rdma_sq_bind_wqe { + struct regpair addr; + __le32 l_key; + u8 req_type; + u8 flags; +#define RDMA_SQ_BIND_WQE_COMP_FLG_MASK 0x1 +#define RDMA_SQ_BIND_WQE_COMP_FLG_SHIFT 0 +#define RDMA_SQ_BIND_WQE_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_BIND_WQE_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_BIND_WQE_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_BIND_WQE_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_BIND_WQE_SE_FLG_MASK 0x1 +#define RDMA_SQ_BIND_WQE_SE_FLG_SHIFT 3 +#define RDMA_SQ_BIND_WQE_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_BIND_WQE_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_BIND_WQE_RESERVED0_MASK 0x7 +#define RDMA_SQ_BIND_WQE_RESERVED0_SHIFT 5 + u8 wqe_size; + u8 prev_wqe_size; + u8 bind_ctrl; +#define RDMA_SQ_BIND_WQE_ZERO_BASED_MASK 0x1 +#define RDMA_SQ_BIND_WQE_ZERO_BASED_SHIFT 0 +#define RDMA_SQ_BIND_WQE_MW_TYPE_MASK 0x1 +#define RDMA_SQ_BIND_WQE_MW_TYPE_SHIFT 1 +#define RDMA_SQ_BIND_WQE_RESERVED1_MASK 0x3F +#define RDMA_SQ_BIND_WQE_RESERVED1_SHIFT 2 + u8 access_ctrl; +#define RDMA_SQ_BIND_WQE_REMOTE_READ_MASK 0x1 +#define RDMA_SQ_BIND_WQE_REMOTE_READ_SHIFT 0 +#define RDMA_SQ_BIND_WQE_REMOTE_WRITE_MASK 0x1 +#define RDMA_SQ_BIND_WQE_REMOTE_WRITE_SHIFT 1 +#define RDMA_SQ_BIND_WQE_ENABLE_ATOMIC_MASK 0x1 +#define RDMA_SQ_BIND_WQE_ENABLE_ATOMIC_SHIFT 2 +#define RDMA_SQ_BIND_WQE_LOCAL_READ_MASK 0x1 +#define RDMA_SQ_BIND_WQE_LOCAL_READ_SHIFT 3 +#define RDMA_SQ_BIND_WQE_LOCAL_WRITE_MASK 0x1 +#define RDMA_SQ_BIND_WQE_LOCAL_WRITE_SHIFT 4 +#define RDMA_SQ_BIND_WQE_RESERVED2_MASK 0x7 +#define RDMA_SQ_BIND_WQE_RESERVED2_SHIFT 5 + u8 reserved3; + u8 length_hi; + __le32 length_lo; + __le32 parent_l_key; + __le32 reserved4; +}; + +/* First element (16 bytes) of bind wqe */ +struct rdma_sq_bind_wqe_1st { + struct regpair addr; + __le32 l_key; + u8 req_type; + u8 flags; +#define RDMA_SQ_BIND_WQE_1ST_COMP_FLG_MASK 0x1 +#define RDMA_SQ_BIND_WQE_1ST_COMP_FLG_SHIFT 0 +#define RDMA_SQ_BIND_WQE_1ST_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_BIND_WQE_1ST_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_BIND_WQE_1ST_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_BIND_WQE_1ST_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_BIND_WQE_1ST_SE_FLG_MASK 0x1 +#define RDMA_SQ_BIND_WQE_1ST_SE_FLG_SHIFT 3 +#define RDMA_SQ_BIND_WQE_1ST_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_BIND_WQE_1ST_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_BIND_WQE_1ST_RESERVED0_MASK 0x7 +#define RDMA_SQ_BIND_WQE_1ST_RESERVED0_SHIFT 5 + u8 wqe_size; + u8 prev_wqe_size; +}; + +/* Second element (16 bytes) of bind wqe */ +struct rdma_sq_bind_wqe_2nd { + u8 bind_ctrl; +#define RDMA_SQ_BIND_WQE_2ND_ZERO_BASED_MASK 0x1 +#define RDMA_SQ_BIND_WQE_2ND_ZERO_BASED_SHIFT 0 +#define RDMA_SQ_BIND_WQE_2ND_MW_TYPE_MASK 0x1 +#define RDMA_SQ_BIND_WQE_2ND_MW_TYPE_SHIFT 1 +#define RDMA_SQ_BIND_WQE_2ND_RESERVED1_MASK 0x3F +#define RDMA_SQ_BIND_WQE_2ND_RESERVED1_SHIFT 2 + u8 access_ctrl; +#define RDMA_SQ_BIND_WQE_2ND_REMOTE_READ_MASK 0x1 +#define RDMA_SQ_BIND_WQE_2ND_REMOTE_READ_SHIFT 0 +#define RDMA_SQ_BIND_WQE_2ND_REMOTE_WRITE_MASK 0x1 +#define RDMA_SQ_BIND_WQE_2ND_REMOTE_WRITE_SHIFT 1 +#define RDMA_SQ_BIND_WQE_2ND_ENABLE_ATOMIC_MASK 0x1 +#define RDMA_SQ_BIND_WQE_2ND_ENABLE_ATOMIC_SHIFT 2 +#define RDMA_SQ_BIND_WQE_2ND_LOCAL_READ_MASK 0x1 +#define RDMA_SQ_BIND_WQE_2ND_LOCAL_READ_SHIFT 3 +#define RDMA_SQ_BIND_WQE_2ND_LOCAL_WRITE_MASK 0x1 +#define RDMA_SQ_BIND_WQE_2ND_LOCAL_WRITE_SHIFT 4 +#define RDMA_SQ_BIND_WQE_2ND_RESERVED2_MASK 0x7 +#define RDMA_SQ_BIND_WQE_2ND_RESERVED2_SHIFT 5 + u8 reserved3; + u8 length_hi; + __le32 length_lo; + __le32 parent_l_key; + __le32 reserved4; +}; + +/* Structure with only the SQ WQE common + * fields. Size is of one SQ element (16B) + */ +struct rdma_sq_common_wqe { + __le32 reserved1[3]; + u8 req_type; + u8 flags; +#define RDMA_SQ_COMMON_WQE_COMP_FLG_MASK 0x1 +#define RDMA_SQ_COMMON_WQE_COMP_FLG_SHIFT 0 +#define RDMA_SQ_COMMON_WQE_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_COMMON_WQE_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_COMMON_WQE_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_COMMON_WQE_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_COMMON_WQE_SE_FLG_MASK 0x1 +#define RDMA_SQ_COMMON_WQE_SE_FLG_SHIFT 3 +#define RDMA_SQ_COMMON_WQE_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_COMMON_WQE_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_COMMON_WQE_RESERVED0_MASK 0x7 +#define RDMA_SQ_COMMON_WQE_RESERVED0_SHIFT 5 + u8 wqe_size; + u8 prev_wqe_size; +}; + +struct rdma_sq_fmr_wqe { + struct regpair addr; + __le32 l_key; + u8 req_type; + u8 flags; +#define RDMA_SQ_FMR_WQE_COMP_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_COMP_FLG_SHIFT 0 +#define RDMA_SQ_FMR_WQE_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_FMR_WQE_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_FMR_WQE_SE_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_SE_FLG_SHIFT 3 +#define RDMA_SQ_FMR_WQE_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_FMR_WQE_DIF_ON_HOST_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_DIF_ON_HOST_FLG_SHIFT 5 +#define RDMA_SQ_FMR_WQE_RESERVED0_MASK 0x3 +#define RDMA_SQ_FMR_WQE_RESERVED0_SHIFT 6 + u8 wqe_size; + u8 prev_wqe_size; + u8 fmr_ctrl; +#define RDMA_SQ_FMR_WQE_PAGE_SIZE_LOG_MASK 0x1F +#define RDMA_SQ_FMR_WQE_PAGE_SIZE_LOG_SHIFT 0 +#define RDMA_SQ_FMR_WQE_ZERO_BASED_MASK 0x1 +#define RDMA_SQ_FMR_WQE_ZERO_BASED_SHIFT 5 +#define RDMA_SQ_FMR_WQE_BIND_EN_MASK 0x1 +#define RDMA_SQ_FMR_WQE_BIND_EN_SHIFT 6 +#define RDMA_SQ_FMR_WQE_RESERVED1_MASK 0x1 +#define RDMA_SQ_FMR_WQE_RESERVED1_SHIFT 7 + u8 access_ctrl; +#define RDMA_SQ_FMR_WQE_REMOTE_READ_MASK 0x1 +#define RDMA_SQ_FMR_WQE_REMOTE_READ_SHIFT 0 +#define RDMA_SQ_FMR_WQE_REMOTE_WRITE_MASK 0x1 +#define RDMA_SQ_FMR_WQE_REMOTE_WRITE_SHIFT 1 +#define RDMA_SQ_FMR_WQE_ENABLE_ATOMIC_MASK 0x1 +#define RDMA_SQ_FMR_WQE_ENABLE_ATOMIC_SHIFT 2 +#define RDMA_SQ_FMR_WQE_LOCAL_READ_MASK 0x1 +#define RDMA_SQ_FMR_WQE_LOCAL_READ_SHIFT 3 +#define RDMA_SQ_FMR_WQE_LOCAL_WRITE_MASK 0x1 +#define RDMA_SQ_FMR_WQE_LOCAL_WRITE_SHIFT 4 +#define RDMA_SQ_FMR_WQE_RESERVED2_MASK 0x7 +#define RDMA_SQ_FMR_WQE_RESERVED2_SHIFT 5 + u8 reserved3; + u8 length_hi; + __le32 length_lo; + struct regpair pbl_addr; + __le32 dif_base_ref_tag; + __le16 dif_app_tag; + __le16 dif_app_tag_mask; + __le16 dif_runt_crc_value; + __le16 dif_flags; +#define RDMA_SQ_FMR_WQE_DIF_IO_DIRECTION_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_DIF_IO_DIRECTION_FLG_SHIFT 0 +#define RDMA_SQ_FMR_WQE_DIF_BLOCK_SIZE_MASK 0x1 +#define RDMA_SQ_FMR_WQE_DIF_BLOCK_SIZE_SHIFT 1 +#define RDMA_SQ_FMR_WQE_DIF_RUNT_VALID_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_DIF_RUNT_VALID_FLG_SHIFT 2 +#define RDMA_SQ_FMR_WQE_DIF_VALIDATE_CRC_GUARD_MASK 0x1 +#define RDMA_SQ_FMR_WQE_DIF_VALIDATE_CRC_GUARD_SHIFT 3 +#define RDMA_SQ_FMR_WQE_DIF_VALIDATE_REF_TAG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_DIF_VALIDATE_REF_TAG_SHIFT 4 +#define RDMA_SQ_FMR_WQE_DIF_VALIDATE_APP_TAG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_DIF_VALIDATE_APP_TAG_SHIFT 5 +#define RDMA_SQ_FMR_WQE_DIF_CRC_SEED_MASK 0x1 +#define RDMA_SQ_FMR_WQE_DIF_CRC_SEED_SHIFT 6 +#define RDMA_SQ_FMR_WQE_RESERVED4_MASK 0x1FF +#define RDMA_SQ_FMR_WQE_RESERVED4_SHIFT 7 + __le32 Reserved5; +}; + +/* First element (16 bytes) of fmr wqe */ +struct rdma_sq_fmr_wqe_1st { + struct regpair addr; + __le32 l_key; + u8 req_type; + u8 flags; +#define RDMA_SQ_FMR_WQE_1ST_COMP_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_1ST_COMP_FLG_SHIFT 0 +#define RDMA_SQ_FMR_WQE_1ST_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_1ST_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_FMR_WQE_1ST_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_1ST_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_FMR_WQE_1ST_SE_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_1ST_SE_FLG_SHIFT 3 +#define RDMA_SQ_FMR_WQE_1ST_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_1ST_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_FMR_WQE_1ST_DIF_ON_HOST_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_1ST_DIF_ON_HOST_FLG_SHIFT 5 +#define RDMA_SQ_FMR_WQE_1ST_RESERVED0_MASK 0x3 +#define RDMA_SQ_FMR_WQE_1ST_RESERVED0_SHIFT 6 + u8 wqe_size; + u8 prev_wqe_size; +}; + +/* Second element (16 bytes) of fmr wqe */ +struct rdma_sq_fmr_wqe_2nd { + u8 fmr_ctrl; +#define RDMA_SQ_FMR_WQE_2ND_PAGE_SIZE_LOG_MASK 0x1F +#define RDMA_SQ_FMR_WQE_2ND_PAGE_SIZE_LOG_SHIFT 0 +#define RDMA_SQ_FMR_WQE_2ND_ZERO_BASED_MASK 0x1 +#define RDMA_SQ_FMR_WQE_2ND_ZERO_BASED_SHIFT 5 +#define RDMA_SQ_FMR_WQE_2ND_BIND_EN_MASK 0x1 +#define RDMA_SQ_FMR_WQE_2ND_BIND_EN_SHIFT 6 +#define RDMA_SQ_FMR_WQE_2ND_RESERVED1_MASK 0x1 +#define RDMA_SQ_FMR_WQE_2ND_RESERVED1_SHIFT 7 + u8 access_ctrl; +#define RDMA_SQ_FMR_WQE_2ND_REMOTE_READ_MASK 0x1 +#define RDMA_SQ_FMR_WQE_2ND_REMOTE_READ_SHIFT 0 +#define RDMA_SQ_FMR_WQE_2ND_REMOTE_WRITE_MASK 0x1 +#define RDMA_SQ_FMR_WQE_2ND_REMOTE_WRITE_SHIFT 1 +#define RDMA_SQ_FMR_WQE_2ND_ENABLE_ATOMIC_MASK 0x1 +#define RDMA_SQ_FMR_WQE_2ND_ENABLE_ATOMIC_SHIFT 2 +#define RDMA_SQ_FMR_WQE_2ND_LOCAL_READ_MASK 0x1 +#define RDMA_SQ_FMR_WQE_2ND_LOCAL_READ_SHIFT 3 +#define RDMA_SQ_FMR_WQE_2ND_LOCAL_WRITE_MASK 0x1 +#define RDMA_SQ_FMR_WQE_2ND_LOCAL_WRITE_SHIFT 4 +#define RDMA_SQ_FMR_WQE_2ND_RESERVED2_MASK 0x7 +#define RDMA_SQ_FMR_WQE_2ND_RESERVED2_SHIFT 5 + u8 reserved3; + u8 length_hi; + __le32 length_lo; + struct regpair pbl_addr; +}; + +/* Third element (16 bytes) of fmr wqe */ +struct rdma_sq_fmr_wqe_3rd { + __le32 dif_base_ref_tag; + __le16 dif_app_tag; + __le16 dif_app_tag_mask; + __le16 dif_runt_crc_value; + __le16 dif_flags; +#define RDMA_SQ_FMR_WQE_3RD_DIF_IO_DIRECTION_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_3RD_DIF_IO_DIRECTION_FLG_SHIFT 0 +#define RDMA_SQ_FMR_WQE_3RD_DIF_BLOCK_SIZE_MASK 0x1 +#define RDMA_SQ_FMR_WQE_3RD_DIF_BLOCK_SIZE_SHIFT 1 +#define RDMA_SQ_FMR_WQE_3RD_DIF_RUNT_VALID_FLG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_3RD_DIF_RUNT_VALID_FLG_SHIFT 2 +#define RDMA_SQ_FMR_WQE_3RD_DIF_VALIDATE_CRC_GUARD_MASK 0x1 +#define RDMA_SQ_FMR_WQE_3RD_DIF_VALIDATE_CRC_GUARD_SHIFT 3 +#define RDMA_SQ_FMR_WQE_3RD_DIF_VALIDATE_REF_TAG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_3RD_DIF_VALIDATE_REF_TAG_SHIFT 4 +#define RDMA_SQ_FMR_WQE_3RD_DIF_VALIDATE_APP_TAG_MASK 0x1 +#define RDMA_SQ_FMR_WQE_3RD_DIF_VALIDATE_APP_TAG_SHIFT 5 +#define RDMA_SQ_FMR_WQE_3RD_DIF_CRC_SEED_MASK 0x1 +#define RDMA_SQ_FMR_WQE_3RD_DIF_CRC_SEED_SHIFT 6 +#define RDMA_SQ_FMR_WQE_3RD_RESERVED4_MASK 0x1FF +#define RDMA_SQ_FMR_WQE_3RD_RESERVED4_SHIFT 7 + __le32 Reserved5; +}; + +struct rdma_sq_local_inv_wqe { + struct regpair reserved; + __le32 inv_l_key; + u8 req_type; + u8 flags; +#define RDMA_SQ_LOCAL_INV_WQE_COMP_FLG_MASK 0x1 +#define RDMA_SQ_LOCAL_INV_WQE_COMP_FLG_SHIFT 0 +#define RDMA_SQ_LOCAL_INV_WQE_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_LOCAL_INV_WQE_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_LOCAL_INV_WQE_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_LOCAL_INV_WQE_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_LOCAL_INV_WQE_SE_FLG_MASK 0x1 +#define RDMA_SQ_LOCAL_INV_WQE_SE_FLG_SHIFT 3 +#define RDMA_SQ_LOCAL_INV_WQE_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_LOCAL_INV_WQE_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_LOCAL_INV_WQE_DIF_ON_HOST_FLG_MASK 0x1 +#define RDMA_SQ_LOCAL_INV_WQE_DIF_ON_HOST_FLG_SHIFT 5 +#define RDMA_SQ_LOCAL_INV_WQE_RESERVED0_MASK 0x3 +#define RDMA_SQ_LOCAL_INV_WQE_RESERVED0_SHIFT 6 + u8 wqe_size; + u8 prev_wqe_size; +}; + +struct rdma_sq_rdma_wqe { + __le32 imm_data; + __le32 length; + __le32 xrc_srq; + u8 req_type; + u8 flags; +#define RDMA_SQ_RDMA_WQE_COMP_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_COMP_FLG_SHIFT 0 +#define RDMA_SQ_RDMA_WQE_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_RDMA_WQE_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_RDMA_WQE_SE_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_SE_FLG_SHIFT 3 +#define RDMA_SQ_RDMA_WQE_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_RDMA_WQE_DIF_ON_HOST_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_DIF_ON_HOST_FLG_SHIFT 5 +#define RDMA_SQ_RDMA_WQE_RESERVED0_MASK 0x3 +#define RDMA_SQ_RDMA_WQE_RESERVED0_SHIFT 6 + u8 wqe_size; + u8 prev_wqe_size; + struct regpair remote_va; + __le32 r_key; + u8 dif_flags; +#define RDMA_SQ_RDMA_WQE_DIF_BLOCK_SIZE_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_DIF_BLOCK_SIZE_SHIFT 0 +#define RDMA_SQ_RDMA_WQE_DIF_FIRST_RDMA_IN_IO_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_DIF_FIRST_RDMA_IN_IO_FLG_SHIFT 1 +#define RDMA_SQ_RDMA_WQE_DIF_LAST_RDMA_IN_IO_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_DIF_LAST_RDMA_IN_IO_FLG_SHIFT 2 +#define RDMA_SQ_RDMA_WQE_RESERVED1_MASK 0x1F +#define RDMA_SQ_RDMA_WQE_RESERVED1_SHIFT 3 + u8 reserved2[3]; +}; + +/* First element (16 bytes) of rdma wqe */ +struct rdma_sq_rdma_wqe_1st { + __le32 imm_data; + __le32 length; + __le32 xrc_srq; + u8 req_type; + u8 flags; +#define RDMA_SQ_RDMA_WQE_1ST_COMP_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_1ST_COMP_FLG_SHIFT 0 +#define RDMA_SQ_RDMA_WQE_1ST_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_1ST_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_RDMA_WQE_1ST_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_1ST_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_RDMA_WQE_1ST_SE_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_1ST_SE_FLG_SHIFT 3 +#define RDMA_SQ_RDMA_WQE_1ST_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_1ST_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_RDMA_WQE_1ST_DIF_ON_HOST_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_1ST_DIF_ON_HOST_FLG_SHIFT 5 +#define RDMA_SQ_RDMA_WQE_1ST_RESERVED0_MASK 0x3 +#define RDMA_SQ_RDMA_WQE_1ST_RESERVED0_SHIFT 6 + u8 wqe_size; + u8 prev_wqe_size; +}; + +/* Second element (16 bytes) of rdma wqe */ +struct rdma_sq_rdma_wqe_2nd { + struct regpair remote_va; + __le32 r_key; + u8 dif_flags; +#define RDMA_SQ_RDMA_WQE_2ND_DIF_BLOCK_SIZE_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_2ND_DIF_BLOCK_SIZE_SHIFT 0 +#define RDMA_SQ_RDMA_WQE_2ND_DIF_FIRST_SEGMENT_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_2ND_DIF_FIRST_SEGMENT_FLG_SHIFT 1 +#define RDMA_SQ_RDMA_WQE_2ND_DIF_LAST_SEGMENT_FLG_MASK 0x1 +#define RDMA_SQ_RDMA_WQE_2ND_DIF_LAST_SEGMENT_FLG_SHIFT 2 +#define RDMA_SQ_RDMA_WQE_2ND_RESERVED1_MASK 0x1F +#define RDMA_SQ_RDMA_WQE_2ND_RESERVED1_SHIFT 3 + u8 reserved2[3]; +}; + +/* SQ WQE req type enumeration */ +enum rdma_sq_req_type { + RDMA_SQ_REQ_TYPE_SEND, + RDMA_SQ_REQ_TYPE_SEND_WITH_IMM, + RDMA_SQ_REQ_TYPE_SEND_WITH_INVALIDATE, + RDMA_SQ_REQ_TYPE_RDMA_WR, + RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM, + RDMA_SQ_REQ_TYPE_RDMA_RD, + RDMA_SQ_REQ_TYPE_ATOMIC_CMP_AND_SWAP, + RDMA_SQ_REQ_TYPE_ATOMIC_ADD, + RDMA_SQ_REQ_TYPE_LOCAL_INVALIDATE, + RDMA_SQ_REQ_TYPE_FAST_MR, + RDMA_SQ_REQ_TYPE_BIND, + RDMA_SQ_REQ_TYPE_INVALID, + MAX_RDMA_SQ_REQ_TYPE +}; + +struct rdma_sq_send_wqe { + __le32 inv_key_or_imm_data; + __le32 length; + __le32 xrc_srq; + u8 req_type; + u8 flags; +#define RDMA_SQ_SEND_WQE_COMP_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_COMP_FLG_SHIFT 0 +#define RDMA_SQ_SEND_WQE_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_SEND_WQE_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_SEND_WQE_SE_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_SE_FLG_SHIFT 3 +#define RDMA_SQ_SEND_WQE_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_SEND_WQE_DIF_ON_HOST_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_DIF_ON_HOST_FLG_SHIFT 5 +#define RDMA_SQ_SEND_WQE_RESERVED0_MASK 0x3 +#define RDMA_SQ_SEND_WQE_RESERVED0_SHIFT 6 + u8 wqe_size; + u8 prev_wqe_size; + __le32 reserved1[4]; +}; + +struct rdma_sq_send_wqe_1st { + __le32 inv_key_or_imm_data; + __le32 length; + __le32 xrc_srq; + u8 req_type; + u8 flags; +#define RDMA_SQ_SEND_WQE_1ST_COMP_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_1ST_COMP_FLG_SHIFT 0 +#define RDMA_SQ_SEND_WQE_1ST_RD_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_1ST_RD_FENCE_FLG_SHIFT 1 +#define RDMA_SQ_SEND_WQE_1ST_INV_FENCE_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_1ST_INV_FENCE_FLG_SHIFT 2 +#define RDMA_SQ_SEND_WQE_1ST_SE_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_1ST_SE_FLG_SHIFT 3 +#define RDMA_SQ_SEND_WQE_1ST_INLINE_FLG_MASK 0x1 +#define RDMA_SQ_SEND_WQE_1ST_INLINE_FLG_SHIFT 4 +#define RDMA_SQ_SEND_WQE_1ST_RESERVED0_MASK 0x7 +#define RDMA_SQ_SEND_WQE_1ST_RESERVED0_SHIFT 5 + u8 wqe_size; + u8 prev_wqe_size; +}; + +struct rdma_sq_send_wqe_2st { + __le32 reserved1[4]; +}; + #endif /* __QED_HSI_RDMA__ */ diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index e70e808e2b9b3..e4b4d47c6a2da 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -2447,3 +2447,1023 @@ struct ib_mr *qedr_get_dma_mr(struct ib_pd *ibpd, int acc) kfree(mr); return ERR_PTR(rc); } + +static inline int qedr_wq_is_full(struct qedr_qp_hwq_info *wq) +{ + return (((wq->prod + 1) % wq->max_wr) == wq->cons); +} + +static int sge_data_len(struct ib_sge *sg_list, int num_sge) +{ + int i, len = 0; + + for (i = 0; i < num_sge; i++) + len += sg_list[i].length; + + return len; +} + +static void swap_wqe_data64(u64 *p) +{ + int i; + + for (i = 0; i < QEDR_SQE_ELEMENT_SIZE / sizeof(u64); i++, p++) + *p = cpu_to_be64(cpu_to_le64(*p)); +} + +static u32 qedr_prepare_sq_inline_data(struct qedr_dev *dev, + struct qedr_qp *qp, u8 *wqe_size, + struct ib_send_wr *wr, + struct ib_send_wr **bad_wr, u8 *bits, + u8 bit) +{ + u32 data_size = sge_data_len(wr->sg_list, wr->num_sge); + char *seg_prt, *wqe; + int i, seg_siz; + + if (data_size > ROCE_REQ_MAX_INLINE_DATA_SIZE) { + DP_ERR(dev, "Too much inline data in WR: %d\n", data_size); + *bad_wr = wr; + return 0; + } + + if (!data_size) + return data_size; + + *bits |= bit; + + seg_prt = NULL; + wqe = NULL; + seg_siz = 0; + + /* Copy data inline */ + for (i = 0; i < wr->num_sge; i++) { + u32 len = wr->sg_list[i].length; + void *src = (void *)(uintptr_t)wr->sg_list[i].addr; + + while (len > 0) { + u32 cur; + + /* New segment required */ + if (!seg_siz) { + wqe = (char *)qed_chain_produce(&qp->sq.pbl); + seg_prt = wqe; + seg_siz = sizeof(struct rdma_sq_common_wqe); + (*wqe_size)++; + } + + /* Calculate currently allowed length */ + cur = min_t(u32, len, seg_siz); + memcpy(seg_prt, src, cur); + + /* Update segment variables */ + seg_prt += cur; + seg_siz -= cur; + + /* Update sge variables */ + src += cur; + len -= cur; + + /* Swap fully-completed segments */ + if (!seg_siz) + swap_wqe_data64((u64 *)wqe); + } + } + + /* swap last not completed segment */ + if (seg_siz) + swap_wqe_data64((u64 *)wqe); + + return data_size; +} + +#define RQ_SGE_SET(sge, vaddr, vlength, vflags) \ + do { \ + DMA_REGPAIR_LE(sge->addr, vaddr); \ + (sge)->length = cpu_to_le32(vlength); \ + (sge)->flags = cpu_to_le32(vflags); \ + } while (0) + +#define SRQ_HDR_SET(hdr, vwr_id, num_sge) \ + do { \ + DMA_REGPAIR_LE(hdr->wr_id, vwr_id); \ + (hdr)->num_sges = num_sge; \ + } while (0) + +#define SRQ_SGE_SET(sge, vaddr, vlength, vlkey) \ + do { \ + DMA_REGPAIR_LE(sge->addr, vaddr); \ + (sge)->length = cpu_to_le32(vlength); \ + (sge)->l_key = cpu_to_le32(vlkey); \ + } while (0) + +static u32 qedr_prepare_sq_sges(struct qedr_qp *qp, u8 *wqe_size, + struct ib_send_wr *wr) +{ + u32 data_size = 0; + int i; + + for (i = 0; i < wr->num_sge; i++) { + struct rdma_sq_sge *sge = qed_chain_produce(&qp->sq.pbl); + + DMA_REGPAIR_LE(sge->addr, wr->sg_list[i].addr); + sge->l_key = cpu_to_le32(wr->sg_list[i].lkey); + sge->length = cpu_to_le32(wr->sg_list[i].length); + data_size += wr->sg_list[i].length; + } + + if (wqe_size) + *wqe_size += wr->num_sge; + + return data_size; +} + +static u32 qedr_prepare_sq_rdma_data(struct qedr_dev *dev, + struct qedr_qp *qp, + struct rdma_sq_rdma_wqe_1st *rwqe, + struct rdma_sq_rdma_wqe_2nd *rwqe2, + struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + rwqe2->r_key = cpu_to_le32(rdma_wr(wr)->rkey); + DMA_REGPAIR_LE(rwqe2->remote_va, rdma_wr(wr)->remote_addr); + + if (wr->send_flags & IB_SEND_INLINE) { + u8 flags = 0; + + SET_FIELD2(flags, RDMA_SQ_RDMA_WQE_1ST_INLINE_FLG, 1); + return qedr_prepare_sq_inline_data(dev, qp, &rwqe->wqe_size, wr, + bad_wr, &rwqe->flags, flags); + } + + return qedr_prepare_sq_sges(qp, &rwqe->wqe_size, wr); +} + +static u32 qedr_prepare_sq_send_data(struct qedr_dev *dev, + struct qedr_qp *qp, + struct rdma_sq_send_wqe_1st *swqe, + struct rdma_sq_send_wqe_2st *swqe2, + struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + memset(swqe2, 0, sizeof(*swqe2)); + if (wr->send_flags & IB_SEND_INLINE) { + u8 flags = 0; + + SET_FIELD2(flags, RDMA_SQ_SEND_WQE_INLINE_FLG, 1); + return qedr_prepare_sq_inline_data(dev, qp, &swqe->wqe_size, wr, + bad_wr, &swqe->flags, flags); + } + + return qedr_prepare_sq_sges(qp, &swqe->wqe_size, wr); +} + +static int qedr_prepare_reg(struct qedr_qp *qp, + struct rdma_sq_fmr_wqe_1st *fwqe1, + struct ib_reg_wr *wr) +{ + struct qedr_mr *mr = get_qedr_mr(wr->mr); + struct rdma_sq_fmr_wqe_2nd *fwqe2; + + fwqe2 = (struct rdma_sq_fmr_wqe_2nd *)qed_chain_produce(&qp->sq.pbl); + fwqe1->addr.hi = upper_32_bits(mr->ibmr.iova); + fwqe1->addr.lo = lower_32_bits(mr->ibmr.iova); + fwqe1->l_key = wr->key; + + SET_FIELD2(fwqe2->access_ctrl, RDMA_SQ_FMR_WQE_2ND_REMOTE_READ, + !!(wr->access & IB_ACCESS_REMOTE_READ)); + SET_FIELD2(fwqe2->access_ctrl, RDMA_SQ_FMR_WQE_2ND_REMOTE_WRITE, + !!(wr->access & IB_ACCESS_REMOTE_WRITE)); + SET_FIELD2(fwqe2->access_ctrl, RDMA_SQ_FMR_WQE_2ND_ENABLE_ATOMIC, + !!(wr->access & IB_ACCESS_REMOTE_ATOMIC)); + SET_FIELD2(fwqe2->access_ctrl, RDMA_SQ_FMR_WQE_2ND_LOCAL_READ, 1); + SET_FIELD2(fwqe2->access_ctrl, RDMA_SQ_FMR_WQE_2ND_LOCAL_WRITE, + !!(wr->access & IB_ACCESS_LOCAL_WRITE)); + fwqe2->fmr_ctrl = 0; + + SET_FIELD2(fwqe2->fmr_ctrl, RDMA_SQ_FMR_WQE_2ND_PAGE_SIZE_LOG, + ilog2(mr->ibmr.page_size) - 12); + + fwqe2->length_hi = 0; + fwqe2->length_lo = mr->ibmr.length; + fwqe2->pbl_addr.hi = upper_32_bits(mr->info.pbl_table->pa); + fwqe2->pbl_addr.lo = lower_32_bits(mr->info.pbl_table->pa); + + qp->wqe_wr_id[qp->sq.prod].mr = mr; + + return 0; +} + +enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode) +{ + switch (opcode) { + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + return IB_WC_RDMA_WRITE; + case IB_WR_SEND_WITH_IMM: + case IB_WR_SEND: + case IB_WR_SEND_WITH_INV: + return IB_WC_SEND; + case IB_WR_RDMA_READ: + return IB_WC_RDMA_READ; + case IB_WR_ATOMIC_CMP_AND_SWP: + return IB_WC_COMP_SWAP; + case IB_WR_ATOMIC_FETCH_AND_ADD: + return IB_WC_FETCH_ADD; + case IB_WR_REG_MR: + return IB_WC_REG_MR; + case IB_WR_LOCAL_INV: + return IB_WC_LOCAL_INV; + default: + return IB_WC_SEND; + } +} + +inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr) +{ + int wq_is_full, err_wr, pbl_is_full; + struct qedr_dev *dev = qp->dev; + + /* prevent SQ overflow and/or processing of a bad WR */ + err_wr = wr->num_sge > qp->sq.max_sges; + wq_is_full = qedr_wq_is_full(&qp->sq); + pbl_is_full = qed_chain_get_elem_left_u32(&qp->sq.pbl) < + QEDR_MAX_SQE_ELEMENTS_PER_SQE; + if (wq_is_full || err_wr || pbl_is_full) { + if (wq_is_full && !(qp->err_bitmap & QEDR_QP_ERR_SQ_FULL)) { + DP_ERR(dev, + "error: WQ is full. Post send on QP %p failed (this error appears only once)\n", + qp); + qp->err_bitmap |= QEDR_QP_ERR_SQ_FULL; + } + + if (err_wr && !(qp->err_bitmap & QEDR_QP_ERR_BAD_SR)) { + DP_ERR(dev, + "error: WR is bad. Post send on QP %p failed (this error appears only once)\n", + qp); + qp->err_bitmap |= QEDR_QP_ERR_BAD_SR; + } + + if (pbl_is_full && + !(qp->err_bitmap & QEDR_QP_ERR_SQ_PBL_FULL)) { + DP_ERR(dev, + "error: WQ PBL is full. Post send on QP %p failed (this error appears only once)\n", + qp); + qp->err_bitmap |= QEDR_QP_ERR_SQ_PBL_FULL; + } + return false; + } + return true; +} + +int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + struct qedr_dev *dev = get_qedr_dev(ibqp->device); + struct qedr_qp *qp = get_qedr_qp(ibqp); + struct rdma_sq_atomic_wqe_1st *awqe1; + struct rdma_sq_atomic_wqe_2nd *awqe2; + struct rdma_sq_atomic_wqe_3rd *awqe3; + struct rdma_sq_send_wqe_2st *swqe2; + struct rdma_sq_local_inv_wqe *iwqe; + struct rdma_sq_rdma_wqe_2nd *rwqe2; + struct rdma_sq_send_wqe_1st *swqe; + struct rdma_sq_rdma_wqe_1st *rwqe; + struct rdma_sq_fmr_wqe_1st *fwqe1; + struct rdma_sq_common_wqe *wqe; + u32 length; + int rc = 0; + bool comp; + + if (!qedr_can_post_send(qp, wr)) { + *bad_wr = wr; + return -ENOMEM; + } + + wqe = qed_chain_produce(&qp->sq.pbl); + qp->wqe_wr_id[qp->sq.prod].signaled = + !!(wr->send_flags & IB_SEND_SIGNALED) || qp->signaled; + + wqe->flags = 0; + SET_FIELD2(wqe->flags, RDMA_SQ_SEND_WQE_SE_FLG, + !!(wr->send_flags & IB_SEND_SOLICITED)); + comp = (!!(wr->send_flags & IB_SEND_SIGNALED)) || qp->signaled; + SET_FIELD2(wqe->flags, RDMA_SQ_SEND_WQE_COMP_FLG, comp); + SET_FIELD2(wqe->flags, RDMA_SQ_SEND_WQE_RD_FENCE_FLG, + !!(wr->send_flags & IB_SEND_FENCE)); + wqe->prev_wqe_size = qp->prev_wqe_size; + + qp->wqe_wr_id[qp->sq.prod].opcode = qedr_ib_to_wc_opcode(wr->opcode); + + switch (wr->opcode) { + case IB_WR_SEND_WITH_IMM: + wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_IMM; + swqe = (struct rdma_sq_send_wqe_1st *)wqe; + swqe->wqe_size = 2; + swqe2 = qed_chain_produce(&qp->sq.pbl); + + swqe->inv_key_or_imm_data = cpu_to_le32(wr->ex.imm_data); + length = qedr_prepare_sq_send_data(dev, qp, swqe, swqe2, + wr, bad_wr); + swqe->length = cpu_to_le32(length); + qp->wqe_wr_id[qp->sq.prod].wqe_size = swqe->wqe_size; + qp->prev_wqe_size = swqe->wqe_size; + qp->wqe_wr_id[qp->sq.prod].bytes_len = swqe->length; + break; + case IB_WR_SEND: + wqe->req_type = RDMA_SQ_REQ_TYPE_SEND; + swqe = (struct rdma_sq_send_wqe_1st *)wqe; + + swqe->wqe_size = 2; + swqe2 = qed_chain_produce(&qp->sq.pbl); + length = qedr_prepare_sq_send_data(dev, qp, swqe, swqe2, + wr, bad_wr); + swqe->length = cpu_to_le32(length); + qp->wqe_wr_id[qp->sq.prod].wqe_size = swqe->wqe_size; + qp->prev_wqe_size = swqe->wqe_size; + qp->wqe_wr_id[qp->sq.prod].bytes_len = swqe->length; + break; + case IB_WR_SEND_WITH_INV: + wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_INVALIDATE; + swqe = (struct rdma_sq_send_wqe_1st *)wqe; + swqe2 = qed_chain_produce(&qp->sq.pbl); + swqe->wqe_size = 2; + swqe->inv_key_or_imm_data = cpu_to_le32(wr->ex.invalidate_rkey); + length = qedr_prepare_sq_send_data(dev, qp, swqe, swqe2, + wr, bad_wr); + swqe->length = cpu_to_le32(length); + qp->wqe_wr_id[qp->sq.prod].wqe_size = swqe->wqe_size; + qp->prev_wqe_size = swqe->wqe_size; + qp->wqe_wr_id[qp->sq.prod].bytes_len = swqe->length; + break; + + case IB_WR_RDMA_WRITE_WITH_IMM: + wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM; + rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; + + rwqe->wqe_size = 2; + rwqe->imm_data = htonl(cpu_to_le32(wr->ex.imm_data)); + rwqe2 = qed_chain_produce(&qp->sq.pbl); + length = qedr_prepare_sq_rdma_data(dev, qp, rwqe, rwqe2, + wr, bad_wr); + rwqe->length = cpu_to_le32(length); + qp->wqe_wr_id[qp->sq.prod].wqe_size = rwqe->wqe_size; + qp->prev_wqe_size = rwqe->wqe_size; + qp->wqe_wr_id[qp->sq.prod].bytes_len = rwqe->length; + break; + case IB_WR_RDMA_WRITE: + wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR; + rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; + + rwqe->wqe_size = 2; + rwqe2 = qed_chain_produce(&qp->sq.pbl); + length = qedr_prepare_sq_rdma_data(dev, qp, rwqe, rwqe2, + wr, bad_wr); + rwqe->length = cpu_to_le32(length); + qp->wqe_wr_id[qp->sq.prod].wqe_size = rwqe->wqe_size; + qp->prev_wqe_size = rwqe->wqe_size; + qp->wqe_wr_id[qp->sq.prod].bytes_len = rwqe->length; + break; + case IB_WR_RDMA_READ_WITH_INV: + DP_ERR(dev, + "RDMA READ WITH INVALIDATE not supported\n"); + *bad_wr = wr; + rc = -EINVAL; + break; + + case IB_WR_RDMA_READ: + wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_RD; + rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; + + rwqe->wqe_size = 2; + rwqe2 = qed_chain_produce(&qp->sq.pbl); + length = qedr_prepare_sq_rdma_data(dev, qp, rwqe, rwqe2, + wr, bad_wr); + rwqe->length = cpu_to_le32(length); + qp->wqe_wr_id[qp->sq.prod].wqe_size = rwqe->wqe_size; + qp->prev_wqe_size = rwqe->wqe_size; + qp->wqe_wr_id[qp->sq.prod].bytes_len = rwqe->length; + break; + + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + awqe1 = (struct rdma_sq_atomic_wqe_1st *)wqe; + awqe1->wqe_size = 4; + + awqe2 = qed_chain_produce(&qp->sq.pbl); + DMA_REGPAIR_LE(awqe2->remote_va, atomic_wr(wr)->remote_addr); + awqe2->r_key = cpu_to_le32(atomic_wr(wr)->rkey); + + awqe3 = qed_chain_produce(&qp->sq.pbl); + + if (wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) { + wqe->req_type = RDMA_SQ_REQ_TYPE_ATOMIC_ADD; + DMA_REGPAIR_LE(awqe3->swap_data, + atomic_wr(wr)->compare_add); + } else { + wqe->req_type = RDMA_SQ_REQ_TYPE_ATOMIC_CMP_AND_SWAP; + DMA_REGPAIR_LE(awqe3->swap_data, + atomic_wr(wr)->swap); + DMA_REGPAIR_LE(awqe3->cmp_data, + atomic_wr(wr)->compare_add); + } + + qedr_prepare_sq_sges(qp, NULL, wr); + + qp->wqe_wr_id[qp->sq.prod].wqe_size = awqe1->wqe_size; + qp->prev_wqe_size = awqe1->wqe_size; + break; + + case IB_WR_LOCAL_INV: + iwqe = (struct rdma_sq_local_inv_wqe *)wqe; + iwqe->wqe_size = 1; + + iwqe->req_type = RDMA_SQ_REQ_TYPE_LOCAL_INVALIDATE; + iwqe->inv_l_key = wr->ex.invalidate_rkey; + qp->wqe_wr_id[qp->sq.prod].wqe_size = iwqe->wqe_size; + qp->prev_wqe_size = iwqe->wqe_size; + break; + case IB_WR_REG_MR: + DP_DEBUG(dev, QEDR_MSG_CQ, "REG_MR\n"); + wqe->req_type = RDMA_SQ_REQ_TYPE_FAST_MR; + fwqe1 = (struct rdma_sq_fmr_wqe_1st *)wqe; + fwqe1->wqe_size = 2; + + rc = qedr_prepare_reg(qp, fwqe1, reg_wr(wr)); + if (rc) { + DP_ERR(dev, "IB_REG_MR failed rc=%d\n", rc); + *bad_wr = wr; + break; + } + + qp->wqe_wr_id[qp->sq.prod].wqe_size = fwqe1->wqe_size; + qp->prev_wqe_size = fwqe1->wqe_size; + break; + default: + DP_ERR(dev, "invalid opcode 0x%x!\n", wr->opcode); + rc = -EINVAL; + *bad_wr = wr; + break; + } + + if (*bad_wr) { + u16 value; + + /* Restore prod to its position before + * this WR was processed + */ + value = le16_to_cpu(qp->sq.db_data.data.value); + qed_chain_set_prod(&qp->sq.pbl, value, wqe); + + /* Restore prev_wqe_size */ + qp->prev_wqe_size = wqe->prev_wqe_size; + rc = -EINVAL; + DP_ERR(dev, "POST SEND FAILED\n"); + } + + return rc; +} + +int qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + struct qedr_dev *dev = get_qedr_dev(ibqp->device); + struct qedr_qp *qp = get_qedr_qp(ibqp); + unsigned long flags; + int rc = 0; + + *bad_wr = NULL; + + spin_lock_irqsave(&qp->q_lock, flags); + + if ((qp->state == QED_ROCE_QP_STATE_RESET) || + (qp->state == QED_ROCE_QP_STATE_ERR)) { + spin_unlock_irqrestore(&qp->q_lock, flags); + *bad_wr = wr; + DP_DEBUG(dev, QEDR_MSG_CQ, + "QP in wrong state! QP icid=0x%x state %d\n", + qp->icid, qp->state); + return -EINVAL; + } + + if (!wr) { + DP_ERR(dev, "Got an empty post send.\n"); + return -EINVAL; + } + + while (wr) { + rc = __qedr_post_send(ibqp, wr, bad_wr); + if (rc) + break; + + qp->wqe_wr_id[qp->sq.prod].wr_id = wr->wr_id; + + qedr_inc_sw_prod(&qp->sq); + + qp->sq.db_data.data.value++; + + wr = wr->next; + } + + /* Trigger doorbell + * If there was a failure in the first WR then it will be triggered in + * vane. However this is not harmful (as long as the producer value is + * unchanged). For performance reasons we avoid checking for this + * redundant doorbell. + */ + wmb(); + writel(qp->sq.db_data.raw, qp->sq.db); + + /* Make sure write sticks */ + mmiowb(); + + spin_unlock_irqrestore(&qp->q_lock, flags); + + return rc; +} + +int qedr_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct qedr_qp *qp = get_qedr_qp(ibqp); + struct qedr_dev *dev = qp->dev; + unsigned long flags; + int status = 0; + + spin_lock_irqsave(&qp->q_lock, flags); + + if ((qp->state == QED_ROCE_QP_STATE_RESET) || + (qp->state == QED_ROCE_QP_STATE_ERR)) { + spin_unlock_irqrestore(&qp->q_lock, flags); + *bad_wr = wr; + return -EINVAL; + } + + while (wr) { + int i; + + if (qed_chain_get_elem_left_u32(&qp->rq.pbl) < + QEDR_MAX_RQE_ELEMENTS_PER_RQE || + wr->num_sge > qp->rq.max_sges) { + DP_ERR(dev, "Can't post WR (%d < %d) || (%d > %d)\n", + qed_chain_get_elem_left_u32(&qp->rq.pbl), + QEDR_MAX_RQE_ELEMENTS_PER_RQE, wr->num_sge, + qp->rq.max_sges); + status = -ENOMEM; + *bad_wr = wr; + break; + } + for (i = 0; i < wr->num_sge; i++) { + u32 flags = 0; + struct rdma_rq_sge *rqe = + qed_chain_produce(&qp->rq.pbl); + + /* First one must include the number + * of SGE in the list + */ + if (!i) + SET_FIELD(flags, RDMA_RQ_SGE_NUM_SGES, + wr->num_sge); + + SET_FIELD(flags, RDMA_RQ_SGE_L_KEY, + wr->sg_list[i].lkey); + + RQ_SGE_SET(rqe, wr->sg_list[i].addr, + wr->sg_list[i].length, flags); + } + + /* Special case of no sges. FW requires between 1-4 sges... + * in this case we need to post 1 sge with length zero. this is + * because rdma write with immediate consumes an RQ. + */ + if (!wr->num_sge) { + u32 flags = 0; + struct rdma_rq_sge *rqe = + qed_chain_produce(&qp->rq.pbl); + + /* First one must include the number + * of SGE in the list + */ + SET_FIELD(flags, RDMA_RQ_SGE_L_KEY, 0); + SET_FIELD(flags, RDMA_RQ_SGE_NUM_SGES, 1); + + RQ_SGE_SET(rqe, 0, 0, flags); + i = 1; + } + + qp->rqe_wr_id[qp->rq.prod].wr_id = wr->wr_id; + qp->rqe_wr_id[qp->rq.prod].wqe_size = i; + + qedr_inc_sw_prod(&qp->rq); + + /* Flush all the writes before signalling doorbell */ + wmb(); + + qp->rq.db_data.data.value++; + + writel(qp->rq.db_data.raw, qp->rq.db); + + /* Make sure write sticks */ + mmiowb(); + + wr = wr->next; + } + + spin_unlock_irqrestore(&qp->q_lock, flags); + + return status; +} + +static int is_valid_cqe(struct qedr_cq *cq, union rdma_cqe *cqe) +{ + struct rdma_cqe_requester *resp_cqe = &cqe->req; + + return (resp_cqe->flags & RDMA_CQE_REQUESTER_TOGGLE_BIT_MASK) == + cq->pbl_toggle; +} + +static struct qedr_qp *cqe_get_qp(union rdma_cqe *cqe) +{ + struct rdma_cqe_requester *resp_cqe = &cqe->req; + struct qedr_qp *qp; + + qp = (struct qedr_qp *)(uintptr_t)HILO_GEN(resp_cqe->qp_handle.hi, + resp_cqe->qp_handle.lo, + u64); + return qp; +} + +static enum rdma_cqe_type cqe_get_type(union rdma_cqe *cqe) +{ + struct rdma_cqe_requester *resp_cqe = &cqe->req; + + return GET_FIELD(resp_cqe->flags, RDMA_CQE_REQUESTER_TYPE); +} + +/* Return latest CQE (needs processing) */ +static union rdma_cqe *get_cqe(struct qedr_cq *cq) +{ + return cq->latest_cqe; +} + +/* In fmr we need to increase the number of fmr completed counter for the fmr + * algorithm determining whether we can free a pbl or not. + * we need to perform this whether the work request was signaled or not. for + * this purpose we call this function from the condition that checks if a wr + * should be skipped, to make sure we don't miss it ( possibly this fmr + * operation was not signalted) + */ +static inline void qedr_chk_if_fmr(struct qedr_qp *qp) +{ + if (qp->wqe_wr_id[qp->sq.cons].opcode == IB_WC_REG_MR) + qp->wqe_wr_id[qp->sq.cons].mr->info.completed++; +} + +static int process_req(struct qedr_dev *dev, struct qedr_qp *qp, + struct qedr_cq *cq, int num_entries, + struct ib_wc *wc, u16 hw_cons, enum ib_wc_status status, + int force) +{ + u16 cnt = 0; + + while (num_entries && qp->sq.wqe_cons != hw_cons) { + if (!qp->wqe_wr_id[qp->sq.cons].signaled && !force) { + qedr_chk_if_fmr(qp); + /* skip WC */ + goto next_cqe; + } + + /* fill WC */ + wc->status = status; + wc->wc_flags = 0; + wc->src_qp = qp->id; + wc->qp = &qp->ibqp; + + wc->wr_id = qp->wqe_wr_id[qp->sq.cons].wr_id; + wc->opcode = qp->wqe_wr_id[qp->sq.cons].opcode; + + switch (wc->opcode) { + case IB_WC_RDMA_WRITE: + wc->byte_len = qp->wqe_wr_id[qp->sq.cons].bytes_len; + break; + case IB_WC_COMP_SWAP: + case IB_WC_FETCH_ADD: + wc->byte_len = 8; + break; + case IB_WC_REG_MR: + qp->wqe_wr_id[qp->sq.cons].mr->info.completed++; + break; + default: + break; + } + + num_entries--; + wc++; + cnt++; +next_cqe: + while (qp->wqe_wr_id[qp->sq.cons].wqe_size--) + qed_chain_consume(&qp->sq.pbl); + qedr_inc_sw_cons(&qp->sq); + } + + return cnt; +} + +static int qedr_poll_cq_req(struct qedr_dev *dev, + struct qedr_qp *qp, struct qedr_cq *cq, + int num_entries, struct ib_wc *wc, + struct rdma_cqe_requester *req) +{ + int cnt = 0; + + switch (req->status) { + case RDMA_CQE_REQ_STS_OK: + cnt = process_req(dev, qp, cq, num_entries, wc, req->sq_cons, + IB_WC_SUCCESS, 0); + break; + case RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR: + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + cnt = process_req(dev, qp, cq, num_entries, wc, req->sq_cons, + IB_WC_WR_FLUSH_ERR, 0); + break; + default: + /* process all WQE before the cosumer */ + qp->state = QED_ROCE_QP_STATE_ERR; + cnt = process_req(dev, qp, cq, num_entries, wc, + req->sq_cons - 1, IB_WC_SUCCESS, 0); + wc += cnt; + /* if we have extra WC fill it with actual error info */ + if (cnt < num_entries) { + enum ib_wc_status wc_status; + + switch (req->status) { + case RDMA_CQE_REQ_STS_BAD_RESPONSE_ERR: + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_BAD_RESPONSE_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_BAD_RESP_ERR; + break; + case RDMA_CQE_REQ_STS_LOCAL_LENGTH_ERR: + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_LOCAL_LENGTH_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_LOC_LEN_ERR; + break; + case RDMA_CQE_REQ_STS_LOCAL_QP_OPERATION_ERR: + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_LOCAL_QP_OPERATION_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_LOC_QP_OP_ERR; + break; + case RDMA_CQE_REQ_STS_LOCAL_PROTECTION_ERR: + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_LOCAL_PROTECTION_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_LOC_PROT_ERR; + break; + case RDMA_CQE_REQ_STS_MEMORY_MGT_OPERATION_ERR: + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_MEMORY_MGT_OPERATION_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_MW_BIND_ERR; + break; + case RDMA_CQE_REQ_STS_REMOTE_INVALID_REQUEST_ERR: + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_REMOTE_INVALID_REQUEST_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_REM_INV_REQ_ERR; + break; + case RDMA_CQE_REQ_STS_REMOTE_ACCESS_ERR: + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_REMOTE_ACCESS_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_REM_ACCESS_ERR; + break; + case RDMA_CQE_REQ_STS_REMOTE_OPERATION_ERR: + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_REMOTE_OPERATION_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_REM_OP_ERR; + break; + case RDMA_CQE_REQ_STS_RNR_NAK_RETRY_CNT_ERR: + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_RNR_NAK_RETRY_CNT_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_RNR_RETRY_EXC_ERR; + break; + case RDMA_CQE_REQ_STS_TRANSPORT_RETRY_CNT_ERR: + DP_ERR(dev, + "Error: POLL CQ with ROCE_CQE_REQ_STS_TRANSPORT_RETRY_CNT_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_RETRY_EXC_ERR; + break; + default: + DP_ERR(dev, + "Error: POLL CQ with IB_WC_GENERAL_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); + wc_status = IB_WC_GENERAL_ERR; + } + cnt += process_req(dev, qp, cq, 1, wc, req->sq_cons, + wc_status, 1); + } + } + + return cnt; +} + +static void __process_resp_one(struct qedr_dev *dev, struct qedr_qp *qp, + struct qedr_cq *cq, struct ib_wc *wc, + struct rdma_cqe_responder *resp, u64 wr_id) +{ + enum ib_wc_status wc_status = IB_WC_SUCCESS; + u8 flags; + + wc->opcode = IB_WC_RECV; + wc->wc_flags = 0; + + switch (resp->status) { + case RDMA_CQE_RESP_STS_LOCAL_ACCESS_ERR: + wc_status = IB_WC_LOC_ACCESS_ERR; + break; + case RDMA_CQE_RESP_STS_LOCAL_LENGTH_ERR: + wc_status = IB_WC_LOC_LEN_ERR; + break; + case RDMA_CQE_RESP_STS_LOCAL_QP_OPERATION_ERR: + wc_status = IB_WC_LOC_QP_OP_ERR; + break; + case RDMA_CQE_RESP_STS_LOCAL_PROTECTION_ERR: + wc_status = IB_WC_LOC_PROT_ERR; + break; + case RDMA_CQE_RESP_STS_MEMORY_MGT_OPERATION_ERR: + wc_status = IB_WC_MW_BIND_ERR; + break; + case RDMA_CQE_RESP_STS_REMOTE_INVALID_REQUEST_ERR: + wc_status = IB_WC_REM_INV_RD_REQ_ERR; + break; + case RDMA_CQE_RESP_STS_OK: + wc_status = IB_WC_SUCCESS; + wc->byte_len = le32_to_cpu(resp->length); + + flags = resp->flags & QEDR_RESP_RDMA_IMM; + + if (flags == QEDR_RESP_RDMA_IMM) + wc->opcode = IB_WC_RECV_RDMA_WITH_IMM; + + if (flags == QEDR_RESP_RDMA_IMM || flags == QEDR_RESP_IMM) { + wc->ex.imm_data = + le32_to_cpu(resp->imm_data_or_inv_r_Key); + wc->wc_flags |= IB_WC_WITH_IMM; + } + break; + default: + wc->status = IB_WC_GENERAL_ERR; + DP_ERR(dev, "Invalid CQE status detected\n"); + } + + /* fill WC */ + wc->status = wc_status; + wc->src_qp = qp->id; + wc->qp = &qp->ibqp; + wc->wr_id = wr_id; +} + +static int process_resp_one(struct qedr_dev *dev, struct qedr_qp *qp, + struct qedr_cq *cq, struct ib_wc *wc, + struct rdma_cqe_responder *resp) +{ + u64 wr_id = qp->rqe_wr_id[qp->rq.cons].wr_id; + + __process_resp_one(dev, qp, cq, wc, resp, wr_id); + + while (qp->rqe_wr_id[qp->rq.cons].wqe_size--) + qed_chain_consume(&qp->rq.pbl); + qedr_inc_sw_cons(&qp->rq); + + return 1; +} + +static int process_resp_flush(struct qedr_qp *qp, struct qedr_cq *cq, + int num_entries, struct ib_wc *wc, u16 hw_cons) +{ + u16 cnt = 0; + + while (num_entries && qp->rq.wqe_cons != hw_cons) { + /* fill WC */ + wc->status = IB_WC_WR_FLUSH_ERR; + wc->wc_flags = 0; + wc->src_qp = qp->id; + wc->byte_len = 0; + wc->wr_id = qp->rqe_wr_id[qp->rq.cons].wr_id; + wc->qp = &qp->ibqp; + num_entries--; + wc++; + cnt++; + while (qp->rqe_wr_id[qp->rq.cons].wqe_size--) + qed_chain_consume(&qp->rq.pbl); + qedr_inc_sw_cons(&qp->rq); + } + + return cnt; +} + +static void try_consume_resp_cqe(struct qedr_cq *cq, struct qedr_qp *qp, + struct rdma_cqe_responder *resp, int *update) +{ + if (le16_to_cpu(resp->rq_cons) == qp->rq.wqe_cons) { + consume_cqe(cq); + *update |= 1; + } +} + +static int qedr_poll_cq_resp(struct qedr_dev *dev, struct qedr_qp *qp, + struct qedr_cq *cq, int num_entries, + struct ib_wc *wc, struct rdma_cqe_responder *resp, + int *update) +{ + int cnt; + + if (resp->status == RDMA_CQE_RESP_STS_WORK_REQUEST_FLUSHED_ERR) { + cnt = process_resp_flush(qp, cq, num_entries, wc, + resp->rq_cons); + try_consume_resp_cqe(cq, qp, resp, update); + } else { + cnt = process_resp_one(dev, qp, cq, wc, resp); + consume_cqe(cq); + *update |= 1; + } + + return cnt; +} + +static void try_consume_req_cqe(struct qedr_cq *cq, struct qedr_qp *qp, + struct rdma_cqe_requester *req, int *update) +{ + if (le16_to_cpu(req->sq_cons) == qp->sq.wqe_cons) { + consume_cqe(cq); + *update |= 1; + } +} + +int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) +{ + struct qedr_dev *dev = get_qedr_dev(ibcq->device); + struct qedr_cq *cq = get_qedr_cq(ibcq); + union rdma_cqe *cqe = cq->latest_cqe; + u32 old_cons, new_cons; + unsigned long flags; + int update = 0; + int done = 0; + + spin_lock_irqsave(&cq->cq_lock, flags); + old_cons = qed_chain_get_cons_idx_u32(&cq->pbl); + while (num_entries && is_valid_cqe(cq, cqe)) { + struct qedr_qp *qp; + int cnt = 0; + + /* prevent speculative reads of any field of CQE */ + rmb(); + + qp = cqe_get_qp(cqe); + if (!qp) { + WARN(1, "Error: CQE QP pointer is NULL. CQE=%p\n", cqe); + break; + } + + wc->qp = &qp->ibqp; + + switch (cqe_get_type(cqe)) { + case RDMA_CQE_TYPE_REQUESTER: + cnt = qedr_poll_cq_req(dev, qp, cq, num_entries, wc, + &cqe->req); + try_consume_req_cqe(cq, qp, &cqe->req, &update); + break; + case RDMA_CQE_TYPE_RESPONDER_RQ: + cnt = qedr_poll_cq_resp(dev, qp, cq, num_entries, wc, + &cqe->resp, &update); + break; + case RDMA_CQE_TYPE_INVALID: + default: + DP_ERR(dev, "Error: invalid CQE type = %d\n", + cqe_get_type(cqe)); + } + num_entries -= cnt; + wc += cnt; + done += cnt; + + cqe = get_cqe(cq); + } + new_cons = qed_chain_get_cons_idx_u32(&cq->pbl); + + cq->cq_cons += new_cons - old_cons; + + if (update) + /* doorbell notifies abount latest VALID entry, + * but chain already point to the next INVALID one + */ + doorbell_cq(cq, cq->cq_cons - 1, cq->arm_flags); + + spin_unlock_irqrestore(&cq->cq_lock, flags); + return done; +} diff --git a/drivers/infiniband/hw/qedr/verbs.h b/drivers/infiniband/hw/qedr/verbs.h index 4853f4af99837..fb9b751a6dde3 100644 --- a/drivers/infiniband/hw/qedr/verbs.h +++ b/drivers/infiniband/hw/qedr/verbs.h @@ -81,4 +81,9 @@ int qedr_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, struct ib_mr *qedr_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, u32 max_num_sg); +int qedr_poll_cq(struct ib_cq *, int num_entries, struct ib_wc *wc); +int qedr_post_send(struct ib_qp *, struct ib_send_wr *, + struct ib_send_wr **bad_wr); +int qedr_post_recv(struct ib_qp *, struct ib_recv_wr *, + struct ib_recv_wr **bad_wr); #endif -- GitLab From 1d1424c8f834e4e3b8792d310a94b0e2e8f59b4c Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 10 Oct 2016 13:15:37 +0300 Subject: [PATCH 0568/1167] qedr: Add LL2 RoCE interface Add light L2 interface for RoCE. Signed-off-by: Rajesh Borundia Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/main.c | 34 ++++++++++++++++++++++++++++++- drivers/infiniband/hw/qedr/qedr.h | 2 +- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 858cc354153dd..e5a07a2d4c5e9 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -724,6 +724,38 @@ static void qedr_shutdown(struct qedr_dev *dev) qedr_remove(dev); } +static void qedr_mac_address_change(struct qedr_dev *dev) +{ + union ib_gid *sgid = &dev->sgid_tbl[0]; + u8 guid[8], mac_addr[6]; + int rc; + + /* Update SGID */ + ether_addr_copy(&mac_addr[0], dev->ndev->dev_addr); + guid[0] = mac_addr[0] ^ 2; + guid[1] = mac_addr[1]; + guid[2] = mac_addr[2]; + guid[3] = 0xff; + guid[4] = 0xfe; + guid[5] = mac_addr[3]; + guid[6] = mac_addr[4]; + guid[7] = mac_addr[5]; + sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); + memcpy(&sgid->raw[8], guid, sizeof(guid)); + + /* Update LL2 */ + rc = dev->ops->roce_ll2_set_mac_filter(dev->cdev, + dev->gsi_ll2_mac_address, + dev->ndev->dev_addr); + + ether_addr_copy(dev->gsi_ll2_mac_address, dev->ndev->dev_addr); + + qedr_ib_dispatch_event(dev, 1, IB_EVENT_GID_CHANGE); + + if (rc) + DP_ERR(dev, "Error updating mac filter\n"); +} + /* event handling via NIC driver ensures that all the NIC specific * initialization done before RoCE driver notifies * event to stack. @@ -741,7 +773,7 @@ static void qedr_notify(struct qedr_dev *dev, enum qede_roce_event event) qedr_shutdown(dev); break; case QEDE_CHANGE_ADDR: - qedr_ib_dispatch_event(dev, 1, IB_EVENT_GID_CHANGE); + qedr_mac_address_change(dev); break; default: pr_err("Event not supported\n"); diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 775dbf16fdf28..0b404d87921f1 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -147,7 +147,7 @@ struct qedr_dev { u8 dp_level; u8 num_hwfns; uint wq_multiplier; - + u8 gsi_ll2_mac_address[ETH_ALEN]; }; #define QEDR_MAX_SQ_PBL (0x8000) -- GitLab From 048867793046e6bd665869816f4702fc49cc9a18 Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 10 Oct 2016 13:15:38 +0300 Subject: [PATCH 0569/1167] qedr: Add GSI support Add support for GSI over light L2. Signed-off-by: Rajesh Borundia Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/Makefile | 2 +- drivers/infiniband/hw/qedr/main.c | 3 + drivers/infiniband/hw/qedr/qedr.h | 15 + drivers/infiniband/hw/qedr/qedr_cm.c | 622 +++++++++++++++++++++++++++ drivers/infiniband/hw/qedr/qedr_cm.h | 21 + drivers/infiniband/hw/qedr/verbs.c | 41 ++ drivers/infiniband/hw/qedr/verbs.h | 3 + 7 files changed, 706 insertions(+), 1 deletion(-) create mode 100644 drivers/infiniband/hw/qedr/qedr_cm.c diff --git a/drivers/infiniband/hw/qedr/Makefile b/drivers/infiniband/hw/qedr/Makefile index b10f2b17ada5c..ba7067c77f2f6 100644 --- a/drivers/infiniband/hw/qedr/Makefile +++ b/drivers/infiniband/hw/qedr/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_INFINIBAND_QEDR) := qedr.o -qedr-y := main.o verbs.o +qedr-y := main.o verbs.o qedr_cm.o diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index e5a07a2d4c5e9..42dff48a31712 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -138,6 +138,9 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.query_pkey = qedr_query_pkey; + dev->ibdev.create_ah = qedr_create_ah; + dev->ibdev.destroy_ah = qedr_destroy_ah; + dev->ibdev.get_dma_mr = qedr_get_dma_mr; dev->ibdev.dereg_mr = qedr_dereg_mr; dev->ibdev.reg_user_mr = qedr_reg_user_mr; diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 0b404d87921f1..620badd7d4fbd 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -55,6 +55,7 @@ #define QEDR_MSG_RQ " RQ" #define QEDR_MSG_SQ " SQ" #define QEDR_MSG_QP " QP" +#define QEDR_MSG_GSI " GSI" #define QEDR_CQ_MAGIC_NUMBER (0x11223344) @@ -148,6 +149,10 @@ struct qedr_dev { u8 num_hwfns; uint wq_multiplier; u8 gsi_ll2_mac_address[ETH_ALEN]; + int gsi_qp_created; + struct qedr_cq *gsi_sqcq; + struct qedr_cq *gsi_rqcq; + struct qedr_qp *gsi_qp; }; #define QEDR_MAX_SQ_PBL (0x8000) @@ -246,6 +251,9 @@ struct qedr_cq { u16 icid; + /* Lock to protect completion handler */ + spinlock_t comp_handler_lock; + /* Lock to protect multiplem CQ's */ spinlock_t cq_lock; u8 arm_flags; @@ -292,6 +300,7 @@ struct qedr_qp_hwq_info { u16 prod; u16 cons; u16 wqe_cons; + u16 gsi_cons; u16 max_wr; /* DB */ @@ -366,6 +375,7 @@ struct qedr_qp { struct ib_sge sg_list[RDMA_MAX_SGE_PER_RQ_WQE]; u8 wqe_size; + u8 smac[ETH_ALEN]; u16 vlan_id; int rc; } *rqe_wr_id; @@ -473,6 +483,11 @@ static inline struct qedr_qp *get_qedr_qp(struct ib_qp *ibqp) return container_of(ibqp, struct qedr_qp, ibqp); } +static inline struct qedr_ah *get_qedr_ah(struct ib_ah *ibah) +{ + return container_of(ibah, struct qedr_ah, ibah); +} + static inline struct qedr_mr *get_qedr_mr(struct ib_mr *ibmr) { return container_of(ibmr, struct qedr_mr, ibmr); diff --git a/drivers/infiniband/hw/qedr/qedr_cm.c b/drivers/infiniband/hw/qedr/qedr_cm.c new file mode 100644 index 0000000000000..63890ebb72bdf --- /dev/null +++ b/drivers/infiniband/hw/qedr/qedr_cm.c @@ -0,0 +1,622 @@ +/* QLogic qedr NIC Driver + * Copyright (c) 2015-2016 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "qedr_hsi.h" +#include +#include +#include "qedr.h" +#include "qedr_hsi.h" +#include "verbs.h" +#include +#include "qedr_hsi.h" +#include "qedr_cm.h" + +void qedr_inc_sw_gsi_cons(struct qedr_qp_hwq_info *info) +{ + info->gsi_cons = (info->gsi_cons + 1) % info->max_wr; +} + +void qedr_store_gsi_qp_cq(struct qedr_dev *dev, struct qedr_qp *qp, + struct ib_qp_init_attr *attrs) +{ + dev->gsi_qp_created = 1; + dev->gsi_sqcq = get_qedr_cq(attrs->send_cq); + dev->gsi_rqcq = get_qedr_cq(attrs->recv_cq); + dev->gsi_qp = qp; +} + +void qedr_ll2_tx_cb(void *_qdev, struct qed_roce_ll2_packet *pkt) +{ + struct qedr_dev *dev = (struct qedr_dev *)_qdev; + struct qedr_cq *cq = dev->gsi_sqcq; + struct qedr_qp *qp = dev->gsi_qp; + unsigned long flags; + + DP_DEBUG(dev, QEDR_MSG_GSI, + "LL2 TX CB: gsi_sqcq=%p, gsi_rqcq=%p, gsi_cons=%d, ibcq_comp=%s\n", + dev->gsi_sqcq, dev->gsi_rqcq, qp->sq.gsi_cons, + cq->ibcq.comp_handler ? "Yes" : "No"); + + dma_free_coherent(&dev->pdev->dev, pkt->header.len, pkt->header.vaddr, + pkt->header.baddr); + kfree(pkt); + + spin_lock_irqsave(&qp->q_lock, flags); + qedr_inc_sw_gsi_cons(&qp->sq); + spin_unlock_irqrestore(&qp->q_lock, flags); + + if (cq->ibcq.comp_handler) { + spin_lock_irqsave(&cq->comp_handler_lock, flags); + (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); + spin_unlock_irqrestore(&cq->comp_handler_lock, flags); + } +} + +void qedr_ll2_rx_cb(void *_dev, struct qed_roce_ll2_packet *pkt, + struct qed_roce_ll2_rx_params *params) +{ + struct qedr_dev *dev = (struct qedr_dev *)_dev; + struct qedr_cq *cq = dev->gsi_rqcq; + struct qedr_qp *qp = dev->gsi_qp; + unsigned long flags; + + spin_lock_irqsave(&qp->q_lock, flags); + + qp->rqe_wr_id[qp->rq.gsi_cons].rc = params->rc; + qp->rqe_wr_id[qp->rq.gsi_cons].vlan_id = params->vlan_id; + qp->rqe_wr_id[qp->rq.gsi_cons].sg_list[0].length = pkt->payload[0].len; + ether_addr_copy(qp->rqe_wr_id[qp->rq.gsi_cons].smac, params->smac); + + qedr_inc_sw_gsi_cons(&qp->rq); + + spin_unlock_irqrestore(&qp->q_lock, flags); + + if (cq->ibcq.comp_handler) { + spin_lock_irqsave(&cq->comp_handler_lock, flags); + (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); + spin_unlock_irqrestore(&cq->comp_handler_lock, flags); + } +} + +static void qedr_destroy_gsi_cq(struct qedr_dev *dev, + struct ib_qp_init_attr *attrs) +{ + struct qed_rdma_destroy_cq_in_params iparams; + struct qed_rdma_destroy_cq_out_params oparams; + struct qedr_cq *cq; + + cq = get_qedr_cq(attrs->send_cq); + iparams.icid = cq->icid; + dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams); + dev->ops->common->chain_free(dev->cdev, &cq->pbl); + + cq = get_qedr_cq(attrs->recv_cq); + /* if a dedicated recv_cq was used, delete it too */ + if (iparams.icid != cq->icid) { + iparams.icid = cq->icid; + dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams); + dev->ops->common->chain_free(dev->cdev, &cq->pbl); + } +} + +static inline int qedr_check_gsi_qp_attrs(struct qedr_dev *dev, + struct ib_qp_init_attr *attrs) +{ + if (attrs->cap.max_recv_sge > QEDR_GSI_MAX_RECV_SGE) { + DP_ERR(dev, + " create gsi qp: failed. max_recv_sge is larger the max %d>%d\n", + attrs->cap.max_recv_sge, QEDR_GSI_MAX_RECV_SGE); + return -EINVAL; + } + + if (attrs->cap.max_recv_wr > QEDR_GSI_MAX_RECV_WR) { + DP_ERR(dev, + " create gsi qp: failed. max_recv_wr is too large %d>%d\n", + attrs->cap.max_recv_wr, QEDR_GSI_MAX_RECV_WR); + return -EINVAL; + } + + if (attrs->cap.max_send_wr > QEDR_GSI_MAX_SEND_WR) { + DP_ERR(dev, + " create gsi qp: failed. max_send_wr is too large %d>%d\n", + attrs->cap.max_send_wr, QEDR_GSI_MAX_SEND_WR); + return -EINVAL; + } + + return 0; +} + +struct ib_qp *qedr_create_gsi_qp(struct qedr_dev *dev, + struct ib_qp_init_attr *attrs, + struct qedr_qp *qp) +{ + struct qed_roce_ll2_params ll2_params; + int rc; + + rc = qedr_check_gsi_qp_attrs(dev, attrs); + if (rc) + return ERR_PTR(rc); + + /* configure and start LL2 */ + memset(&ll2_params, 0, sizeof(ll2_params)); + ll2_params.max_tx_buffers = attrs->cap.max_send_wr; + ll2_params.max_rx_buffers = attrs->cap.max_recv_wr; + ll2_params.cbs.tx_cb = qedr_ll2_tx_cb; + ll2_params.cbs.rx_cb = qedr_ll2_rx_cb; + ll2_params.cb_cookie = (void *)dev; + ll2_params.mtu = dev->ndev->mtu; + ether_addr_copy(ll2_params.mac_address, dev->ndev->dev_addr); + rc = dev->ops->roce_ll2_start(dev->cdev, &ll2_params); + if (rc) { + DP_ERR(dev, "create gsi qp: failed on ll2 start. rc=%d\n", rc); + return ERR_PTR(rc); + } + + /* create QP */ + qp->ibqp.qp_num = 1; + qp->rq.max_wr = attrs->cap.max_recv_wr; + qp->sq.max_wr = attrs->cap.max_send_wr; + + qp->rqe_wr_id = kcalloc(qp->rq.max_wr, sizeof(*qp->rqe_wr_id), + GFP_KERNEL); + if (!qp->rqe_wr_id) + goto err; + qp->wqe_wr_id = kcalloc(qp->sq.max_wr, sizeof(*qp->wqe_wr_id), + GFP_KERNEL); + if (!qp->wqe_wr_id) + goto err; + + qedr_store_gsi_qp_cq(dev, qp, attrs); + ether_addr_copy(dev->gsi_ll2_mac_address, dev->ndev->dev_addr); + + /* the GSI CQ is handled by the driver so remove it from the FW */ + qedr_destroy_gsi_cq(dev, attrs); + dev->gsi_rqcq->cq_type = QEDR_CQ_TYPE_GSI; + dev->gsi_rqcq->cq_type = QEDR_CQ_TYPE_GSI; + + DP_DEBUG(dev, QEDR_MSG_GSI, "created GSI QP %p\n", qp); + + return &qp->ibqp; + +err: + kfree(qp->rqe_wr_id); + + rc = dev->ops->roce_ll2_stop(dev->cdev); + if (rc) + DP_ERR(dev, "create gsi qp: failed destroy on create\n"); + + return ERR_PTR(-ENOMEM); +} + +int qedr_destroy_gsi_qp(struct qedr_dev *dev) +{ + int rc; + + rc = dev->ops->roce_ll2_stop(dev->cdev); + if (rc) + DP_ERR(dev, "destroy gsi qp: failed (rc=%d)\n", rc); + else + DP_DEBUG(dev, QEDR_MSG_GSI, "destroy gsi qp: success\n"); + + return rc; +} + +#define QEDR_MAX_UD_HEADER_SIZE (100) +#define QEDR_GSI_QPN (1) +static inline int qedr_gsi_build_header(struct qedr_dev *dev, + struct qedr_qp *qp, + struct ib_send_wr *swr, + struct ib_ud_header *udh, + int *roce_mode) +{ + bool has_vlan = false, has_grh_ipv6 = true; + struct ib_ah_attr *ah_attr = &get_qedr_ah(ud_wr(swr)->ah)->attr; + struct ib_global_route *grh = &ah_attr->grh; + union ib_gid sgid; + int send_size = 0; + u16 vlan_id = 0; + u16 ether_type; + struct ib_gid_attr sgid_attr; + int rc; + int ip_ver = 0; + + bool has_udp = false; + int i; + + send_size = 0; + for (i = 0; i < swr->num_sge; ++i) + send_size += swr->sg_list[i].length; + + rc = ib_get_cached_gid(qp->ibqp.device, ah_attr->port_num, + grh->sgid_index, &sgid, &sgid_attr); + if (rc) { + DP_ERR(dev, + "gsi post send: failed to get cached GID (port=%d, ix=%d)\n", + ah_attr->port_num, grh->sgid_index); + return rc; + } + + vlan_id = rdma_vlan_dev_vlan_id(sgid_attr.ndev); + if (vlan_id < VLAN_CFI_MASK) + has_vlan = true; + if (sgid_attr.ndev) + dev_put(sgid_attr.ndev); + + if (!memcmp(&sgid, &zgid, sizeof(sgid))) { + DP_ERR(dev, "gsi post send: GID not found GID index %d\n", + ah_attr->grh.sgid_index); + return -ENOENT; + } + + has_udp = (sgid_attr.gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP); + if (!has_udp) { + /* RoCE v1 */ + ether_type = ETH_P_ROCE; + *roce_mode = ROCE_V1; + } else if (ipv6_addr_v4mapped((struct in6_addr *)&sgid)) { + /* RoCE v2 IPv4 */ + ip_ver = 4; + ether_type = ETH_P_IP; + has_grh_ipv6 = false; + *roce_mode = ROCE_V2_IPV4; + } else { + /* RoCE v2 IPv6 */ + ip_ver = 6; + ether_type = ETH_P_IPV6; + *roce_mode = ROCE_V2_IPV6; + } + + rc = ib_ud_header_init(send_size, false, true, has_vlan, + has_grh_ipv6, ip_ver, has_udp, 0, udh); + if (rc) { + DP_ERR(dev, "gsi post send: failed to init header\n"); + return rc; + } + + /* ENET + VLAN headers */ + ether_addr_copy(udh->eth.dmac_h, ah_attr->dmac); + ether_addr_copy(udh->eth.smac_h, dev->ndev->dev_addr); + if (has_vlan) { + udh->eth.type = htons(ETH_P_8021Q); + udh->vlan.tag = htons(vlan_id); + udh->vlan.type = htons(ether_type); + } else { + udh->eth.type = htons(ether_type); + } + + /* BTH */ + udh->bth.solicited_event = !!(swr->send_flags & IB_SEND_SOLICITED); + udh->bth.pkey = QEDR_ROCE_PKEY_DEFAULT; + udh->bth.destination_qpn = htonl(ud_wr(swr)->remote_qpn); + udh->bth.psn = htonl((qp->sq_psn++) & ((1 << 24) - 1)); + udh->bth.opcode = IB_OPCODE_UD_SEND_ONLY; + + /* DETH */ + udh->deth.qkey = htonl(0x80010000); + udh->deth.source_qpn = htonl(QEDR_GSI_QPN); + + if (has_grh_ipv6) { + /* GRH / IPv6 header */ + udh->grh.traffic_class = grh->traffic_class; + udh->grh.flow_label = grh->flow_label; + udh->grh.hop_limit = grh->hop_limit; + udh->grh.destination_gid = grh->dgid; + memcpy(&udh->grh.source_gid.raw, &sgid.raw, + sizeof(udh->grh.source_gid.raw)); + } else { + /* IPv4 header */ + u32 ipv4_addr; + + udh->ip4.protocol = IPPROTO_UDP; + udh->ip4.tos = htonl(ah_attr->grh.flow_label); + udh->ip4.frag_off = htons(IP_DF); + udh->ip4.ttl = ah_attr->grh.hop_limit; + + ipv4_addr = qedr_get_ipv4_from_gid(sgid.raw); + udh->ip4.saddr = ipv4_addr; + ipv4_addr = qedr_get_ipv4_from_gid(ah_attr->grh.dgid.raw); + udh->ip4.daddr = ipv4_addr; + /* note: checksum is calculated by the device */ + } + + /* UDP */ + if (has_udp) { + udh->udp.sport = htons(QEDR_ROCE_V2_UDP_SPORT); + udh->udp.dport = htons(ROCE_V2_UDP_DPORT); + udh->udp.csum = 0; + /* UDP length is untouched hence is zero */ + } + return 0; +} + +static inline int qedr_gsi_build_packet(struct qedr_dev *dev, + struct qedr_qp *qp, + struct ib_send_wr *swr, + struct qed_roce_ll2_packet **p_packet) +{ + u8 ud_header_buffer[QEDR_MAX_UD_HEADER_SIZE]; + struct qed_roce_ll2_packet *packet; + struct pci_dev *pdev = dev->pdev; + int roce_mode, header_size; + struct ib_ud_header udh; + int i, rc; + + *p_packet = NULL; + + rc = qedr_gsi_build_header(dev, qp, swr, &udh, &roce_mode); + if (rc) + return rc; + + header_size = ib_ud_header_pack(&udh, &ud_header_buffer); + + packet = kzalloc(sizeof(*packet), GFP_ATOMIC); + if (!packet) + return -ENOMEM; + + packet->header.vaddr = dma_alloc_coherent(&pdev->dev, header_size, + &packet->header.baddr, + GFP_ATOMIC); + if (!packet->header.vaddr) { + kfree(packet); + return -ENOMEM; + } + + if (ether_addr_equal(udh.eth.smac_h, udh.eth.dmac_h)) + packet->tx_dest = QED_ROCE_LL2_TX_DEST_NW; + else + packet->tx_dest = QED_ROCE_LL2_TX_DEST_LB; + + packet->roce_mode = roce_mode; + memcpy(packet->header.vaddr, ud_header_buffer, header_size); + packet->header.len = header_size; + packet->n_seg = swr->num_sge; + for (i = 0; i < packet->n_seg; i++) { + packet->payload[i].baddr = swr->sg_list[i].addr; + packet->payload[i].len = swr->sg_list[i].length; + } + + *p_packet = packet; + + return 0; +} + +int qedr_gsi_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + struct qed_roce_ll2_packet *pkt = NULL; + struct qedr_qp *qp = get_qedr_qp(ibqp); + struct qed_roce_ll2_tx_params params; + struct qedr_dev *dev = qp->dev; + unsigned long flags; + int rc; + + if (qp->state != QED_ROCE_QP_STATE_RTS) { + *bad_wr = wr; + DP_ERR(dev, + "gsi post recv: failed to post rx buffer. state is %d and not QED_ROCE_QP_STATE_RTS\n", + qp->state); + return -EINVAL; + } + + if (wr->num_sge > RDMA_MAX_SGE_PER_SQ_WQE) { + DP_ERR(dev, "gsi post send: num_sge is too large (%d>%d)\n", + wr->num_sge, RDMA_MAX_SGE_PER_SQ_WQE); + rc = -EINVAL; + goto err; + } + + if (wr->opcode != IB_WR_SEND) { + DP_ERR(dev, + "gsi post send: failed due to unsupported opcode %d\n", + wr->opcode); + rc = -EINVAL; + goto err; + } + + memset(¶ms, 0, sizeof(params)); + + spin_lock_irqsave(&qp->q_lock, flags); + + rc = qedr_gsi_build_packet(dev, qp, wr, &pkt); + if (rc) { + spin_unlock_irqrestore(&qp->q_lock, flags); + goto err; + } + + rc = dev->ops->roce_ll2_tx(dev->cdev, pkt, ¶ms); + if (!rc) { + qp->wqe_wr_id[qp->sq.prod].wr_id = wr->wr_id; + qedr_inc_sw_prod(&qp->sq); + DP_DEBUG(qp->dev, QEDR_MSG_GSI, + "gsi post send: opcode=%d, in_irq=%ld, irqs_disabled=%d, wr_id=%llx\n", + wr->opcode, in_irq(), irqs_disabled(), wr->wr_id); + } else { + if (rc == QED_ROCE_TX_HEAD_FAILURE) { + /* TX failed while posting header - release resources */ + dma_free_coherent(&dev->pdev->dev, pkt->header.len, + pkt->header.vaddr, pkt->header.baddr); + kfree(pkt); + } else if (rc == QED_ROCE_TX_FRAG_FAILURE) { + /* NTD since TX failed while posting a fragment. We will + * release the resources on TX callback + */ + } + + DP_ERR(dev, "gsi post send: failed to transmit (rc=%d)\n", rc); + rc = -EAGAIN; + *bad_wr = wr; + } + + spin_unlock_irqrestore(&qp->q_lock, flags); + + if (wr->next) { + DP_ERR(dev, + "gsi post send: failed second WR. Only one WR may be passed at a time\n"); + *bad_wr = wr->next; + rc = -EINVAL; + } + + return rc; + +err: + *bad_wr = wr; + return rc; +} + +int qedr_gsi_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct qedr_dev *dev = get_qedr_dev(ibqp->device); + struct qedr_qp *qp = get_qedr_qp(ibqp); + struct qed_roce_ll2_buffer buf; + unsigned long flags; + int status = 0; + int rc; + + if ((qp->state != QED_ROCE_QP_STATE_RTR) && + (qp->state != QED_ROCE_QP_STATE_RTS)) { + *bad_wr = wr; + DP_ERR(dev, + "gsi post recv: failed to post rx buffer. state is %d and not QED_ROCE_QP_STATE_RTR/S\n", + qp->state); + return -EINVAL; + } + + memset(&buf, 0, sizeof(buf)); + + spin_lock_irqsave(&qp->q_lock, flags); + + while (wr) { + if (wr->num_sge > QEDR_GSI_MAX_RECV_SGE) { + DP_ERR(dev, + "gsi post recv: failed to post rx buffer. too many sges %d>%d\n", + wr->num_sge, QEDR_GSI_MAX_RECV_SGE); + goto err; + } + + buf.baddr = wr->sg_list[0].addr; + buf.len = wr->sg_list[0].length; + + rc = dev->ops->roce_ll2_post_rx_buffer(dev->cdev, &buf, 0, 1); + if (rc) { + DP_ERR(dev, + "gsi post recv: failed to post rx buffer (rc=%d)\n", + rc); + goto err; + } + + memset(&qp->rqe_wr_id[qp->rq.prod], 0, + sizeof(qp->rqe_wr_id[qp->rq.prod])); + qp->rqe_wr_id[qp->rq.prod].sg_list[0] = wr->sg_list[0]; + qp->rqe_wr_id[qp->rq.prod].wr_id = wr->wr_id; + + qedr_inc_sw_prod(&qp->rq); + + wr = wr->next; + } + + spin_unlock_irqrestore(&qp->q_lock, flags); + + return status; +err: + spin_unlock_irqrestore(&qp->q_lock, flags); + *bad_wr = wr; + return -ENOMEM; +} + +int qedr_gsi_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) +{ + struct qedr_dev *dev = get_qedr_dev(ibcq->device); + struct qedr_cq *cq = get_qedr_cq(ibcq); + struct qedr_qp *qp = dev->gsi_qp; + unsigned long flags; + int i = 0; + + spin_lock_irqsave(&cq->cq_lock, flags); + + while (i < num_entries && qp->rq.cons != qp->rq.gsi_cons) { + memset(&wc[i], 0, sizeof(*wc)); + + wc[i].qp = &qp->ibqp; + wc[i].wr_id = qp->rqe_wr_id[qp->rq.cons].wr_id; + wc[i].opcode = IB_WC_RECV; + wc[i].pkey_index = 0; + wc[i].status = (qp->rqe_wr_id[qp->rq.cons].rc) ? + IB_WC_GENERAL_ERR : IB_WC_SUCCESS; + /* 0 - currently only one recv sg is supported */ + wc[i].byte_len = qp->rqe_wr_id[qp->rq.cons].sg_list[0].length; + wc[i].wc_flags |= IB_WC_GRH | IB_WC_IP_CSUM_OK; + ether_addr_copy(wc[i].smac, qp->rqe_wr_id[qp->rq.cons].smac); + wc[i].wc_flags |= IB_WC_WITH_SMAC; + if (qp->rqe_wr_id[qp->rq.cons].vlan_id) { + wc[i].wc_flags |= IB_WC_WITH_VLAN; + wc[i].vlan_id = qp->rqe_wr_id[qp->rq.cons].vlan_id; + } + + qedr_inc_sw_cons(&qp->rq); + i++; + } + + while (i < num_entries && qp->sq.cons != qp->sq.gsi_cons) { + memset(&wc[i], 0, sizeof(*wc)); + + wc[i].qp = &qp->ibqp; + wc[i].wr_id = qp->wqe_wr_id[qp->sq.cons].wr_id; + wc[i].opcode = IB_WC_SEND; + wc[i].status = IB_WC_SUCCESS; + + qedr_inc_sw_cons(&qp->sq); + i++; + } + + spin_unlock_irqrestore(&cq->cq_lock, flags); + + DP_DEBUG(dev, QEDR_MSG_GSI, + "gsi poll_cq: requested entries=%d, actual=%d, qp->rq.cons=%d, qp->rq.gsi_cons=%x, qp->sq.cons=%d, qp->sq.gsi_cons=%d, qp_num=%d\n", + num_entries, i, qp->rq.cons, qp->rq.gsi_cons, qp->sq.cons, + qp->sq.gsi_cons, qp->ibqp.qp_num); + + return i; +} diff --git a/drivers/infiniband/hw/qedr/qedr_cm.h b/drivers/infiniband/hw/qedr/qedr_cm.h index b8a8b76d77b81..9ba6e15cd93f8 100644 --- a/drivers/infiniband/hw/qedr/qedr_cm.h +++ b/drivers/infiniband/hw/qedr/qedr_cm.h @@ -32,9 +32,30 @@ #ifndef LINUX_QEDR_CM_H_ #define LINUX_QEDR_CM_H_ +#define QEDR_GSI_MAX_RECV_WR (4096) +#define QEDR_GSI_MAX_SEND_WR (4096) + +#define QEDR_GSI_MAX_RECV_SGE (1) /* LL2 FW limitation */ + +#define ETH_P_ROCE (0x8915) +#define QEDR_ROCE_V2_UDP_SPORT (0000) + static inline u32 qedr_get_ipv4_from_gid(u8 *gid) { return *(u32 *)(void *)&gid[12]; } +/* RDMA CM */ +int qedr_gsi_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); +int qedr_gsi_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); +int qedr_gsi_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr); +struct ib_qp *qedr_create_gsi_qp(struct qedr_dev *dev, + struct ib_qp_init_attr *attrs, + struct qedr_qp *qp); +void qedr_store_gsi_qp_cq(struct qedr_dev *dev, + struct qedr_qp *qp, struct ib_qp_init_attr *attrs); +int qedr_destroy_gsi_qp(struct qedr_dev *dev); +void qedr_inc_sw_gsi_cons(struct qedr_qp_hwq_info *info); #endif diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index e4b4d47c6a2da..44ad6ae036c9a 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -1502,6 +1502,15 @@ struct ib_qp *qedr_create_qp(struct ib_pd *ibpd, qedr_set_qp_init_params(dev, qp, pd, attrs); + if (attrs->qp_type == IB_QPT_GSI) { + if (udata) { + DP_ERR(dev, + "create qp: unexpected udata when creating GSI QP\n"); + goto err0; + } + return qedr_create_gsi_qp(dev, attrs, qp); + } + memset(&in_params, 0, sizeof(in_params)); if (udata) { @@ -2068,6 +2077,8 @@ int qedr_destroy_qp(struct ib_qp *ibqp) rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp); if (rc) return rc; + } else { + qedr_destroy_gsi_qp(dev); } if (ibqp->uobject && ibqp->uobject->context) { @@ -2083,6 +2094,27 @@ int qedr_destroy_qp(struct ib_qp *ibqp) return rc; } +struct ib_ah *qedr_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr) +{ + struct qedr_ah *ah; + + ah = kzalloc(sizeof(*ah), GFP_ATOMIC); + if (!ah) + return ERR_PTR(-ENOMEM); + + ah->attr = *attr; + + return &ah->ibah; +} + +int qedr_destroy_ah(struct ib_ah *ibah) +{ + struct qedr_ah *ah = get_qedr_ah(ibah); + + kfree(ah); + return 0; +} + static void free_mr_info(struct qedr_dev *dev, struct mr_info *info) { struct qedr_pbl *pbl, *tmp; @@ -2934,6 +2966,9 @@ int qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, *bad_wr = NULL; + if (qp->qp_type == IB_QPT_GSI) + return qedr_gsi_post_send(ibqp, wr, bad_wr); + spin_lock_irqsave(&qp->q_lock, flags); if ((qp->state == QED_ROCE_QP_STATE_RESET) || @@ -2990,6 +3025,9 @@ int qedr_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, unsigned long flags; int status = 0; + if (qp->qp_type == IB_QPT_GSI) + return qedr_gsi_post_recv(ibqp, wr, bad_wr); + spin_lock_irqsave(&qp->q_lock, flags); if ((qp->state == QED_ROCE_QP_STATE_RESET) || @@ -3416,6 +3454,9 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) int update = 0; int done = 0; + if (cq->cq_type == QEDR_CQ_TYPE_GSI) + return qedr_gsi_poll_cq(ibcq, num_entries, wc); + spin_lock_irqsave(&cq->cq_lock, flags); old_cons = qed_chain_get_cons_idx_u32(&cq->pbl); while (num_entries && is_valid_cqe(cq, cqe)) { diff --git a/drivers/infiniband/hw/qedr/verbs.h b/drivers/infiniband/hw/qedr/verbs.h index fb9b751a6dde3..fbc6db5a5e1ff 100644 --- a/drivers/infiniband/hw/qedr/verbs.h +++ b/drivers/infiniband/hw/qedr/verbs.h @@ -70,6 +70,9 @@ int qedr_query_qp(struct ib_qp *, struct ib_qp_attr *qp_attr, int qp_attr_mask, struct ib_qp_init_attr *); int qedr_destroy_qp(struct ib_qp *ibqp); +struct ib_ah *qedr_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr); +int qedr_destroy_ah(struct ib_ah *ibah); + int qedr_dereg_mr(struct ib_mr *); struct ib_mr *qedr_get_dma_mr(struct ib_pd *, int acc); -- GitLab From 993d1b52615e1a549e55875c3b74308391672d9f Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 10 Oct 2016 13:15:39 +0300 Subject: [PATCH 0570/1167] qedr: Add events support and register IB device Add error handling support. Register ib device with ib stack. Signed-off-by: Rajesh Borundia Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/main.c | 114 ++++++++++++++++++++++++++++- drivers/infiniband/hw/qedr/verbs.c | 37 ++++++++++ drivers/infiniband/hw/qedr/verbs.h | 9 +++ 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 42dff48a31712..7b74d09a8217c 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -79,10 +79,25 @@ static void qedr_get_dev_fw_str(struct ib_device *ibdev, char *str, (fw_ver >> 8) & 0xFF, fw_ver & 0xFF); } +static struct net_device *qedr_get_netdev(struct ib_device *dev, u8 port_num) +{ + struct qedr_dev *qdev; + + qdev = get_qedr_dev(dev); + dev_hold(qdev->ndev); + + /* The HW vendor's device driver must guarantee + * that this function returns NULL before the net device reaches + * NETDEV_UNREGISTER_FINAL state. + */ + return qdev->ndev; +} + static int qedr_register_device(struct qedr_dev *dev) { strlcpy(dev->ibdev.name, "qedr%d", IB_DEVICE_NAME_MAX); + dev->ibdev.node_guid = dev->attr.node_guid; memcpy(dev->ibdev.node_desc, QEDR_NODE_DESC, sizeof(QEDR_NODE_DESC)); dev->ibdev.owner = THIS_MODULE; dev->ibdev.uverbs_abi_ver = QEDR_ABI_VERSION; @@ -151,12 +166,16 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.post_send = qedr_post_send; dev->ibdev.post_recv = qedr_post_recv; + dev->ibdev.process_mad = qedr_process_mad; + dev->ibdev.get_port_immutable = qedr_port_immutable; + dev->ibdev.get_netdev = qedr_get_netdev; + dev->ibdev.dma_device = &dev->pdev->dev; dev->ibdev.get_link_layer = qedr_link_layer; dev->ibdev.get_dev_fw_str = qedr_get_dev_fw_str; - return 0; + return ib_register_device(&dev->ibdev, NULL); } /* This function allocates fast-path status block memory */ @@ -557,6 +576,92 @@ static int qedr_set_device_attr(struct qedr_dev *dev) return 0; } +void qedr_unaffiliated_event(void *context, + u8 event_code) +{ + pr_err("unaffiliated event not implemented yet\n"); +} + +void qedr_affiliated_event(void *context, u8 e_code, void *fw_handle) +{ +#define EVENT_TYPE_NOT_DEFINED 0 +#define EVENT_TYPE_CQ 1 +#define EVENT_TYPE_QP 2 + struct qedr_dev *dev = (struct qedr_dev *)context; + union event_ring_data *data = fw_handle; + u64 roce_handle64 = ((u64)data->roce_handle.hi << 32) + + data->roce_handle.lo; + u8 event_type = EVENT_TYPE_NOT_DEFINED; + struct ib_event event; + struct ib_cq *ibcq; + struct ib_qp *ibqp; + struct qedr_cq *cq; + struct qedr_qp *qp; + + switch (e_code) { + case ROCE_ASYNC_EVENT_CQ_OVERFLOW_ERR: + event.event = IB_EVENT_CQ_ERR; + event_type = EVENT_TYPE_CQ; + break; + case ROCE_ASYNC_EVENT_SQ_DRAINED: + event.event = IB_EVENT_SQ_DRAINED; + event_type = EVENT_TYPE_QP; + break; + case ROCE_ASYNC_EVENT_QP_CATASTROPHIC_ERR: + event.event = IB_EVENT_QP_FATAL; + event_type = EVENT_TYPE_QP; + break; + case ROCE_ASYNC_EVENT_LOCAL_INVALID_REQUEST_ERR: + event.event = IB_EVENT_QP_REQ_ERR; + event_type = EVENT_TYPE_QP; + break; + case ROCE_ASYNC_EVENT_LOCAL_ACCESS_ERR: + event.event = IB_EVENT_QP_ACCESS_ERR; + event_type = EVENT_TYPE_QP; + break; + default: + DP_ERR(dev, "unsupported event %d on handle=%llx\n", e_code, + roce_handle64); + } + + switch (event_type) { + case EVENT_TYPE_CQ: + cq = (struct qedr_cq *)(uintptr_t)roce_handle64; + if (cq) { + ibcq = &cq->ibcq; + if (ibcq->event_handler) { + event.device = ibcq->device; + event.element.cq = ibcq; + ibcq->event_handler(&event, ibcq->cq_context); + } + } else { + WARN(1, + "Error: CQ event with NULL pointer ibcq. Handle=%llx\n", + roce_handle64); + } + DP_ERR(dev, "CQ event %d on hanlde %p\n", e_code, cq); + break; + case EVENT_TYPE_QP: + qp = (struct qedr_qp *)(uintptr_t)roce_handle64; + if (qp) { + ibqp = &qp->ibqp; + if (ibqp->event_handler) { + event.device = ibqp->device; + event.element.qp = ibqp; + ibqp->event_handler(&event, ibqp->qp_context); + } + } else { + WARN(1, + "Error: QP event with NULL pointer ibqp. Handle=%llx\n", + roce_handle64); + } + DP_ERR(dev, "QP event %d on hanlde %p\n", e_code, qp); + break; + default: + break; + } +} + static int qedr_init_hw(struct qedr_dev *dev) { struct qed_rdma_add_user_out_params out_params; @@ -585,6 +690,8 @@ static int qedr_init_hw(struct qedr_dev *dev) cur_pbl->pbl_ptr = (u64)p_phys_table; } + events.affiliated_event = qedr_affiliated_event; + events.unaffiliated_event = qedr_unaffiliated_event; events.context = dev; in_params->events = &events; @@ -683,11 +790,13 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, for (i = 0; i < ARRAY_SIZE(qedr_attributes); i++) if (device_create_file(&dev->ibdev.dev, qedr_attributes[i])) - goto reg_err; + goto sysfs_err; DP_DEBUG(dev, QEDR_MSG_INIT, "qedr driver loaded successfully\n"); return dev; +sysfs_err: + ib_unregister_device(&dev->ibdev); reg_err: qedr_sync_free_irqs(dev); irq_err: @@ -707,6 +816,7 @@ static void qedr_remove(struct qedr_dev *dev) * of the registered clients. */ qedr_remove_sysfiles(dev); + ib_unregister_device(&dev->ibdev); qedr_stop_hw(dev); qedr_sync_free_irqs(dev); diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 44ad6ae036c9a..a61514296767d 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -3508,3 +3508,40 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) spin_unlock_irqrestore(&cq->cq_lock, flags); return done; } + +int qedr_process_mad(struct ib_device *ibdev, int process_mad_flags, + u8 port_num, + const struct ib_wc *in_wc, + const struct ib_grh *in_grh, + const struct ib_mad_hdr *mad_hdr, + size_t in_mad_size, struct ib_mad_hdr *out_mad, + size_t *out_mad_size, u16 *out_mad_pkey_index) +{ + struct qedr_dev *dev = get_qedr_dev(ibdev); + + DP_DEBUG(dev, QEDR_MSG_GSI, + "QEDR_PROCESS_MAD in_mad %x %x %x %x %x %x %x %x\n", + mad_hdr->attr_id, mad_hdr->base_version, mad_hdr->attr_mod, + mad_hdr->class_specific, mad_hdr->class_version, + mad_hdr->method, mad_hdr->mgmt_class, mad_hdr->status); + return IB_MAD_RESULT_SUCCESS; +} + +int qedr_port_immutable(struct ib_device *ibdev, u8 port_num, + struct ib_port_immutable *immutable) +{ + struct ib_port_attr attr; + int err; + + err = qedr_query_port(ibdev, port_num, &attr); + if (err) + return err; + + immutable->pkey_tbl_len = attr.pkey_tbl_len; + immutable->gid_tbl_len = attr.gid_tbl_len; + immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE | + RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP; + immutable->max_mad_size = IB_MGMT_MAD_SIZE; + + return 0; +} diff --git a/drivers/infiniband/hw/qedr/verbs.h b/drivers/infiniband/hw/qedr/verbs.h index fbc6db5a5e1ff..a9b5e67bb81e9 100644 --- a/drivers/infiniband/hw/qedr/verbs.h +++ b/drivers/infiniband/hw/qedr/verbs.h @@ -89,4 +89,13 @@ int qedr_post_send(struct ib_qp *, struct ib_send_wr *, struct ib_send_wr **bad_wr); int qedr_post_recv(struct ib_qp *, struct ib_recv_wr *, struct ib_recv_wr **bad_wr); +int qedr_process_mad(struct ib_device *ibdev, int process_mad_flags, + u8 port_num, const struct ib_wc *in_wc, + const struct ib_grh *in_grh, + const struct ib_mad_hdr *in_mad, + size_t in_mad_size, struct ib_mad_hdr *out_mad, + size_t *out_mad_size, u16 *out_mad_pkey_index); + +int qedr_port_immutable(struct ib_device *ibdev, u8 port_num, + struct ib_port_immutable *immutable); #endif -- GitLab From 9593265531fa66177a0547e63abd99907ec0a687 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 Sep 2016 01:36:34 -0500 Subject: [PATCH 0571/1167] CIFS: Add new mount option to set owner uid and gid from special sids in acl Add "idsfromsid" mount option to indicate to cifs.ko that it should try to retrieve the uid and gid owner fields from special sids in the ACL if present. This first patch just adds the parsing for the mount option. Signed-off-by: Steve French Reviewed-by: Shirish Pargaonkar Reviewed-by: Pavel Shilovsky --- fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/cifsfs.c | 2 ++ fs/cifs/cifsglob.h | 1 + fs/cifs/connect.c | 8 +++++++- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 1418daa03d959..07ed81cf1552e 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -49,6 +49,7 @@ #define CIFS_MOUNT_USE_PREFIX_PATH 0x1000000 /* make subpath with unaccessible * root mountable */ +#define CIFS_MOUNT_UID_FROM_ACL 0x2000000 /* try to get UID via special SID */ struct cifs_sb_info { struct rb_root tlink_tree; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f963c880c72d5..15261ba464c50 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -469,6 +469,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) seq_puts(s, ",posixpaths"); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) seq_puts(s, ",setuids"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) + seq_puts(s, ",idsfromsid"); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) seq_puts(s, ",serverino"); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0c828d3c48c38..1f17f6bd7a601 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -478,6 +478,7 @@ struct smb_vol { bool retry:1; bool intr:1; bool setuids:1; + bool setuidfromacl:1; bool override_uid:1; bool override_gid:1; bool dynperm:1; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 657369db76dfe..aab5227979e2e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -75,7 +75,7 @@ enum { Opt_noposixpaths, Opt_nounix, Opt_nocase, Opt_brl, Opt_nobrl, - Opt_forcemandatorylock, Opt_setuids, + Opt_forcemandatorylock, Opt_setuidfromacl, Opt_setuids, Opt_nosetuids, Opt_dynperm, Opt_nodynperm, Opt_nohard, Opt_nosoft, Opt_nointr, Opt_intr, @@ -147,6 +147,7 @@ static const match_table_t cifs_mount_option_tokens = { { Opt_forcemandatorylock, "forcemand" }, { Opt_setuids, "setuids" }, { Opt_nosetuids, "nosetuids" }, + { Opt_setuidfromacl, "idsfromsid" }, { Opt_dynperm, "dynperm" }, { Opt_nodynperm, "nodynperm" }, { Opt_nohard, "nohard" }, @@ -1376,6 +1377,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, case Opt_nosetuids: vol->setuids = 0; break; + case Opt_setuidfromacl: + vol->setuidfromacl = 1; + break; case Opt_dynperm: vol->dynperm = true; break; @@ -3279,6 +3283,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; if (pvolume_info->setuids) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; + if (pvolume_info->setuidfromacl) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL; if (pvolume_info->server_ino) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; if (pvolume_info->remap) -- GitLab From 3514de3fd5fab518520e393152d3f4e3d0441d8d Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 13 Oct 2016 19:06:23 -0500 Subject: [PATCH 0572/1167] CIFS: Retrieve uid and gid from special sid if enabled New mount option "idsfromsid" indicates to cifs.ko that it should try to retrieve the uid and gid owner fields from special sids. This patch adds the code to parse the owner sids in the ACL to see if they match, and if so populate the uid and/or gid from them. This is faster than upcalling for them and asking winbind, and is a fairly common case, and is also helpful when cifs.upcall and idmapping is not configured. Signed-off-by: Steve French Reviewed-by: Shirish Pargaonkar Reviewed-by: Jeff Layton Reviewed-by: Pavel Shilovsky --- fs/cifs/cifsacl.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 71e8a56e94795..15bac390dff94 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -42,6 +42,35 @@ static const struct cifs_sid sid_authusers = { /* group users */ static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; +/* S-1-22-1 Unmapped Unix users */ +static const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22}, + {cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; + +/* S-1-22-2 Unmapped Unix groups */ +static const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22}, + {cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; + +/* + * See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx + */ + +/* S-1-5-88 MS NFS and Apple style UID/GID/mode */ + +/* S-1-5-88-1 Unix uid */ +static const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5}, + {cpu_to_le32(88), + cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; + +/* S-1-5-88-2 Unix gid */ +static const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5}, + {cpu_to_le32(88), + cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; + +/* S-1-5-88-3 Unix mode */ +static const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5}, + {cpu_to_le32(88), + cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; + static const struct cred *root_cred; static int @@ -183,6 +212,62 @@ compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) return 0; /* sids compare/match */ } +static bool +is_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group) +{ + int i; + int num_subauth; + const struct cifs_sid *pwell_known_sid; + + if (!psid || (puid == NULL)) + return false; + + num_subauth = psid->num_subauth; + + /* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */ + if (num_subauth == 2) { + if (is_group) + pwell_known_sid = &sid_unix_groups; + else + pwell_known_sid = &sid_unix_users; + } else if (num_subauth == 3) { + if (is_group) + pwell_known_sid = &sid_unix_NFS_groups; + else + pwell_known_sid = &sid_unix_NFS_users; + } else + return false; + + /* compare the revision */ + if (psid->revision != pwell_known_sid->revision) + return false; + + /* compare all of the six auth values */ + for (i = 0; i < NUM_AUTHS; ++i) { + if (psid->authority[i] != pwell_known_sid->authority[i]) { + cifs_dbg(FYI, "auth %d did not match\n", i); + return false; + } + } + + if (num_subauth == 2) { + if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) + return false; + + *puid = le32_to_cpu(psid->sub_auth[1]); + } else /* 3 subauths, ie Windows/Mac style */ { + *puid = le32_to_cpu(psid->sub_auth[0]); + if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) || + (psid->sub_auth[1] != pwell_known_sid->sub_auth[1])) + return false; + + *puid = le32_to_cpu(psid->sub_auth[2]); + } + + cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid); + return true; /* well known sid found, uid returned */ +} + static void cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src) { @@ -276,6 +361,43 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, return -EIO; } + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) { + uint32_t unix_id; + bool is_group; + + if (sidtype != SIDOWNER) + is_group = true; + else + is_group = false; + + if (is_well_known_sid(psid, &unix_id, is_group) == false) + goto try_upcall_to_get_id; + + if (is_group) { + kgid_t gid; + gid_t id; + + id = (gid_t)unix_id; + gid = make_kgid(&init_user_ns, id); + if (gid_valid(gid)) { + fgid = gid; + goto got_valid_id; + } + } else { + kuid_t uid; + uid_t id; + + id = (uid_t)unix_id; + uid = make_kuid(&init_user_ns, id); + if (uid_valid(uid)) { + fuid = uid; + goto got_valid_id; + } + } + /* If unable to find uid/gid easily from SID try via upcall */ + } + +try_upcall_to_get_id: sidstr = sid_to_key_str(psid, sidtype); if (!sidstr) return -ENOMEM; @@ -329,6 +451,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, * Note that we return 0 here unconditionally. If the mapping * fails then we just fall back to using the mnt_uid/mnt_gid. */ +got_valid_id: if (sidtype == SIDOWNER) fattr->cf_uid = fuid; else -- GitLab From 85a624403c77c3f074931aefdfced59f61b668cb Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 13 Oct 2016 16:13:55 -0700 Subject: [PATCH 0573/1167] ethtool: silence warning on bit loss Sparse was complaining when we went to prototype some code using ethtool_cmd_speed_set and SPEED_100000, which uses the upper 16 bits of __u32 speed for the first time. CHECK ... .../uapi/linux/ethtool.h:123:28: warning: cast truncates bits from constant value (186a0 becomes 86a0) The warning is actually bogus, as no bits are really lost, but we can get rid of the sparse warning with this one small change. Reported-by: Preethi Banala Signed-off-by: Jesse Brandeburg Signed-off-by: David S. Miller --- include/uapi/linux/ethtool.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index 099a4200732cc..8e547231c1b74 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -119,8 +119,7 @@ struct ethtool_cmd { static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep, __u32 speed) { - - ep->speed = (__u16)speed; + ep->speed = (__u16)(speed & 0xFFFF); ep->speed_hi = (__u16)(speed >> 16); } -- GitLab From 610df1d2342d639ec87a8fb5290ca4799d91d59b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 13 Oct 2016 16:43:16 -0700 Subject: [PATCH 0574/1167] net: asix: Avoid looping when the device does not respond Check answers from USB stack and avoid re-sending the request multiple times if the device does not respond. This fixes the following problem, observed with a probably flaky adapter. [62108.732707] usb 1-3: new high-speed USB device number 5 using xhci_hcd [62108.914421] usb 1-3: New USB device found, idVendor=0b95, idProduct=7720 [62108.914463] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [62108.914476] usb 1-3: Product: AX88x72A [62108.914486] usb 1-3: Manufacturer: ASIX Elec. Corp. [62108.914495] usb 1-3: SerialNumber: 000001 [62114.109109] asix 1-3:1.0 (unnamed net_device) (uninitialized): Failed to write reg index 0x0000: -110 [62114.109139] asix 1-3:1.0 (unnamed net_device) (uninitialized): Failed to send software reset: ffffff92 [62119.109048] asix 1-3:1.0 (unnamed net_device) (uninitialized): Failed to write reg index 0x0000: -110 ... Since the USB timeout is 5 seconds, and the operation is retried 30 times, this results in [62278.180353] INFO: task mtpd:1725 blocked for more than 120 seconds. [62278.180373] Tainted: G W 3.18.0-13298-g94ace9e #1 [62278.180383] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. ... [62278.180957] kworker/2:0 D 0000000000000000 0 5744 2 0x00000000 [62278.180978] Workqueue: usb_hub_wq hub_event [62278.181029] ffff880177f833b8 0000000000000046 ffff88017fd00000 ffff88017b126d80 [62278.181048] ffff880177f83fd8 ffff880065a71b60 0000000000013340 ffff880065a71b60 [62278.181065] 0000000000000286 0000000103b1c199 0000000000001388 0000000000000002 [62278.181081] Call Trace: [62278.181092] [] ? console_conditional_schedule+0x2c/0x2c [62278.181105] [] schedule+0x69/0x6b [62278.181117] [] schedule_timeout+0xe3/0x11d [62278.181133] [] ? trace_timer_start+0x51/0x51 [62278.181146] [] do_wait_for_common+0x12f/0x16c [62278.181162] [] ? wake_up_process+0x39/0x39 [62278.181174] [] wait_for_common+0x52/0x6d [62278.181187] [] wait_for_completion_timeout+0x13/0x15 [62278.181201] [] usb_start_wait_urb+0x93/0xf1 [62278.181214] [] usb_control_msg+0xe1/0x11d [62278.181230] [] usbnet_write_cmd+0x9c/0xc6 [usbnet] [62278.181286] [] asix_write_cmd+0x4e/0x7e [asix] [62278.181300] [] asix_set_sw_mii+0x25/0x4e [asix] [62278.181314] [] asix_mdio_read+0x51/0x109 [asix] ... Signed-off-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/usb/asix_common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index f79eb12c326aa..125cff57c759e 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -433,13 +433,13 @@ int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) mutex_lock(&dev->phy_mutex); do { ret = asix_set_sw_mii(dev, 0); - if (ret == -ENODEV) + if (ret == -ENODEV || ret == -ETIMEDOUT) break; usleep_range(1000, 1100); ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &smsr, 0); } while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV)); - if (ret == -ENODEV) { + if (ret == -ENODEV || ret == -ETIMEDOUT) { mutex_unlock(&dev->phy_mutex); return ret; } @@ -497,13 +497,13 @@ int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc) mutex_lock(&dev->phy_mutex); do { ret = asix_set_sw_mii(dev, 1); - if (ret == -ENODEV) + if (ret == -ENODEV || ret == -ETIMEDOUT) break; usleep_range(1000, 1100); ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &smsr, 1); } while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV)); - if (ret == -ENODEV) { + if (ret == -ENODEV || ret == -ETIMEDOUT) { mutex_unlock(&dev->phy_mutex); return ret; } -- GitLab From e7cb08e894a0b876443ef8fdb0706575dc00a5d2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Oct 2016 16:18:39 -0400 Subject: [PATCH 0575/1167] scsi: zfcp: spin_lock_irqsave() is not nestable We accidentally overwrite the original saved value of "flags" so that we can't re-enable IRQs at the end of the function. Presumably this function is mostly called with IRQs disabled or it would be obvious in testing. Fixes: aceeffbb59bb ("zfcp: trace full payload of all SAN records (req,resp,iels)") Cc: #2.6.38+ Signed-off-by: Dan Carpenter Signed-off-by: Steffen Maier Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_dbf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 637cf8973c9e1..581001989937c 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -384,7 +384,7 @@ void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf, /* if (len > rec_len): * dump data up to cap_len ignoring small duplicate in rec->payload */ - spin_lock_irqsave(&dbf->pay_lock, flags); + spin_lock(&dbf->pay_lock); memset(payload, 0, sizeof(*payload)); memcpy(payload->area, paytag, ZFCP_DBF_TAG_LEN); payload->fsf_req_id = req_id; -- GitLab From 8a4236a2c7868768943a24dc7b1e2ff495836880 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 13 Oct 2016 14:45:24 -0500 Subject: [PATCH 0576/1167] scsi: ipr: Fix async error WARN_ON Commit afc3f83cb4a5 ("scsi: ipr: Add asynchronous error notification") introduced the warn on shown below. To fix this, rather than attempting to send the KOBJ_CHANGE uevent from interrupt context, which is what is causing the WARN_ON, just wake the ipr worker thread which will send a KOBJ_CHANGE uevent. [ 142.278120] WARNING: CPU: 15 PID: 0 at kernel/softirq.c:161 __local_bh_enable_ip+0x7c/0xd0 [ 142.278124] Modules linked in: ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 ipt_REJECT nf_reject_ipv4 xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw iptable_filter ses enclosure scsi_transport_sas sg pseries_rng nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c sr_mod sd_mod cdrom ipr libata ibmvscsi scsi_transport_srp ibmveth dm_mirror dm_region_hash dm_log dm_mod [ 142.278208] CPU: 15 PID: 0 Comm: swapper/15 Not tainted 4.8.0.ipr+ #21 [ 142.278213] task: c00000010cf24480 task.stack: c00000010cfec000 [ 142.278217] NIP: c0000000000c0c7c LR: c000000000881778 CTR: c0000000003c5bf0 [ 142.278221] REGS: c00000010cfef080 TRAP: 0700 Not tainted (4.8.0.ipr+) [ 142.278224] MSR: 8000000000029033 CR: 28008022 XER: 2000000f [ 142.278236] CFAR: c0000000000c0c20 SOFTE: 0 GPR00: c000000000706c78 c00000010cfef300 c000000000f91d00 c000000000706c78 GPR04: 0000000000000200 c000000000f7bc80 0000000000000000 00000000024000c0 GPR08: 0000000000000000 0000000000000001 c000000000ee1d00 c000000000a9bdd0 GPR12: c0000000003c5bf0 c00000000eb22d00 c000000100ca3880 c00000020ed38400 GPR16: 0000000000000000 0000000000000000 c000000100940508 0000000000000000 GPR20: 0000000000000000 0000000000000000 0000000000000000 00000000024000c0 GPR24: c0000000004588e0 c00000010863bd00 c00000010863bd00 c0000000013773f8 GPR28: c000000000f7bc80 0000000000000000 ffffffffffffffff c000000000f7bcd8 [ 142.278290] NIP [c0000000000c0c7c] __local_bh_enable_ip+0x7c/0xd0 [ 142.278296] LR [c000000000881778] _raw_spin_unlock_bh+0x38/0x60 [ 142.278299] Call Trace: [ 142.278303] [c00000010cfef300] [c000000000f7bc80] init_net+0x0/0x1900 (unreliable) [ 142.278310] [c00000010cfef320] [c000000000706c78] peernet2id+0x58/0x80 [ 142.278316] [c00000010cfef370] [c00000000075caec] netlink_broadcast_filtered+0x30c/0x550 [ 142.278323] [c00000010cfef430] [c000000000459078] kobject_uevent_env+0x588/0x780 [ 142.278331] [c00000010cfef510] [d000000003163a6c] ipr_process_error+0x11c/0x240 [ipr] [ 142.278337] [c00000010cfef5c0] [d000000003152298] ipr_fail_all_ops+0x108/0x220 [ipr] [ 142.278343] [c00000010cfef670] [d0000000031643f8] ipr_reset_restore_cfg_space+0xa8/0x240 [ipr] [ 142.278350] [c00000010cfef6f0] [d000000003158a00] ipr_reset_ioa_job+0x80/0xe0 [ipr] [ 142.278356] [c00000010cfef720] [d000000003153f78] ipr_reset_timer_done+0xa8/0xe0 [ipr] [ 142.278363] [c00000010cfef770] [c000000000149c88] call_timer_fn+0x58/0x1c0 [ 142.278368] [c00000010cfef800] [c000000000149f60] expire_timers+0x140/0x200 [ 142.278373] [c00000010cfef870] [c00000000014a0e8] run_timer_softirq+0xc8/0x230 [ 142.278379] [c00000010cfef900] [c0000000000c0844] __do_softirq+0x164/0x3c0 [ 142.278384] [c00000010cfef9f0] [c0000000000c0f18] irq_exit+0x1a8/0x1c0 [ 142.278389] [c00000010cfefa20] [c000000000020b54] timer_interrupt+0xa4/0xe0 [ 142.278394] [c00000010cfefa50] [c000000000002414] decrementer_common+0x114/0x180 Signed-off-by: Brian King Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index a8762a3efeef3..532474109624d 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -2586,7 +2586,6 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd) struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); u32 fd_ioasc; - char *envp[] = { "ASYNC_ERR_LOG=1", NULL }; if (ioa_cfg->sis64) fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc); @@ -2607,8 +2606,8 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd) } list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_report_q); + schedule_work(&ioa_cfg->work_q); hostrcb = ipr_get_free_hostrcb(ioa_cfg); - kobject_uevent_env(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE, envp); ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); } -- GitLab From ffecee4f2442bb8cb6b34c3335fef4eb50c22fdd Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Sat, 8 Oct 2016 11:18:07 +0200 Subject: [PATCH 0577/1167] iov_iter: kernel-doc import_iovec() and rw_copy_check_uvector() Both import_iovec() and rw_copy_check_uvector() take an array (typically small and on-stack) which is used to hold an iovec array copy from userspace. This is to avoid an expensive memory allocation in the fast path (i.e. few iovec elements). The caller may have to check whether these functions actually used the provided buffer or allocated a new one -- but this differs between the too. Let's just add a kernel doc to clarify what the semantics are for each function. Signed-off-by: Vegard Nossum Signed-off-by: Al Viro --- fs/read_write.c | 29 +++++++++++++++++++++++++++++ lib/iov_iter.c | 22 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/fs/read_write.c b/fs/read_write.c index 66215a7b17cf1..190e0d362581a 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -730,6 +730,35 @@ static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter, /* A write operation does a read from user space and vice versa */ #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) +/** + * rw_copy_check_uvector() - Copy an array of &struct iovec from userspace + * into the kernel and check that it is valid. + * + * @type: One of %CHECK_IOVEC_ONLY, %READ, or %WRITE. + * @uvector: Pointer to the userspace array. + * @nr_segs: Number of elements in userspace array. + * @fast_segs: Number of elements in @fast_pointer. + * @fast_pointer: Pointer to (usually small on-stack) kernel array. + * @ret_pointer: (output parameter) Pointer to a variable that will point to + * either @fast_pointer, a newly allocated kernel array, or NULL, + * depending on which array was used. + * + * This function copies an array of &struct iovec of @nr_segs from + * userspace into the kernel and checks that each element is valid (e.g. + * it does not point to a kernel address or cause overflow by being too + * large, etc.). + * + * As an optimization, the caller may provide a pointer to a small + * on-stack array in @fast_pointer, typically %UIO_FASTIOV elements long + * (the size of this array, or 0 if unused, should be given in @fast_segs). + * + * @ret_pointer will always point to the array that was used, so the + * caller must take care not to call kfree() on it e.g. in case the + * @fast_pointer array was used and it was allocated on the stack. + * + * Return: The total number of bytes covered by the iovec array on success + * or a negative error code on error. + */ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, unsigned long nr_segs, unsigned long fast_segs, struct iovec *fast_pointer, diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 7312e7784611d..f0c7f1481baee 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1139,6 +1139,28 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags) } EXPORT_SYMBOL(dup_iter); +/** + * import_iovec() - Copy an array of &struct iovec from userspace + * into the kernel, check that it is valid, and initialize a new + * &struct iov_iter iterator to access it. + * + * @type: One of %READ or %WRITE. + * @uvector: Pointer to the userspace array. + * @nr_segs: Number of elements in userspace array. + * @fast_segs: Number of elements in @iov. + * @iov: (input and output parameter) Pointer to pointer to (usually small + * on-stack) kernel array. + * @i: Pointer to iterator that will be initialized on success. + * + * If the array pointed to by *@iov is large enough to hold all @nr_segs, + * then this function places %NULL in *@iov on return. Otherwise, a new + * array will be allocated and the result placed in *@iov. This means that + * the caller may call kfree() on *@iov regardless of whether the small + * on-stack array was used or not (and regardless of whether this function + * returns an error or not). + * + * Return: 0 on success or negative error code on error. + */ int import_iovec(int type, const struct iovec __user * uvector, unsigned nr_segs, unsigned fast_segs, struct iovec **iov, struct iov_iter *i) -- GitLab From 655042cc1406fcec20aa7ffd7d790ada18ac5211 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Fri, 14 Oct 2016 03:03:36 +0200 Subject: [PATCH 0578/1167] overlayfs: Fix setting IOP_XATTR flag ovl_fill_super calls ovl_new_inode to create a root inode for the new superblock before initializing sb->s_xattr. This wrongly causes IOP_XATTR to be cleared in i_opflags of the new inode, causing SELinux to log the following message: SELinux: (dev overlay, type overlay) has no xattr support Fix this by initializing sb->s_xattr and similar fields before calling ovl_new_inode. Signed-off-by: Andreas Gruenbacher Signed-off-by: Al Viro --- fs/overlayfs/super.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 7e3f0127fc1aa..0ffc8da1aa3f4 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -1292,6 +1292,12 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) if (!oe) goto out_put_cred; + sb->s_magic = OVERLAYFS_SUPER_MAGIC; + sb->s_op = &ovl_super_operations; + sb->s_xattr = ovl_xattr_handlers; + sb->s_fs_info = ufs; + sb->s_flags |= MS_POSIXACL | MS_NOREMOTELOCK; + root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR)); if (!root_dentry) goto out_free_oe; @@ -1315,12 +1321,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ovl_inode_init(d_inode(root_dentry), realinode, !!upperpath.dentry); ovl_copyattr(realinode, d_inode(root_dentry)); - sb->s_magic = OVERLAYFS_SUPER_MAGIC; - sb->s_op = &ovl_super_operations; - sb->s_xattr = ovl_xattr_handlers; sb->s_root = root_dentry; - sb->s_fs_info = ufs; - sb->s_flags |= MS_POSIXACL | MS_NOREMOTELOCK; return 0; -- GitLab From 89f39af129382a40d7cd1f6914617282cfeee28e Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 26 Sep 2016 18:07:48 +0200 Subject: [PATCH 0579/1167] fs/super.c: fix race between freeze_super() and thaw_super() Change thaw_super() to check frozen != SB_FREEZE_COMPLETE rather than frozen == SB_UNFROZEN, otherwise it can race with freeze_super() which drops sb->s_umount after SB_FREEZE_WRITE to preserve the lock ordering. In this case thaw_super() will wrongly call s_op->unfreeze_fs() before it was actually frozen, and call sb_freeze_unlock() which leads to the unbalanced percpu_up_write(). Unfortunately lockdep can't detect this, so this triggers misc BUG_ON()'s in kernel/rcu/sync.c. Reported-and-tested-by: Nikolay Borisov Signed-off-by: Oleg Nesterov Cc: stable@vger.kernel.org Signed-off-by: Al Viro --- fs/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/super.c b/fs/super.c index c2ff475c1711f..47d11e0462d0e 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1379,8 +1379,8 @@ int freeze_super(struct super_block *sb) } } /* - * This is just for debugging purposes so that fs can warn if it - * sees write activity when frozen is set to SB_FREEZE_COMPLETE. + * For debugging purposes so that fs can warn if it sees write activity + * when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super(). */ sb->s_writers.frozen = SB_FREEZE_COMPLETE; up_write(&sb->s_umount); @@ -1399,7 +1399,7 @@ int thaw_super(struct super_block *sb) int error; down_write(&sb->s_umount); - if (sb->s_writers.frozen == SB_UNFROZEN) { + if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) { up_write(&sb->s_umount); return -EINVAL; } -- GitLab From f1a9622037cd370460fd06bb7e28d0f01ceb8ef1 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 26 Sep 2016 18:55:25 +0200 Subject: [PATCH 0580/1167] fs/super.c: don't fool lockdep in freeze_super() and thaw_super() paths sb_wait_write()->percpu_rwsem_release() fools lockdep to avoid the false-positives. Now that xfs was fixed by Dave's commit dbad7c993053 ("xfs: stop holding ILOCK over filldir callbacks") we can remove it and change freeze_super() and thaw_super() to run with s_writers.rw_sem locks held; we add two trivial helpers for that, lockdep_sb_freeze_release() and lockdep_sb_freeze_acquire(). xfstests-dev/check `grep -il freeze tests/*/???` does not trigger any warning from lockdep. Signed-off-by: Oleg Nesterov Signed-off-by: Al Viro --- fs/super.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/fs/super.c b/fs/super.c index 47d11e0462d0e..c183835566c19 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1269,25 +1269,34 @@ EXPORT_SYMBOL(__sb_start_write); static void sb_wait_write(struct super_block *sb, int level) { percpu_down_write(sb->s_writers.rw_sem + level-1); - /* - * We are going to return to userspace and forget about this lock, the - * ownership goes to the caller of thaw_super() which does unlock. - * - * FIXME: we should do this before return from freeze_super() after we - * called sync_filesystem(sb) and s_op->freeze_fs(sb), and thaw_super() - * should re-acquire these locks before s_op->unfreeze_fs(sb). However - * this leads to lockdep false-positives, so currently we do the early - * release right after acquire. - */ - percpu_rwsem_release(sb->s_writers.rw_sem + level-1, 0, _THIS_IP_); } -static void sb_freeze_unlock(struct super_block *sb) +/* + * We are going to return to userspace and forget about these locks, the + * ownership goes to the caller of thaw_super() which does unlock(). + */ +static void lockdep_sb_freeze_release(struct super_block *sb) +{ + int level; + + for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--) + percpu_rwsem_release(sb->s_writers.rw_sem + level, 0, _THIS_IP_); +} + +/* + * Tell lockdep we are holding these locks before we call ->unfreeze_fs(sb). + */ +static void lockdep_sb_freeze_acquire(struct super_block *sb) { int level; for (level = 0; level < SB_FREEZE_LEVELS; ++level) percpu_rwsem_acquire(sb->s_writers.rw_sem + level, 0, _THIS_IP_); +} + +static void sb_freeze_unlock(struct super_block *sb) +{ + int level; for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--) percpu_up_write(sb->s_writers.rw_sem + level); @@ -1383,6 +1392,7 @@ int freeze_super(struct super_block *sb) * when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super(). */ sb->s_writers.frozen = SB_FREEZE_COMPLETE; + lockdep_sb_freeze_release(sb); up_write(&sb->s_umount); return 0; } @@ -1409,11 +1419,14 @@ int thaw_super(struct super_block *sb) goto out; } + lockdep_sb_freeze_acquire(sb); + if (sb->s_op->unfreeze_fs) { error = sb->s_op->unfreeze_fs(sb); if (error) { printk(KERN_ERR "VFS:Filesystem thaw failed\n"); + lockdep_sb_freeze_release(sb); up_write(&sb->s_umount); return error; } -- GitLab From 7041c57709efdc1e31aaff663cfe17f0b21f4743 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 12 Oct 2016 13:42:23 -0700 Subject: [PATCH 0581/1167] score: traps: Add missing include file to fix build error score images fail to build as follows. arch/score/kernel/traps.c: In function 'show_stack': arch/score/kernel/traps.c:55:3: error: implicit declaration of function '__get_user' __get_user() is declared in asm/uaccess.h, which was previously included through asm/module.h. Cc: Al Viro Fixes: 88dd4a748da7 ("score: separate extable.h, switch module.h to it") Signed-off-by: Guenter Roeck Signed-off-by: Al Viro --- arch/score/kernel/traps.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/score/kernel/traps.c b/arch/score/kernel/traps.c index 1517a7dcd6d92..5cea1e750ceca 100644 --- a/arch/score/kernel/traps.c +++ b/arch/score/kernel/traps.c @@ -29,6 +29,7 @@ #include #include #include +#include unsigned long exception_handlers[32]; -- GitLab From f573bbc7a7773b8fc0d62be6b79345f5a971d97d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 14 Oct 2016 14:26:24 -0400 Subject: [PATCH 0582/1167] pkeys: Remove easily triggered WARN This easy-to-trigger warning shows up instantly when running Trinity on a kernel with CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS disabled. At most this should have been a printk, but the -EINVAL alone should be more than adequate indicator that something isn't available. Signed-off-by: Dave Jones Acked-by: Dave Hansen Cc: linux-arch@vger.kernel.org Cc: arnd@arndb.de Cc: linux-api@vger.kernel.org Cc: linux-mm@kvack.org Cc: luto@kernel.org Cc: torvalds@linux-foundation.org Cc: akpm@linux-foundation.org Cc: mgorman@techsingularity.net Signed-off-by: Thomas Gleixner --- include/linux/pkeys.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/pkeys.h b/include/linux/pkeys.h index e4c08c1ff0c59..a1bacf1150b21 100644 --- a/include/linux/pkeys.h +++ b/include/linux/pkeys.h @@ -25,7 +25,6 @@ static inline int mm_pkey_alloc(struct mm_struct *mm) static inline int mm_pkey_free(struct mm_struct *mm, int pkey) { - WARN_ONCE(1, "free of protection key when disabled"); return -EINVAL; } -- GitLab From 199625098a18a5522b424dea9b122b254c022fc5 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 15 Oct 2016 09:39:31 -0400 Subject: [PATCH 0583/1167] ext4: correct endianness conversion in __xattr_check_inode() It should be cpu_to_le32(), not le32_to_cpu(). No change in behavior. Found with sparse, and this was the only endianness warning in fs/ext4/. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara --- fs/ext4/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index c15d63389957b..e90c5cd04d89f 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -241,7 +241,7 @@ __xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, int error = -EFSCORRUPTED; if (((void *) header >= end) || - (header->h_magic != le32_to_cpu(EXT4_XATTR_MAGIC))) + (header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC))) goto errout; error = ext4_xattr_check_names(entry, end, entry); errout: -- GitLab From 8906a8223ad4909b391c5628f7991ebceda30e52 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 15 Oct 2016 09:48:50 -0400 Subject: [PATCH 0584/1167] fscrypto: lock inode while setting encryption policy i_rwsem needs to be acquired while setting an encryption policy so that concurrent calls to FS_IOC_SET_ENCRYPTION_POLICY are correctly serialized (especially the ->get_context() + ->set_context() pair), and so that new files cannot be created in the directory during or after the ->empty_dir() check. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o Reviewed-by: Richard Weinberger Cc: stable@vger.kernel.org --- fs/crypto/policy.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index ed115acb5dee0..6865663aac696 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -109,6 +109,8 @@ int fscrypt_process_policy(struct file *filp, if (ret) return ret; + inode_lock(inode); + if (!inode_has_encryption_context(inode)) { if (!S_ISDIR(inode->i_mode)) ret = -EINVAL; @@ -127,6 +129,8 @@ int fscrypt_process_policy(struct file *filp, ret = -EINVAL; } + inode_unlock(inode); + mnt_drop_write_file(filp); return ret; } -- GitLab From d74f3d25289aa9722cf777a7482eeee2eacdf46e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 15 Oct 2016 09:57:31 -0400 Subject: [PATCH 0585/1167] ext4: add missing KERN_CONT to a few more debugging uses Recent commits require line continuing printks to always use pr_cont or KERN_CONT. Add these markings to a few more printks. Miscellaneaous: o Integrate the ea_idebug and ea_bdebug macros to use a single call to printk(KERN_DEBUG instead of 3 separate printks o Use the more common varargs macro style Signed-off-by: Joe Perches Signed-off-by: Theodore Ts'o Reviewed-by: Andreas Dilger --- fs/ext4/block_validity.c | 4 ++-- fs/ext4/mballoc.h | 17 ++++++++--------- fs/ext4/namei.c | 18 ++++++++++-------- fs/ext4/xattr.c | 18 ++++++------------ 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c index 02ddec6d8a7da..fdb19543af1e6 100644 --- a/fs/ext4/block_validity.c +++ b/fs/ext4/block_validity.c @@ -128,12 +128,12 @@ static void debug_print_tree(struct ext4_sb_info *sbi) node = rb_first(&sbi->system_blks); while (node) { entry = rb_entry(node, struct ext4_system_zone, node); - printk("%s%llu-%llu", first ? "" : ", ", + printk(KERN_CONT "%s%llu-%llu", first ? "" : ", ", entry->start_blk, entry->start_blk + entry->count - 1); first = 0; node = rb_next(node); } - printk("\n"); + printk(KERN_CONT "\n"); } int ext4_setup_system_zone(struct super_block *sb) diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h index 3ef1df6ae9ec6..1aba469f82209 100644 --- a/fs/ext4/mballoc.h +++ b/fs/ext4/mballoc.h @@ -27,16 +27,15 @@ #ifdef CONFIG_EXT4_DEBUG extern ushort ext4_mballoc_debug; -#define mb_debug(n, fmt, a...) \ - do { \ - if ((n) <= ext4_mballoc_debug) { \ - printk(KERN_DEBUG "(%s, %d): %s: ", \ - __FILE__, __LINE__, __func__); \ - printk(fmt, ## a); \ - } \ - } while (0) +#define mb_debug(n, fmt, ...) \ +do { \ + if ((n) <= ext4_mballoc_debug) { \ + printk(KERN_DEBUG "(%s, %d): %s: " fmt, \ + __FILE__, __LINE__, __func__, ##__VA_ARGS__); \ + } \ +} while (0) #else -#define mb_debug(n, fmt, a...) no_printk(fmt, ## a) +#define mb_debug(n, fmt, ...) no_printk(fmt, ##__VA_ARGS__) #endif #define EXT4_MB_HISTORY_ALLOC 1 /* allocation */ diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index f92f10d4f66ac..104f8bfba7182 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -577,12 +577,13 @@ static inline unsigned dx_node_limit(struct inode *dir) static void dx_show_index(char * label, struct dx_entry *entries) { int i, n = dx_get_count (entries); - printk(KERN_DEBUG "%s index ", label); + printk(KERN_DEBUG "%s index", label); for (i = 0; i < n; i++) { - printk("%x->%lu ", i ? dx_get_hash(entries + i) : - 0, (unsigned long)dx_get_block(entries + i)); + printk(KERN_CONT " %x->%lu", + i ? dx_get_hash(entries + i) : 0, + (unsigned long)dx_get_block(entries + i)); } - printk("\n"); + printk(KERN_CONT "\n"); } struct stats @@ -679,7 +680,7 @@ static struct stats dx_show_leaf(struct inode *dir, } de = ext4_next_entry(de, size); } - printk("(%i)\n", names); + printk(KERN_CONT "(%i)\n", names); return (struct stats) { names, space, 1 }; } @@ -798,7 +799,7 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, q = entries + count - 1; while (p <= q) { m = p + (q - p) / 2; - dxtrace(printk(".")); + dxtrace(printk(KERN_CONT ".")); if (dx_get_hash(m) > hash) q = m - 1; else @@ -810,7 +811,7 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, at = entries; while (n--) { - dxtrace(printk(",")); + dxtrace(printk(KERN_CONT ",")); if (dx_get_hash(++at) > hash) { at--; @@ -821,7 +822,8 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, } at = p - 1; - dxtrace(printk(" %x->%u\n", at == entries ? 0 : dx_get_hash(at), + dxtrace(printk(KERN_CONT " %x->%u\n", + at == entries ? 0 : dx_get_hash(at), dx_get_block(at))); frame->entries = entries; frame->at = at; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index e90c5cd04d89f..d77be9e9f5352 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -61,18 +61,12 @@ #include "acl.h" #ifdef EXT4_XATTR_DEBUG -# define ea_idebug(inode, f...) do { \ - printk(KERN_DEBUG "inode %s:%lu: ", \ - inode->i_sb->s_id, inode->i_ino); \ - printk(f); \ - printk("\n"); \ - } while (0) -# define ea_bdebug(bh, f...) do { \ - printk(KERN_DEBUG "block %pg:%lu: ", \ - bh->b_bdev, (unsigned long) bh->b_blocknr); \ - printk(f); \ - printk("\n"); \ - } while (0) +# define ea_idebug(inode, fmt, ...) \ + printk(KERN_DEBUG "inode %s:%lu: " fmt "\n", \ + inode->i_sb->s_id, inode->i_ino, ##__VA_ARGS__) +# define ea_bdebug(bh, fmt, ...) \ + printk(KERN_DEBUG "block %pg:%lu: " fmt "\n", \ + bh->b_bdev, (unsigned long)bh->b_blocknr, ##__VA_ARGS__) #else # define ea_idebug(inode, fmt, ...) no_printk(fmt, ##__VA_ARGS__) # define ea_bdebug(bh, fmt, ...) no_printk(fmt, ##__VA_ARGS__) -- GitLab From 1001354ca34179f3db924eb66672442a173147dc Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 15 Oct 2016 12:17:50 -0700 Subject: [PATCH 0586/1167] Linux 4.9-rc1 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index d8c784dff8318..512e47a53e9ae 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 -PATCHLEVEL = 8 +PATCHLEVEL = 9 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Psychotic Stoned Sheep # *DOCUMENTATION* -- GitLab From 87c0fded852ae20bddb7833da6ead082404de86a Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Thu, 29 Sep 2016 13:41:05 +0200 Subject: [PATCH 0587/1167] rbd: don't wait for the lock forever if blacklisted -EBLACKLISTED from __rbd_register_watch() means that our ceph_client got blacklisted - we won't be able to restore the watch and reacquire the lock. Wake up and fail all outstanding requests waiting for the lock and arrange for all new requests that require the lock to fail immediately. Signed-off-by: Ilya Dryomov Tested-by: Mike Christie --- drivers/block/rbd.c | 50 ++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index abb71628ab614..633e8c2ea1201 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -415,15 +415,15 @@ struct rbd_device { }; /* - * Flag bits for rbd_dev->flags. If atomicity is required, - * rbd_dev->lock is used to protect access. - * - * Currently, only the "removing" flag (which is coupled with the - * "open_count" field) requires atomic access. + * Flag bits for rbd_dev->flags: + * - REMOVING (which is coupled with rbd_dev->open_count) is protected + * by rbd_dev->lock + * - BLACKLISTED is protected by rbd_dev->lock_rwsem */ enum rbd_dev_flags { RBD_DEV_FLAG_EXISTS, /* mapped snapshot has not been deleted */ RBD_DEV_FLAG_REMOVING, /* this mapping is being removed */ + RBD_DEV_FLAG_BLACKLISTED, /* our ceph_client is blacklisted */ }; static DEFINE_MUTEX(client_mutex); /* Serialize client creation */ @@ -3926,6 +3926,7 @@ static void rbd_reregister_watch(struct work_struct *work) struct rbd_device *rbd_dev = container_of(to_delayed_work(work), struct rbd_device, watch_dwork); bool was_lock_owner = false; + bool need_to_wake = false; int ret; dout("%s rbd_dev %p\n", __func__, rbd_dev); @@ -3935,19 +3936,27 @@ static void rbd_reregister_watch(struct work_struct *work) was_lock_owner = rbd_release_lock(rbd_dev); mutex_lock(&rbd_dev->watch_mutex); - if (rbd_dev->watch_state != RBD_WATCH_STATE_ERROR) - goto fail_unlock; + if (rbd_dev->watch_state != RBD_WATCH_STATE_ERROR) { + mutex_unlock(&rbd_dev->watch_mutex); + goto out; + } ret = __rbd_register_watch(rbd_dev); if (ret) { rbd_warn(rbd_dev, "failed to reregister watch: %d", ret); - if (ret != -EBLACKLISTED) + if (ret == -EBLACKLISTED) { + set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags); + need_to_wake = true; + } else { queue_delayed_work(rbd_dev->task_wq, &rbd_dev->watch_dwork, RBD_RETRY_DELAY); - goto fail_unlock; + } + mutex_unlock(&rbd_dev->watch_mutex); + goto out; } + need_to_wake = true; rbd_dev->watch_state = RBD_WATCH_STATE_REGISTERED; rbd_dev->watch_cookie = rbd_dev->watch_handle->linger_id; mutex_unlock(&rbd_dev->watch_mutex); @@ -3963,13 +3972,10 @@ static void rbd_reregister_watch(struct work_struct *work) ret); } +out: up_write(&rbd_dev->lock_rwsem); - wake_requests(rbd_dev, true); - return; - -fail_unlock: - mutex_unlock(&rbd_dev->watch_mutex); - up_write(&rbd_dev->lock_rwsem); + if (need_to_wake) + wake_requests(rbd_dev, true); } /* @@ -4074,7 +4080,9 @@ static void rbd_wait_state_locked(struct rbd_device *rbd_dev) up_read(&rbd_dev->lock_rwsem); schedule(); down_read(&rbd_dev->lock_rwsem); - } while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED); + } while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED && + !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)); + finish_wait(&rbd_dev->lock_waitq, &wait); } @@ -4166,8 +4174,16 @@ static void rbd_queue_workfn(struct work_struct *work) if (must_be_locked) { down_read(&rbd_dev->lock_rwsem); - if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED) + if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED && + !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) rbd_wait_state_locked(rbd_dev); + + WARN_ON((rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) ^ + !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)); + if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) { + result = -EBLACKLISTED; + goto err_unlock; + } } img_request = rbd_img_request_create(rbd_dev, offset, length, op_type, -- GitLab From 4d73644bc3d76dd161a84e3849c6f2c9c01c4ba7 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Thu, 29 Sep 2016 14:23:12 +0200 Subject: [PATCH 0588/1167] rbd: don't retry watch reregistration if header object is gone If the header object gets deleted (perhaps along with the entire pool), there is no point in attempting to reregister the watch. Treat this the same as blacklisting: fail all pending and new I/Os requiring the lock. Signed-off-by: Ilya Dryomov --- drivers/block/rbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 633e8c2ea1201..7b274ff4632c6 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3944,7 +3944,7 @@ static void rbd_reregister_watch(struct work_struct *work) ret = __rbd_register_watch(rbd_dev); if (ret) { rbd_warn(rbd_dev, "failed to reregister watch: %d", ret); - if (ret == -EBLACKLISTED) { + if (ret == -EBLACKLISTED || ret == -ENOENT) { set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags); need_to_wake = true; } else { -- GitLab From 0d7718f666be181fda1ba2d08f137d87c1419347 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Mon, 10 Oct 2016 15:38:18 +0300 Subject: [PATCH 0589/1167] ceph: fix error handling in ceph_read_iter In case __ceph_do_getattr returns an error and the retry_op in ceph_read_iter is not READ_INLINE, then it's possible to invoke __free_page on a page which is NULL, this naturally leads to a crash. This can happen when, for example, a process waiting on a MDS reply receives sigterm. Fix this by explicitly checking whether the page is set or not. Cc: stable@vger.kernel.org # 3.19+ Signed-off-by: Nikolay Borisov Reviewed-by: Yan, Zheng Signed-off-by: Ilya Dryomov --- fs/ceph/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 7bf08825cc110..18630e8002080 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -1272,7 +1272,8 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to) statret = __ceph_do_getattr(inode, page, CEPH_STAT_CAP_INLINE_DATA, !!page); if (statret < 0) { - __free_page(page); + if (page) + __free_page(page); if (statret == -ENODATA) { BUG_ON(retry_op != READ_INLINE); goto again; -- GitLab From f0076436136751359e0886f3302a2a0b3a28ba6e Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 14 Oct 2016 14:40:33 +0100 Subject: [PATCH 0590/1167] r8169: set coherent DMA mask as well as streaming DMA mask PCI devices that are 64-bit DMA capable should set the coherent DMA mask as well as the streaming DMA mask. On some architectures, these are managed separately, and so the coherent DMA mask will be left at its default value of 32 if it is not set explicitly. This results in errors such as r8169 Gigabit Ethernet driver 2.3LK-NAPI loaded hwdev DMA mask = 0x00000000ffffffff, dev_addr = 0x00000080fbfff000 swiotlb: coherent allocation failed for device 0000:02:00.0 size=4096 CPU: 0 PID: 1062 Comm: systemd-udevd Not tainted 4.8.0+ #35 Hardware name: AMD Seattle/Seattle, BIOS 10:53:24 Oct 13 2016 on systems without memory that is 32-bit addressable by PCI devices. Signed-off-by: Ard Biesheuvel Acked-by: Francois Romieu Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index e55638c7505a7..bf000d819a21a 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -8273,7 +8273,8 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if ((sizeof(dma_addr_t) > 4) && (use_dac == 1 || (use_dac == -1 && pci_is_pcie(pdev) && tp->mac_version >= RTL_GIGA_MAC_VER_18)) && - !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && + !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { /* CPlusCmd Dual Access Cycle is only needed for non-PCIe */ if (!pci_is_pcie(pdev)) -- GitLab From 93966b715b32a783a1641f5a385901bbfab04733 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 14 Oct 2016 14:14:35 -0500 Subject: [PATCH 0591/1167] net: qcom/emac: disable interrupts before calling phy_disconnect There is a race condition that can occur if EMAC interrupts are enabled when phy_disconnect() is called. phy_disconnect() sets adjust_link to NULL. When an interrupt occurs, the ISR might call phy_mac_interrupt(), which wakes up the workqueue function phy_state_machine(). This function might reference adjust_link, thereby causing a null pointer exception. Signed-off-by: Timur Tabi Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/emac/emac-mac.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/emac/emac-mac.c b/drivers/net/ethernet/qualcomm/emac/emac-mac.c index e97968ed4b8f7..6fb3bee904d38 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-mac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-mac.c @@ -1021,14 +1021,18 @@ void emac_mac_down(struct emac_adapter *adpt) napi_disable(&adpt->rx_q.napi); phy_stop(adpt->phydev); - phy_disconnect(adpt->phydev); - /* disable mac irq */ + /* Interrupts must be disabled before the PHY is disconnected, to + * avoid a race condition where adjust_link is null when we get + * an interrupt. + */ writel(DIS_INT, adpt->base + EMAC_INT_STATUS); writel(0, adpt->base + EMAC_INT_MASK); synchronize_irq(adpt->irq.irq); free_irq(adpt->irq.irq, &adpt->irq); + phy_disconnect(adpt->phydev); + emac_mac_reset(adpt); emac_tx_q_descs_free(adpt); -- GitLab From 50756ebecf69276b8a908409fa32c123bb12420b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Oct 2016 22:26:11 +0300 Subject: [PATCH 0592/1167] stmmac: fix an error code in stmmac_ptp_register() PTR_ERR(NULL) is success. We have to preserve the error code earlier. Fixes: 7086605a6ab5 ("stmmac: fix error check when init ptp") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index 289d52725a6c1..5d61fb27219ac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -185,8 +185,10 @@ int stmmac_ptp_register(struct stmmac_priv *priv) priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops, priv->device); if (IS_ERR(priv->ptp_clock)) { + int ret = PTR_ERR(priv->ptp_clock); + priv->ptp_clock = NULL; - return PTR_ERR(priv->ptp_clock); + return ret; } spin_lock_init(&priv->ptp_lock); -- GitLab From fb5c6cfaec126d9a96b9dd471d4711bf4c737a6f Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 15 Oct 2016 00:01:20 +0300 Subject: [PATCH 0593/1167] vmxnet3: avoid assumption about invalid dma_pa in vmxnet3_set_mc() vmxnet3_set_mc() checks new_table_pa returned by dma_map_single() with dma_mapping_error(), but even there it assumes zero is invalid pa (it assumes dma_mapping_error(...,0) returns true if new_table is NULL). The patch adds an explicit variable to track status of new_table_pa. Found by Linux Driver Verification project (linuxtesting.org). v2: use "bool" and "true"/"false" for boolean variables. Signed-off-by: Alexey Khoroshilov Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_drv.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index b5554f2ebee4e..ef83ae3b0a44a 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2279,6 +2279,7 @@ vmxnet3_set_mc(struct net_device *netdev) &adapter->shared->devRead.rxFilterConf; u8 *new_table = NULL; dma_addr_t new_table_pa = 0; + bool new_table_pa_valid = false; u32 new_mode = VMXNET3_RXM_UCAST; if (netdev->flags & IFF_PROMISC) { @@ -2307,13 +2308,15 @@ vmxnet3_set_mc(struct net_device *netdev) new_table, sz, PCI_DMA_TODEVICE); + if (!dma_mapping_error(&adapter->pdev->dev, + new_table_pa)) { + new_mode |= VMXNET3_RXM_MCAST; + new_table_pa_valid = true; + rxConf->mfTablePA = cpu_to_le64( + new_table_pa); + } } - - if (!dma_mapping_error(&adapter->pdev->dev, - new_table_pa)) { - new_mode |= VMXNET3_RXM_MCAST; - rxConf->mfTablePA = cpu_to_le64(new_table_pa); - } else { + if (!new_table_pa_valid) { netdev_info(netdev, "failed to copy mcast list, setting ALL_MULTI\n"); new_mode |= VMXNET3_RXM_ALL_MULTI; @@ -2338,7 +2341,7 @@ vmxnet3_set_mc(struct net_device *netdev) VMXNET3_CMD_UPDATE_MAC_FILTERS); spin_unlock_irqrestore(&adapter->cmd_lock, flags); - if (new_table_pa) + if (new_table_pa_valid) dma_unmap_single(&adapter->pdev->dev, new_table_pa, rxConf->mfTableLen, PCI_DMA_TODEVICE); kfree(new_table); -- GitLab From 0362fcc9d6834034bc0cdb1d9b02a1b9baf96a2a Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 22 Sep 2016 12:02:19 +0800 Subject: [PATCH 0594/1167] arm64: dts: rockchip: remove always-on and boot-on from vcc_sd Please don't add these for vcc_sd, and mmc-core/driver will control it. Otherwise, it will waste energy even without sdmmc in slot. Moreover, it will causes a bug: If we insert/remove sd card, we could see [9.337271] mmc0: new ultra high speed SDR25 SDHC card at address 0007 [9.345144] mmcblk0: mmc0:0007 SD32G 29.3 GiB This is okay for normal sd insert/remove test, but when I debug some issues for sdmmc, I did unbind/bind test. And there is a interesting phenomenon when we bind the driver again: [58.314069] mmc0: new high speed SDHC card at address 0007 [58.320282] mmcblk0: mmc0:0007 SD32G 29.3 GiB So the sd card could just support high speed without power cycle since the vcc_sd is always on, which makes the sd card fail to reinit its internal ocr mask. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts | 2 -- arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts | 2 -- 2 files changed, 4 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts index 46cdddfcea6c4..353314ca74269 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts @@ -258,8 +258,6 @@ }; vcc_sd: SWITCH_REG1 { - regulator-always-on; - regulator-boot-on; regulator-name = "vcc_sd"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts index 5797933ef80e6..13b7f1edad104 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts @@ -152,8 +152,6 @@ gpio = <&gpio3 11 GPIO_ACTIVE_LOW>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-boot-on; vin-supply = <&vcc_io>; }; -- GitLab From 3732710ff6f2ce2b1b7f044937a422b717d4f953 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 13 Oct 2016 16:22:52 -0500 Subject: [PATCH 0595/1167] objtool: Improve rare switch jump table pattern detection GCC 6 added a new switch statement jump table optimization which makes objtool's life harder. It looks like: mov [rodata addr],%reg1 ... some instructions ... jmpq *(%reg1,%reg2,8) The optimization is quite rare, but objtool still needs to be able to identify the pattern so that it can follow all possible control flow paths related to the switch statement. In order to detect the pattern, objtool starts from the indirect jump and scans backwards through the function until it finds the first instruction in the pattern. If it encounters an unconditional jump along the way, it stops and considers the pattern to be not found. As it turns out, unconditional jumps can happen, as long as they are small forward jumps within the range being scanned. This fixes the following warnings: drivers/infiniband/sw/rxe/rxe_comp.o: warning: objtool: rxe_completer()+0x2f4: sibling call from callable instruction with changed frame pointer drivers/infiniband/sw/rxe/rxe_resp.o: warning: objtool: rxe_responder()+0x10f: sibling call from callable instruction with changed frame pointer Reported-by: Arnd Bergmann Signed-off-by: Josh Poimboeuf Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/8a9ed68ae1780e8d3963e4ee13f2f257fe3a3c33.1476393584.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar --- tools/objtool/builtin-check.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 143b6cdd7f068..a00a05d287e7e 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -713,6 +713,7 @@ static struct rela *find_switch_table(struct objtool_file *file, struct instruction *insn) { struct rela *text_rela, *rodata_rela; + struct instruction *orig_insn = insn; text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); if (text_rela && text_rela->sym == file->rodata->sym) { @@ -733,10 +734,16 @@ static struct rela *find_switch_table(struct objtool_file *file, /* case 3 */ func_for_each_insn_continue_reverse(file, func, insn) { - if (insn->type == INSN_JUMP_UNCONDITIONAL || - insn->type == INSN_JUMP_DYNAMIC) + if (insn->type == INSN_JUMP_DYNAMIC) break; + /* allow small jumps within the range */ + if (insn->type == INSN_JUMP_UNCONDITIONAL && + insn->jump_dest && + (insn->jump_dest->offset <= insn->offset || + insn->jump_dest->offset >= orig_insn->offset)) + break; + text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); if (text_rela && text_rela->sym == file->rodata->sym) -- GitLab From 9cfffb116887b1b7c51cd4e3fa5790dc52a0758f Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 13 Oct 2016 16:22:53 -0500 Subject: [PATCH 0596/1167] objtool: Skip all "unreachable instruction" warnings for gcov kernels Recently objtool has started reporting a few "unreachable instruction" warnings when CONFIG_GCOV is enabled for newer versions of GCC. Usually this warning means there's some new control flow that objtool doesn't understand. But in this case, objtool is correct and the instructions really are inaccessible. It's an annoying quirk of gcov, but it's harmless, so it's ok to just silence the warnings. With older versions of GCC, it was relatively easy to detect gcov-specific instructions and to skip any unreachable warnings produced by them. But GCC 6 has gotten craftier. Instead of continuing to play whack-a-mole with gcov, just use a bigger, more permanent hammer and disable unreachable warnings for the whole file when gcov is enabled. This is fine to do because a) unreachable warnings are usually of questionable value; and b) gcov isn't used for production kernels and we can relax the checks a bit there. Reported-by: kbuild test robot Signed-off-by: Josh Poimboeuf Cc: Andy Lutomirski Cc: Arnd Bergmann Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/38d5c87d61d9cd46486dd2c86f46603dff0df86f.1476393584.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar --- tools/objtool/builtin-check.c | 57 ++++++++++++++++------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index a00a05d287e7e..4490601a92354 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -97,6 +97,19 @@ static struct instruction *next_insn_same_sec(struct objtool_file *file, return next; } +static bool gcov_enabled(struct objtool_file *file) +{ + struct section *sec; + struct symbol *sym; + + list_for_each_entry(sec, &file->elf->sections, list) + list_for_each_entry(sym, &sec->symbol_list, list) + if (!strncmp(sym->name, "__gcov_.", 8)) + return true; + + return false; +} + #define for_each_insn(file, insn) \ list_for_each_entry(insn, &file->insn_list, list) @@ -1041,34 +1054,6 @@ static int validate_branch(struct objtool_file *file, return 0; } -static bool is_gcov_insn(struct instruction *insn) -{ - struct rela *rela; - struct section *sec; - struct symbol *sym; - unsigned long offset; - - rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); - if (!rela) - return false; - - if (rela->sym->type != STT_SECTION) - return false; - - sec = rela->sym->sec; - offset = rela->addend + insn->offset + insn->len - rela->offset; - - list_for_each_entry(sym, &sec->symbol_list, list) { - if (sym->type != STT_OBJECT) - continue; - - if (offset >= sym->offset && offset < sym->offset + sym->len) - return (!memcmp(sym->name, "__gcov0.", 8)); - } - - return false; -} - static bool is_kasan_insn(struct instruction *insn) { return (insn->type == INSN_CALL && @@ -1090,9 +1075,6 @@ static bool ignore_unreachable_insn(struct symbol *func, if (insn->type == INSN_NOP) return true; - if (is_gcov_insn(insn)) - return true; - /* * Check if this (or a subsequent) instruction is related to * CONFIG_UBSAN or CONFIG_KASAN. @@ -1153,6 +1135,19 @@ static int validate_functions(struct objtool_file *file) ignore_unreachable_insn(func, insn)) continue; + /* + * gcov produces a lot of unreachable + * instructions. If we get an unreachable + * warning and the file has gcov enabled, just + * ignore it, and all other such warnings for + * the file. + */ + if (!file->ignore_unreachables && + gcov_enabled(file)) { + file->ignore_unreachables = true; + continue; + } + WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset); warnings++; } -- GitLab From 9254139ad083433c50ba62920107ed55fc4ca5e2 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 11 Oct 2016 14:13:38 +0200 Subject: [PATCH 0597/1167] kprobes: Avoid false KASAN reports during stack copy Kprobes save and restore raw stack chunks with memcpy(). With KASAN these chunks can contain poisoned stack redzones, as the result memcpy() interceptor produces false stack out-of-bounds reports. Use __memcpy() instead of memcpy() for stack copying. __memcpy() is not instrumented by KASAN and does not lead to the false reports. Currently there is a spew of KASAN reports during boot if CONFIG_KPROBES_SANITY_TEST is enabled: [ ] Kprobe smoke test: started [ ] ================================================================== [ ] BUG: KASAN: stack-out-of-bounds in setjmp_pre_handler+0x17c/0x280 at addr ffff88085259fba8 [ ] Read of size 64 by task swapper/0/1 [ ] page:ffffea00214967c0 count:0 mapcount:0 mapping: (null) index:0x0 [ ] flags: 0x2fffff80000000() [ ] page dumped because: kasan: bad access detected [...] Reported-by: CAI Qian Tested-by: CAI Qian Signed-off-by: Dmitry Vyukov Acked-by: Masami Hiramatsu Cc: Alexander Potapenko Cc: Alexander Shishkin Cc: Ananth N Mavinakayanahalli Cc: Andrew Morton Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Anil S Keshavamurthy Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: David S. Miller Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: kasan-dev@googlegroups.com [ Improved various details. ] Signed-off-by: Ingo Molnar --- arch/x86/kernel/kprobes/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 28cee019209ce..f423b0ef23a72 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -1057,9 +1057,10 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) * tailcall optimization. So, to be absolutely safe * we also save and restore enough stack bytes to cover * the argument area. + * Use __memcpy() to avoid KASAN stack out-of-bounds reports as we copy + * raw stack chunk with redzones: */ - memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr, - MIN_STACK_SIZE(addr)); + __memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr, MIN_STACK_SIZE(addr)); regs->flags &= ~X86_EFLAGS_IF; trace_hardirqs_off(); regs->ip = (unsigned long)(jp->entry); @@ -1118,7 +1119,7 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) /* It's OK to start function graph tracing again */ unpause_graph_tracing(); *regs = kcb->jprobe_saved_regs; - memcpy(saved_sp, kcb->jprobes_stack, MIN_STACK_SIZE(saved_sp)); + __memcpy(saved_sp, kcb->jprobes_stack, MIN_STACK_SIZE(saved_sp)); preempt_enable_no_resched(); return 1; } -- GitLab From 9f7d416c36124667c406978bcb39746589c35d7f Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 14 Oct 2016 16:07:23 +0200 Subject: [PATCH 0598/1167] kprobes: Unpoison stack in jprobe_return() for KASAN I observed false KSAN positives in the sctp code, when sctp uses jprobe_return() in jsctp_sf_eat_sack(). The stray 0xf4 in shadow memory are stack redzones: [ ] ================================================================== [ ] BUG: KASAN: stack-out-of-bounds in memcmp+0xe9/0x150 at addr ffff88005e48f480 [ ] Read of size 1 by task syz-executor/18535 [ ] page:ffffea00017923c0 count:0 mapcount:0 mapping: (null) index:0x0 [ ] flags: 0x1fffc0000000000() [ ] page dumped because: kasan: bad access detected [ ] CPU: 1 PID: 18535 Comm: syz-executor Not tainted 4.8.0+ #28 [ ] Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 [ ] ffff88005e48f2d0 ffffffff82d2b849 ffffffff0bc91e90 fffffbfff10971e8 [ ] ffffed000bc91e90 ffffed000bc91e90 0000000000000001 0000000000000000 [ ] ffff88005e48f480 ffff88005e48f350 ffffffff817d3169 ffff88005e48f370 [ ] Call Trace: [ ] [] dump_stack+0x12e/0x185 [ ] [] kasan_report+0x489/0x4b0 [ ] [] __asan_report_load1_noabort+0x19/0x20 [ ] [] memcmp+0xe9/0x150 [ ] [] depot_save_stack+0x176/0x5c0 [ ] [] save_stack+0xb1/0xd0 [ ] [] kasan_slab_free+0x72/0xc0 [ ] [] kfree+0xc8/0x2a0 [ ] [] skb_free_head+0x79/0xb0 [ ] [] skb_release_data+0x37a/0x420 [ ] [] skb_release_all+0x4f/0x60 [ ] [] consume_skb+0x138/0x370 [ ] [] sctp_chunk_put+0xcb/0x180 [ ] [] sctp_chunk_free+0x58/0x70 [ ] [] sctp_inq_pop+0x68f/0xef0 [ ] [] sctp_assoc_bh_rcv+0xd6/0x4b0 [ ] [] sctp_inq_push+0x131/0x190 [ ] [] sctp_backlog_rcv+0xe9/0xa20 [ ... ] [ ] Memory state around the buggy address: [ ] ffff88005e48f380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ ] ffff88005e48f400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ ] >ffff88005e48f480: f4 f4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ ] ^ [ ] ffff88005e48f500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ ] ffff88005e48f580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ ] ================================================================== KASAN stack instrumentation poisons stack redzones on function entry and unpoisons them on function exit. If a function exits abnormally (e.g. with a longjmp like jprobe_return()), stack redzones are left poisoned. Later this leads to random KASAN false reports. Unpoison stack redzones in the frames we are going to jump over before doing actual longjmp in jprobe_return(). Signed-off-by: Dmitry Vyukov Acked-by: Masami Hiramatsu Reviewed-by: Mark Rutland Cc: Mark Rutland Cc: Catalin Marinas Cc: Andrey Ryabinin Cc: Lorenzo Pieralisi Cc: Alexander Potapenko Cc: Will Deacon Cc: Andrew Morton Cc: Ananth N Mavinakayanahalli Cc: Anil S Keshavamurthy Cc: "David S. Miller" Cc: Masami Hiramatsu Cc: kasan-dev@googlegroups.com Cc: surovegin@google.com Cc: rostedt@goodmis.org Link: http://lkml.kernel.org/r/1476454043-101898-1-git-send-email-dvyukov@google.com Signed-off-by: Ingo Molnar --- arch/arm64/kernel/sleep.S | 2 +- arch/x86/kernel/kprobes/core.c | 4 ++++ include/linux/kasan.h | 2 ++ mm/kasan/kasan.c | 22 +++++++++++++++++++--- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index b8799e7c79de5..1bec41b5fda39 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -135,7 +135,7 @@ ENTRY(_cpu_resume) #ifdef CONFIG_KASAN mov x0, sp - bl kasan_unpoison_remaining_stack + bl kasan_unpoison_task_stack_below #endif ldp x19, x20, [x29, #16] diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index f423b0ef23a72..d9d8d16b69db8 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -1081,6 +1082,9 @@ void jprobe_return(void) { struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + /* Unpoison stack redzones in the frames we are going to jump over. */ + kasan_unpoison_stack_above_sp_to(kcb->jprobe_saved_sp); + asm volatile ( #ifdef CONFIG_X86_64 " xchg %%rbx,%%rsp \n" diff --git a/include/linux/kasan.h b/include/linux/kasan.h index d600303306eb7..820c0ad54a011 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -44,6 +44,7 @@ static inline void kasan_disable_current(void) void kasan_unpoison_shadow(const void *address, size_t size); void kasan_unpoison_task_stack(struct task_struct *task); +void kasan_unpoison_stack_above_sp_to(const void *watermark); void kasan_alloc_pages(struct page *page, unsigned int order); void kasan_free_pages(struct page *page, unsigned int order); @@ -85,6 +86,7 @@ size_t kasan_metadata_size(struct kmem_cache *cache); static inline void kasan_unpoison_shadow(const void *address, size_t size) {} static inline void kasan_unpoison_task_stack(struct task_struct *task) {} +static inline void kasan_unpoison_stack_above_sp_to(const void *watermark) {} static inline void kasan_enable_current(void) {} static inline void kasan_disable_current(void) {} diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c index 88af13c00d3cb..70c009741aab7 100644 --- a/mm/kasan/kasan.c +++ b/mm/kasan/kasan.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "kasan.h" #include "../slab.h" @@ -62,7 +63,7 @@ void kasan_unpoison_shadow(const void *address, size_t size) } } -static void __kasan_unpoison_stack(struct task_struct *task, void *sp) +static void __kasan_unpoison_stack(struct task_struct *task, const void *sp) { void *base = task_stack_page(task); size_t size = sp - base; @@ -77,9 +78,24 @@ void kasan_unpoison_task_stack(struct task_struct *task) } /* Unpoison the stack for the current task beyond a watermark sp value. */ -asmlinkage void kasan_unpoison_remaining_stack(void *sp) +asmlinkage void kasan_unpoison_task_stack_below(const void *watermark) { - __kasan_unpoison_stack(current, sp); + __kasan_unpoison_stack(current, watermark); +} + +/* + * Clear all poison for the region between the current SP and a provided + * watermark value, as is sometimes required prior to hand-crafted asm function + * returns in the middle of functions. + */ +void kasan_unpoison_stack_above_sp_to(const void *watermark) +{ + const void *sp = __builtin_frame_address(0); + size_t size = watermark - sp; + + if (WARN_ON(sp > watermark)) + return; + kasan_unpoison_shadow(sp, size); } /* -- GitLab From a705e07b9c80df27b6bb12f7a4cd4cf4ed2f728b Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Wed, 12 Oct 2016 13:18:56 +0300 Subject: [PATCH 0599/1167] cpu/hotplug: Use distinct name for cpu_hotplug.dep_map Use distinctive name for cpu_hotplug.dep_map to avoid the actual cpu_hotplug.lock appearing as cpu_hotplug.lock#2 in lockdep splats. Signed-off-by: Joonas Lahtinen Reviewed-by: Chris Wilson Acked-by: Gautham R. Shenoy Cc: Andrew Morton Cc: Daniel Vetter Cc: Gautham R . Shenoy Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: intel-gfx@lists.freedesktop.org Cc: trivial@kernel.org Signed-off-by: Ingo Molnar --- kernel/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cpu.c b/kernel/cpu.c index 5df20d6d15207..29de1a9352c00 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -228,7 +228,7 @@ static struct { .wq = __WAIT_QUEUE_HEAD_INITIALIZER(cpu_hotplug.wq), .lock = __MUTEX_INITIALIZER(cpu_hotplug.lock), #ifdef CONFIG_DEBUG_LOCK_ALLOC - .dep_map = {.name = "cpu_hotplug.lock" }, + .dep_map = STATIC_LOCKDEP_MAP_INIT("cpu_hotplug.dep_map", &cpu_hotplug.dep_map), #endif }; -- GitLab From 23446cb66c073b827779e5eb3dec301623299b32 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 12 Oct 2016 11:01:48 -0700 Subject: [PATCH 0600/1167] x86/e820: Don't merge consecutive E820_PRAM ranges Commit: 917db484dc6a ("x86/boot: Fix kdump, cleanup aborted E820_PRAM max_pfn manipulation") ... fixed up the broken manipulations of max_pfn in the presence of E820_PRAM ranges. However, it also broke the sanitize_e820_map() support for not merging E820_PRAM ranges. Re-introduce the enabling to keep resource boundaries between consecutive defined ranges. Otherwise, for example, an environment that boots with memmap=2G!8G,2G!10G will end up with a single 4G /dev/pmem0 device instead of a /dev/pmem0 and /dev/pmem1 device 2G in size. Reported-by: Dave Chinner Signed-off-by: Dan Williams Cc: Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jeff Moyer Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Zhang Yi Cc: linux-nvdimm@lists.01.org Fixes: 917db484dc6a ("x86/boot: Fix kdump, cleanup aborted E820_PRAM max_pfn manipulation") Link: http://lkml.kernel.org/r/147629530854.10618.10383744751594021268.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/e820.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index b85fe5f91c3fe..90e8dde3ec26b 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -350,7 +350,7 @@ int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, * continue building up new bios map based on this * information */ - if (current_type != last_type) { + if (current_type != last_type || current_type == E820_PRAM) { if (last_type != 0) { new_bios[new_bios_entry].size = change_point[chgidx]->addr - last_addr; -- GitLab From 5c38181ce9c5182377e79271a3ed0a2d0e999c33 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Oct 2016 10:29:08 +0300 Subject: [PATCH 0601/1167] perf/x86/intel: Remove an inconsistent NULL check Smatch complains that we don't check "event->ctx" consistently. It's never NULL so we can just remove the check. Signed-off-by: Dan Carpenter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: David Carrillo-Cisneros Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: kernel-janitors@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- arch/x86/events/intel/lbr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index fc6cf21c535e1..81b321ace8e01 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -458,8 +458,8 @@ void intel_pmu_lbr_del(struct perf_event *event) if (!x86_pmu.lbr_nr) return; - if (branch_user_callstack(cpuc->br_sel) && event->ctx && - event->ctx->task_ctx_data) { + if (branch_user_callstack(cpuc->br_sel) && + event->ctx->task_ctx_data) { task_ctx = event->ctx->task_ctx_data; task_ctx->lbr_callstack_users--; } -- GitLab From 3ce0fefc51bd56381b1b9a92835cf8f9db3f2ef8 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 29 Sep 2016 10:00:14 -0700 Subject: [PATCH 0602/1167] ARCv2: intc: untangle SMP, MCIP and IDU The IDU intc is technically part of MCIP (Multi-core IP) hence historically was only available in a SMP hardware build (and thus only in a SMP kernel build). Now that hardware restriction has been lifted, so a UP kernel needs to support it. This requires breaking mcip.c into parts which are strictly SMP (inter-core interrupts) and IDU which in reality is just another intc and thus has no bearing on SMP. This change allows IDU in UP builds and with a suitable device tree, we can have the cascaded intc system ARCv2 core intc <---> ARCv2 IDU intc <---> periperals Signed-off-by: Vineet Gupta --- arch/arc/Kconfig | 17 +++++++++-------- arch/arc/include/asm/mcip.h | 16 ++++++++++++++++ arch/arc/kernel/mcip.c | 31 +++++++++++-------------------- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index ecd12379e2cdb..6f67895cd9c48 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -186,14 +186,6 @@ if SMP config ARC_HAS_COH_CACHES def_bool n -config ARC_MCIP - bool "ARConnect Multicore IP (MCIP) Support " - depends on ISA_ARCV2 - help - This IP block enables SMP in ARC-HS38 cores. - It provides for cross-core interrupts, multi-core debug - hardware semaphores, shared memory,.... - config NR_CPUS int "Maximum number of CPUs (2-4096)" range 2 4096 @@ -211,6 +203,15 @@ config ARC_SMP_HALT_ON_RESET endif #SMP +config ARC_MCIP + bool "ARConnect Multicore IP (MCIP) Support " + depends on ISA_ARCV2 + default y if SMP + help + This IP block enables SMP in ARC-HS38 cores. + It provides for cross-core interrupts, multi-core debug + hardware semaphores, shared memory,.... + menuconfig ARC_CACHE bool "Enable Cache Support" default y diff --git a/arch/arc/include/asm/mcip.h b/arch/arc/include/asm/mcip.h index 847e3bbe387fc..c8fbe4114badd 100644 --- a/arch/arc/include/asm/mcip.h +++ b/arch/arc/include/asm/mcip.h @@ -55,6 +55,22 @@ struct mcip_cmd { #define IDU_M_DISTRI_DEST 0x2 }; +struct mcip_bcr { +#ifdef CONFIG_CPU_BIG_ENDIAN + unsigned int pad3:8, + idu:1, llm:1, num_cores:6, + iocoh:1, gfrc:1, dbg:1, pad2:1, + msg:1, sem:1, ipi:1, pad:1, + ver:8; +#else + unsigned int ver:8, + pad:1, ipi:1, sem:1, msg:1, + pad2:1, dbg:1, gfrc:1, iocoh:1, + num_cores:6, llm:1, idu:1, + pad3:8; +#endif +}; + /* * MCIP programming model * diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 72f9179b1a246..c424d5abc318a 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -15,11 +15,12 @@ #include #include -static char smp_cpuinfo_buf[128]; -static int idu_detected; - static DEFINE_RAW_SPINLOCK(mcip_lock); +#ifdef CONFIG_SMP + +static char smp_cpuinfo_buf[128]; + static void mcip_setup_per_cpu(int cpu) { smp_ipi_irq_setup(cpu, IPI_IRQ); @@ -86,21 +87,7 @@ static void mcip_ipi_clear(int irq) static void mcip_probe_n_setup(void) { - struct mcip_bcr { -#ifdef CONFIG_CPU_BIG_ENDIAN - unsigned int pad3:8, - idu:1, llm:1, num_cores:6, - iocoh:1, gfrc:1, dbg:1, pad2:1, - msg:1, sem:1, ipi:1, pad:1, - ver:8; -#else - unsigned int ver:8, - pad:1, ipi:1, sem:1, msg:1, - pad2:1, dbg:1, gfrc:1, iocoh:1, - num_cores:6, llm:1, idu:1, - pad3:8; -#endif - } mp; + struct mcip_bcr mp; READ_BCR(ARC_REG_MCIP_BCR, mp); @@ -114,7 +101,6 @@ static void mcip_probe_n_setup(void) IS_AVAIL1(mp.gfrc, "GFRC")); cpuinfo_arc700[0].extn.gfrc = mp.gfrc; - idu_detected = mp.idu; if (mp.dbg) { __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf); @@ -130,6 +116,8 @@ struct plat_smp_ops plat_smp_ops = { .ipi_clear = mcip_ipi_clear, }; +#endif + /*************************************************************************** * ARCv2 Interrupt Distribution Unit (IDU) * @@ -295,8 +283,11 @@ idu_of_init(struct device_node *intc, struct device_node *parent) /* Read IDU BCR to confirm nr_irqs */ int nr_irqs = of_irq_count(intc); int i, irq; + struct mcip_bcr mp; + + READ_BCR(ARC_REG_MCIP_BCR, mp); - if (!idu_detected) + if (!mp.idu) panic("IDU not detected, but DeviceTree using it"); pr_info("MCIP: IDU referenced from Devicetree %d irqs\n", nr_irqs); -- GitLab From 27f3d2a3b59f573a398c9acc810c16ebca07be78 Mon Sep 17 00:00:00 2001 From: Daniel Mentz Date: Tue, 4 Oct 2016 16:34:27 -0700 Subject: [PATCH 0603/1167] ARC: [build] Support gz, lzma compressed uImage Add support for lzma compressed uImage. Support for gzip was already available but could not be enabled because we were missing CONFIG_HAVE_KERNEL_GZIP in arch/arc/Kconfig. Signed-off-by: Daniel Mentz Cc: linux-snps-arc@lists.infradead.org Cc: Vineet Gupta Signed-off-by: Vineet Gupta --- arch/arc/Kconfig | 2 ++ arch/arc/boot/Makefile | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 6f67895cd9c48..ac0b309aced59 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -41,6 +41,8 @@ config ARC select PERF_USE_VMALLOC select HAVE_DEBUG_STACKOVERFLOW select HAVE_GENERIC_DMA_COHERENT + select HAVE_KERNEL_GZIP + select HAVE_KERNEL_LZMA config MIGHT_HAVE_PCI bool diff --git a/arch/arc/boot/Makefile b/arch/arc/boot/Makefile index e597cb34c16a8..f94cf151e06ab 100644 --- a/arch/arc/boot/Makefile +++ b/arch/arc/boot/Makefile @@ -14,9 +14,15 @@ UIMAGE_ENTRYADDR = $(LINUX_START_TEXT) suffix-y := bin suffix-$(CONFIG_KERNEL_GZIP) := gz +suffix-$(CONFIG_KERNEL_LZMA) := lzma -targets += uImage uImage.bin uImage.gz -extra-y += vmlinux.bin vmlinux.bin.gz +targets += uImage +targets += uImage.bin +targets += uImage.gz +targets += uImage.lzma +extra-y += vmlinux.bin +extra-y += vmlinux.bin.gz +extra-y += vmlinux.bin.lzma $(obj)/vmlinux.bin: vmlinux FORCE $(call if_changed,objcopy) @@ -24,12 +30,18 @@ $(obj)/vmlinux.bin: vmlinux FORCE $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE $(call if_changed,gzip) +$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE + $(call if_changed,lzma) + $(obj)/uImage.bin: $(obj)/vmlinux.bin FORCE $(call if_changed,uimage,none) $(obj)/uImage.gz: $(obj)/vmlinux.bin.gz FORCE $(call if_changed,uimage,gzip) +$(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma FORCE + $(call if_changed,uimage,lzma) + $(obj)/uImage: $(obj)/uImage.$(suffix-y) @ln -sf $(notdir $<) $@ @echo ' Image $@ is ready' -- GitLab From fa860a1751e388385a7f249dd3f24a6c76db0ba9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 13 Oct 2016 16:13:44 +0200 Subject: [PATCH 0604/1167] drm: Print device information again in debugfs I was a bit over-eager in my cleanup in commit 95c081c17f284de50eaca60d4d55643a64d39019 Author: Daniel Vetter Date: Tue Jun 21 10:54:12 2016 +0200 drm: Move master pointer from drm_minor to drm_device Noticed by Chris Wilson. Fixes: 95c081c17f28 ("drm: Move master pointer from drm_minor to drm_device") Cc: Chris Wilson Cc: Chris Wilson Cc: Daniel Vetter Cc: Emil Velikov Cc: Julia Lawall Signed-off-by: Daniel Vetter Reviewed-by: Alex Deucher Tested-by: Chris Wilson Reviewed-by: Emil Velikov Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_info.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index 1df2d33d0b40e..ffb2ab389d1d1 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -54,9 +54,6 @@ int drm_name_info(struct seq_file *m, void *data) mutex_lock(&dev->master_mutex); master = dev->master; - if (!master) - goto out_unlock; - seq_printf(m, "%s", dev->driver->name); if (dev->dev) seq_printf(m, " dev=%s", dev_name(dev->dev)); @@ -65,7 +62,6 @@ int drm_name_info(struct seq_file *m, void *data) if (dev->unique) seq_printf(m, " unique=%s", dev->unique); seq_printf(m, "\n"); -out_unlock: mutex_unlock(&dev->master_mutex); return 0; -- GitLab From 039bea844016ae85eaf195bf25266b5eb028a319 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 12 Oct 2016 08:02:21 +0530 Subject: [PATCH 0605/1167] Staging: greybus: gpio: Use gbphy_dev->dev instead of bundle->dev Some of the print messages are using the incorrect device pointer, fix them. Signed-off-by: Viresh Kumar Acked-by: Johan Hovold Reviewed-by: Rui Miguel Silva Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/gpio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c index 5e06e4229e423..250caa00de5e9 100644 --- a/drivers/staging/greybus/gpio.c +++ b/drivers/staging/greybus/gpio.c @@ -702,15 +702,13 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev, ret = gb_gpio_irqchip_add(gpio, irqc, 0, handle_level_irq, IRQ_TYPE_NONE); if (ret) { - dev_err(&connection->bundle->dev, - "failed to add irq chip: %d\n", ret); + dev_err(&gbphy_dev->dev, "failed to add irq chip: %d\n", ret); goto exit_line_free; } ret = gpiochip_add(gpio); if (ret) { - dev_err(&connection->bundle->dev, - "failed to add gpio chip: %d\n", ret); + dev_err(&gbphy_dev->dev, "failed to add gpio chip: %d\n", ret); goto exit_gpio_irqchip_remove; } -- GitLab From 4fa589126f23243bd998a464cb6158d343eb6a89 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 12 Oct 2016 08:02:22 +0530 Subject: [PATCH 0606/1167] Staging: greybus: uart: Use gbphy_dev->dev instead of bundle->dev Some of the print messages are using the incorrect device pointer, fix them. Signed-off-by: Viresh Kumar Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index 5ee7954bd9f91..2633d2bfb1b4f 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -888,7 +888,7 @@ static int gb_uart_probe(struct gbphy_device *gbphy_dev, minor = alloc_minor(gb_tty); if (minor < 0) { if (minor == -ENOSPC) { - dev_err(&connection->bundle->dev, + dev_err(&gbphy_dev->dev, "no more free minor numbers\n"); retval = -ENODEV; } else { -- GitLab From 0047b6e5f1b45b391244d78097631eb09a960202 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2016 09:20:22 +0300 Subject: [PATCH 0607/1167] staging: android/ion: testing the wrong variable We're testing "pdev" but we intended to test "heap_pdev". This is a static checker fix and it's unlikely that anyone is affected by this bug. Fixes: 13439479c7de ('staging: ion: Add files for parsing the devicetree') Signed-off-by: Dan Carpenter Acked-by: Laura Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion_of.c b/drivers/staging/android/ion/ion_of.c index 15bac92b7f042..46b2bb99bfd6b 100644 --- a/drivers/staging/android/ion/ion_of.c +++ b/drivers/staging/android/ion/ion_of.c @@ -107,7 +107,7 @@ struct ion_platform_data *ion_parse_dt(struct platform_device *pdev, heap_pdev = of_platform_device_create(node, heaps[i].name, &pdev->dev); - if (!pdev) + if (!heap_pdev) return ERR_PTR(-ENOMEM); heap_pdev->dev.platform_data = &heaps[i]; -- GitLab From 1d4f1d53e1e2d5e38f4d3ca3bf60f8be5025540f Mon Sep 17 00:00:00 2001 From: Aditya Shankar Date: Fri, 7 Oct 2016 09:45:03 +0530 Subject: [PATCH 0608/1167] Staging: wilc1000: Fix kernel Oops on opening the device Commit 2518ac59eb27 ("staging: wilc1000: Replace kthread with workqueue for host interface") adds an unconditional destroy_workqueue() on the wilc's "hif_workqueue" soon after its creation thereby rendering it unusable. It then further attempts to queue work onto this non-existing hif_worqueue and results in: Unable to handle kernel NULL pointer dereference at virtual address 00000010 pgd = de478000 [00000010] *pgd=3eec0831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] ARM Modules linked in: wilc1000_sdio(C) wilc1000(C) CPU: 0 PID: 825 Comm: ifconfig Tainted: G C 4.8.0-rc8+ #37 Hardware name: Atmel SAMA5 task: df56f800 task.stack: deeb0000 PC is at __queue_work+0x90/0x284 LR is at __queue_work+0x58/0x284 pc : [] lr : [] psr: 600f0093 sp : deeb1aa0 ip : def22d78 fp : deea6000 r10: 00000000 r9 : c0a08150 r8 : c0a2f058 r7 : 00000001 r6 : dee9b600 r5 : def22d74 r4 : 00000000 r3 : 00000000 r2 : def22d74 r1 : 07ffffff r0 : 00000000 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none ... [] (__queue_work) from [] (queue_work_on+0x34/0x40) [] (queue_work_on) from [] (wilc_enqueue_cmd+0x54/0x64 [wilc1000]) [] (wilc_enqueue_cmd [wilc1000]) from [] (wilc_set_wfi_drv_handler+0x48/0x70 [wilc1000]) [] (wilc_set_wfi_drv_handler [wilc1000]) from [] (wilc_mac_open+0x214/0x250 [wilc1000]) [] (wilc_mac_open [wilc1000]) from [] (__dev_open+0xb8/0x11c) [] (__dev_open) from [] (__dev_change_flags+0x94/0x158) [] (__dev_change_flags) from [] (dev_change_flags+0x18/0x48) [] (dev_change_flags) from [] (devinet_ioctl+0x6b4/0x788) [] (devinet_ioctl) from [] (sock_ioctl+0x154/0x2cc) [] (sock_ioctl) from [] (do_vfs_ioctl+0x9c/0x878) [] (do_vfs_ioctl) from [] (SyS_ioctl+0x34/0x5c) [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x3c) Code: e5932004 e1520006 01a04003 0affffff (e5943010) ---[ end trace b612328adaa6bf20 ]--- This fix removes the unnecessary call to destroy_workqueue() while opening the device to avoid the above kernel panic. The deinit routine already does a good job of terminating the workqueue when no longer needed. Reported-by: Nicolas Ferre Fixes: 2518ac59eb27 ("staging: wilc1000: Replace kthread with workqueue for host interface") Cc: stable@vger.kernel.org # 4.8+ Signed-off-by: Aditya Shankar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 78f5613e9467c..6ab7443eabdef 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -3388,7 +3388,6 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler) clients_count++; - destroy_workqueue(hif_workqueue); _fail_: return result; } -- GitLab From c89d98e224b4858f42a9fec0f16766b3d7669ba3 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Sun, 16 Oct 2016 13:16:50 -0400 Subject: [PATCH 0609/1167] staging/lustre/llite: Move unstable_stats from sysfs to debugfs It's multiple values per file, so it has no business being in sysfs, besides it was assuming seqfile anyway. Fixes: d806f30e639b ("staging: lustre: osc: revise unstable pages accounting") Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- .../staging/lustre/lustre/llite/lproc_llite.c | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c index 6eae605959055..23fda9d98bffd 100644 --- a/drivers/staging/lustre/lustre/llite/lproc_llite.c +++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c @@ -871,12 +871,10 @@ static ssize_t xattr_cache_store(struct kobject *kobj, } LUSTRE_RW_ATTR(xattr_cache); -static ssize_t unstable_stats_show(struct kobject *kobj, - struct attribute *attr, - char *buf) +static int ll_unstable_stats_seq_show(struct seq_file *m, void *v) { - struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info, - ll_kobj); + struct super_block *sb = m->private; + struct ll_sb_info *sbi = ll_s2sbi(sb); struct cl_client_cache *cache = sbi->ll_cache; long pages; int mb; @@ -884,19 +882,21 @@ static ssize_t unstable_stats_show(struct kobject *kobj, pages = atomic_long_read(&cache->ccc_unstable_nr); mb = (pages * PAGE_SIZE) >> 20; - return sprintf(buf, "unstable_check: %8d\n" - "unstable_pages: %12ld\n" - "unstable_mb: %8d\n", - cache->ccc_unstable_check, pages, mb); + seq_printf(m, + "unstable_check: %8d\n" + "unstable_pages: %12ld\n" + "unstable_mb: %8d\n", + cache->ccc_unstable_check, pages, mb); + + return 0; } -static ssize_t unstable_stats_store(struct kobject *kobj, - struct attribute *attr, - const char *buffer, - size_t count) +static ssize_t ll_unstable_stats_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) { - struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info, - ll_kobj); + struct super_block *sb = ((struct seq_file *)file->private_data)->private; + struct ll_sb_info *sbi = ll_s2sbi(sb); char kernbuf[128]; int val, rc; @@ -922,7 +922,7 @@ static ssize_t unstable_stats_store(struct kobject *kobj, return count; } -LUSTRE_RW_ATTR(unstable_stats); +LPROC_SEQ_FOPS(ll_unstable_stats); static ssize_t root_squash_show(struct kobject *kobj, struct attribute *attr, char *buf) @@ -995,6 +995,7 @@ static struct lprocfs_vars lprocfs_llite_obd_vars[] = { /* { "filegroups", lprocfs_rd_filegroups, 0, 0 }, */ { "max_cached_mb", &ll_max_cached_mb_fops, NULL }, { "statahead_stats", &ll_statahead_stats_fops, NULL, 0 }, + { "unstable_stats", &ll_unstable_stats_fops, NULL }, { "sbi_flags", &ll_sbi_flags_fops, NULL, 0 }, { .name = "nosquash_nids", .fops = &ll_nosquash_nids_fops }, @@ -1026,7 +1027,6 @@ static struct attribute *llite_attrs[] = { &lustre_attr_max_easize.attr, &lustre_attr_default_easize.attr, &lustre_attr_xattr_cache.attr, - &lustre_attr_unstable_stats.attr, &lustre_attr_root_squash.attr, NULL, }; -- GitLab From bbe097f092b0d13e9736bd2794d0ab24547d0e5d Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 15 Sep 2016 17:07:22 +0200 Subject: [PATCH 0610/1167] usb: gadget: udc: atmel: fix endpoint name Since commit c32b5bcfa3c4 ("ARM: dts: at91: Fix USB endpoint nodes"), atmel_usba_udc fails with: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 0 at include/linux/usb/gadget.h:405 ecm_do_notify+0x188/0x1a0 Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 4.7.0+ #15 Hardware name: Atmel SAMA5 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (__warn+0xe4/0xfc) [] (__warn) from [] (warn_slowpath_null+0x20/0x28) [] (warn_slowpath_null) from [] (ecm_do_notify+0x188/0x1a0) [] (ecm_do_notify) from [] (ecm_set_alt+0x74/0x1ac) [] (ecm_set_alt) from [] (composite_setup+0xfc0/0x19f8) [] (composite_setup) from [] (usba_udc_irq+0x8f4/0xd9c) [] (usba_udc_irq) from [] (handle_irq_event_percpu+0x9c/0x158) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x28/0x3c) [] (handle_irq_event) from [] (handle_fasteoi_irq+0xa0/0x168) [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x24/0x34) [] (generic_handle_irq) from [] (__handle_domain_irq+0x54/0xa8) [] (__handle_domain_irq) from [] (__irq_svc+0x54/0x70) [] (__irq_svc) from [] (arch_cpu_idle+0x38/0x3c) [] (arch_cpu_idle) from [] (cpu_startup_entry+0x9c/0xdc) [] (cpu_startup_entry) from [] (start_kernel+0x354/0x360) [] (start_kernel) from [<20008078>] (0x20008078) ---[ end trace e7cf9dcebf4815a6 ]--- Fixes: c32b5bcfa3c4 ("ARM: dts: at91: Fix USB endpoint nodes") Cc: Reported-by: Richard Genoud Acked-by: Nicolas Ferre Signed-off-by: Alexandre Belloni Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/atmel_usba_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index bb1f6c8f0f01a..45bc997d07113 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1978,7 +1978,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret); goto err; } - ep->ep.name = name; + ep->ep.name = kasprintf(GFP_KERNEL, "ep%d", ep->index); ep->ep_regs = udc->regs + USBA_EPT_BASE(i); ep->dma_regs = udc->regs + USBA_DMA_BASE(i); -- GitLab From 6c83f77278f17a7679001027e9231291c20f0d8a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 4 Oct 2016 15:14:43 +0300 Subject: [PATCH 0611/1167] usb: gadget: function: u_ether: don't starve tx request queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we don't guarantee that we will always get an interrupt at least when we're queueing our very last request, we could fall into situation where we queue every request with 'no_interrupt' set. This will cause the link to get stuck. The behavior above has been triggered with g_ether and dwc3. Cc: Reported-by: Ville Syrjälä Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/u_ether.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 9c8c9ed1dc9e0..fe1811650dbc3 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -590,8 +590,9 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, /* throttle high/super speed IRQ rate back slightly */ if (gadget_is_dualspeed(dev->gadget)) - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH || - dev->gadget->speed == USB_SPEED_SUPER) + req->no_interrupt = (((dev->gadget->speed == USB_SPEED_HIGH || + dev->gadget->speed == USB_SPEED_SUPER)) && + !list_empty(&dev->tx_reqs)) ? ((atomic_read(&dev->tx_qlen) % dev->qmult) != 0) : 0; -- GitLab From a9c3ca5fae6bf73770f0576eaf57d5f1305ef4b3 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 5 Oct 2016 14:24:37 +0300 Subject: [PATCH 0612/1167] usb: dwc3: gadget: properly account queued requests Some requests could be accounted for multiple times. Let's fix that so each and every requests is accounted for only once. Cc: # v4.8 Fixes: 55a0237f8f47 ("usb: dwc3: gadget: use allocated/queued reqs for LST bit") Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 07cc8929f2713..3c3ced128c779 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -783,6 +783,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, req->trb = trb; req->trb_dma = dwc3_trb_dma_offset(dep, trb); req->first_trb_index = dep->trb_enqueue; + dep->queued_requests++; } dwc3_ep_inc_enq(dep); @@ -833,8 +834,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl |= DWC3_TRB_CTRL_HWO; - dep->queued_requests++; - trace_dwc3_prepare_trb(dep, trb); } @@ -1861,8 +1860,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, unsigned int s_pkt = 0; unsigned int trb_status; - dep->queued_requests--; dwc3_ep_inc_deq(dep); + + if (req->trb == trb) + dep->queued_requests--; + trace_dwc3_complete_trb(dep, trb); /* -- GitLab From d889c23ce4e3159e3d737f55f9d686a030a7ba87 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 29 Sep 2016 15:44:29 +0300 Subject: [PATCH 0613/1167] usb: dwc3: gadget: never pre-start Isochronous endpoints We cannot pre-start isochronous endpoints because we rely on the micro-frame number passed via XferNotReady command for proper Isochronous scheduling. Fixes: 08a36b543803 ("usb: dwc3: gadget: simplify __dwc3_gadget_ep_queue()") Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3c3ced128c779..f15147f79d141 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1073,9 +1073,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) list_add_tail(&req->list, &dep->pending_list); - if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && - dep->flags & DWC3_EP_PENDING_REQUEST) { - if (list_empty(&dep->started_list)) { + /* + * NOTICE: Isochronous endpoints should NEVER be prestarted. We must + * wait for a XferNotReady event so we will know what's the current + * (micro-)frame number. + * + * Without this trick, we are very, very likely gonna get Bus Expiry + * errors which will force us issue EndTransfer command. + */ + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { + if ((dep->flags & DWC3_EP_PENDING_REQUEST) && + list_empty(&dep->started_list)) { dwc3_stop_active_transfer(dwc, dep->number, true); dep->flags = DWC3_EP_ENABLED; } -- GitLab From 0047f59834e5947d45f34f5f12eb330d158f700b Mon Sep 17 00:00:00 2001 From: Piotr Luc Date: Wed, 12 Oct 2016 20:05:20 +0200 Subject: [PATCH 0614/1167] x86/cpu/intel: Add Knights Mill to Intel family Add CPUID of Knights Mill (KNM) processor to Intel family list. Signed-off-by: Piotr Luc Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20161012180520.30976-1-piotr.luc@intel.com Signed-off-by: Ingo Molnar --- arch/x86/include/asm/intel-family.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h index 9ae5ab80a497c..34a46dc076d36 100644 --- a/arch/x86/include/asm/intel-family.h +++ b/arch/x86/include/asm/intel-family.h @@ -64,5 +64,6 @@ /* Xeon Phi */ #define INTEL_FAM6_XEON_PHI_KNL 0x57 /* Knights Landing */ +#define INTEL_FAM6_XEON_PHI_KNM 0x85 /* Knights Mill */ #endif /* _ASM_X86_INTEL_FAMILY_H */ -- GitLab From 608284bf0def3ca5e6936920fcd84294101ef12d Mon Sep 17 00:00:00 2001 From: Piotr Luc Date: Wed, 12 Oct 2016 20:26:34 +0200 Subject: [PATCH 0615/1167] perf/x86/intel: Add Knights Mill CPUID Add Knights Mill (KNM) to the list of CPUIDs supported by PMU. Signed-off-by: Piotr Luc Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20161012182634.2462-1-piotr.luc@intel.com Signed-off-by: Ingo Molnar --- arch/x86/events/intel/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index a3a9eb84b5cf1..eab0915f59951 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3898,6 +3898,7 @@ __init int intel_pmu_init(void) break; case INTEL_FAM6_XEON_PHI_KNL: + case INTEL_FAM6_XEON_PHI_KNM: memcpy(hw_cache_event_ids, slm_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, @@ -3912,7 +3913,7 @@ __init int intel_pmu_init(void) x86_pmu.flags |= PMU_FL_HAS_RSP_1; x86_pmu.flags |= PMU_FL_NO_HT_SHARING; - pr_cont("Knights Landing events, "); + pr_cont("Knights Landing/Mill events, "); break; case INTEL_FAM6_SKYLAKE_MOBILE: -- GitLab From 36c4b6c14d20b37fda79cbcd3e8ef7d11f5ef9dc Mon Sep 17 00:00:00 2001 From: Piotr Luc Date: Wed, 12 Oct 2016 20:27:25 +0200 Subject: [PATCH 0616/1167] perf/x86/intel/rapl: Add Knights Mill CPUID Add Knights Mill (KNM) to the list of CPUIDs supported by rapl. Signed-off-by: Piotr Luc Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20161012182725.2701-1-piotr.luc@intel.com Signed-off-by: Ingo Molnar --- arch/x86/events/intel/rapl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/events/intel/rapl.c b/arch/x86/events/intel/rapl.c index b0f0e835a770f..0a535cea8ff31 100644 --- a/arch/x86/events/intel/rapl.c +++ b/arch/x86/events/intel/rapl.c @@ -763,6 +763,7 @@ static const struct x86_cpu_id rapl_cpu_match[] __initconst = { X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, hsw_rapl_init), X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM, knl_rapl_init), X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_rapl_init), X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP, skl_rapl_init), -- GitLab From ba2f81575eba8dcf128354169c20ae23f810f652 Mon Sep 17 00:00:00 2001 From: Piotr Luc Date: Wed, 12 Oct 2016 20:27:58 +0200 Subject: [PATCH 0617/1167] perf/x86/intel/uncore: Add Knights Mill CPUID Add Knights Mill (KNM) to the list of CPUIDs supported by PMU. Signed-off-by: Piotr Luc Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20161012182758.2925-1-piotr.luc@intel.com Signed-off-by: Ingo Molnar --- arch/x86/events/intel/uncore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index d9844cc74486e..efca2685d8767 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -1349,6 +1349,7 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = { X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, bdx_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, bdx_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM, knl_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP,skl_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X, skx_uncore_init), -- GitLab From 0f02c4e749bc79975dd23ddcc9bfe38bf76afb67 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 9 Sep 2016 16:28:43 +0200 Subject: [PATCH 0618/1167] s390/dasd: avoid undefined behaviour the mdc value can be quite big (like 65535), so we are in undefined territory when doing the multiplication with the (also signed) FCX_MAX_DATA_FACTOR as outlined by UBSAN: UBSAN: Undefined behaviour in drivers/s390/block/dasd_eckd.c:1678:14 signed integer overflow: 65535 * 65536 cannot be represented in type 'int' CPU: 5 PID: 183 Comm: kworker/u512:1 Not tainted 4.7.0+ #150 Workqueue: events_unbound async_run_entry_fn 000000fb8b59f900 000000fb8b59f990 0000000000000002 0000000000000000 000000fb8b59fa30 000000fb8b59f9a8 000000fb8b59f9a8 000000000011732e 00000000000000a4 0000000000a309e2 0000000000a4c072 000000000000000b 000000fb8b59f9f0 000000fb8b59f990 0000000000000000 0000000000000000 0400000000d83238 000000000011732e 000000fb8b59f990 000000fb8b59f9f0 Call Trace: ([<0000000000117260>] show_trace+0x98/0xa8) ([<00000000001172e0>] show_stack+0x70/0xf0) ([<000000000053ac96>] dump_stack+0x86/0xb8) ([<000000000057f5f8>] ubsan_epilogue+0x28/0x70) ([<000000000057fe9e>] handle_overflow+0xde/0xf0) ([<00000000006c322a>] dasd_eckd_check_characteristics+0x50a/0x550) ([<00000000006b42ca>] dasd_generic_set_online+0xba/0x380) ([<0000000000693d82>] ccw_device_set_online+0x192/0x550) ([<00000000006ac1ae>] dasd_generic_auto_online+0x2e/0x70) ([<0000000000172130>] async_run_entry_fn+0x70/0x270) ([<0000000000165a72>] process_one_work+0x26a/0x638) ([<0000000000165e8a>] worker_thread+0x4a/0x658) ([<000000000016dd9c>] kthread+0x10c/0x110) ([<00000000008963ae>] kernel_thread_starter+0x6/0xc) ([<00000000008963a8>] kernel_thread_starter+0x0/0xc) As this is a runtime value there is actually no risk of any sane compiler to detect and (ab)use this undefinedness, but let's make the multiplication defined by making mdc unsigned. Signed-off-by: Christian Borntraeger Acked-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eckd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 831935af73896..a7a88476e215e 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1205,7 +1205,7 @@ static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm) mdc, lpm); return mdc; } - fcx_max_data = mdc * FCX_MAX_DATA_FACTOR; + fcx_max_data = (u32)mdc * FCX_MAX_DATA_FACTOR; if (fcx_max_data < private->fcx_max_data) { dev_warn(&device->cdev->dev, "The maximum data size for zHPF requests %u " @@ -1675,7 +1675,7 @@ static u32 get_fcx_max_data(struct dasd_device *device) " data size for zHPF requests failed\n"); return 0; } else - return mdc * FCX_MAX_DATA_FACTOR; + return (u32)mdc * FCX_MAX_DATA_FACTOR; } /* -- GitLab From 12e721964e7feb555c3ee499a3f85c194d3d36ea Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 12 Oct 2016 13:43:38 +0200 Subject: [PATCH 0619/1167] s390: ignore pkey system calls Ignore the pkey systems calls since they don't make any sense on s390. In addition any user could trigger a warning if issueing the pkey_free system call, if it would be wired up on a system without pkey support. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/unistd.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index 02613bad8bbba..3066031a73fee 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h @@ -9,6 +9,9 @@ #include #define __IGNORE_time +#define __IGNORE_pkey_mprotect +#define __IGNORE_pkey_alloc +#define __IGNORE_pkey_free #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_SYS_ALARM -- GitLab From 179a98cba11b057d9f1cc70cd2a8831f9e9a06e6 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 12 Oct 2016 11:14:31 +0200 Subject: [PATCH 0620/1167] s390/cio: don't register chpids in reserved state During IPL we register all chpids that are not in the unrecognized state. This includes chpids that are not usable and chpids for which the state could not be obtained. Change that to only register chpids in the configured (usable) or standby (usable after a configure operation) state. All other chpids could only be made available by external control for which we would receive machine checks. Signed-off-by: Sebastian Ott Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 46be25c7461e0..876c7e6e3a992 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -780,7 +780,7 @@ static int cfg_wait_idle(void) static int __init chp_init(void) { struct chp_id chpid; - int ret; + int state, ret; ret = crw_register_handler(CRW_RSC_CPATH, chp_process_crw); if (ret) @@ -791,7 +791,9 @@ static int __init chp_init(void) return 0; /* Register available channel-paths. */ chp_id_for_each(&chpid) { - if (chp_info_get_status(chpid) != CHP_STATUS_NOT_RECOGNIZED) + state = chp_info_get_status(chpid); + if (state == CHP_STATUS_CONFIGURED || + state == CHP_STATUS_STANDBY) chp_new(chpid); } -- GitLab From b5003b5f0a19b6b37ab32b1f0c6b5da2cb3f0903 Mon Sep 17 00:00:00 2001 From: Shyam Saini Date: Thu, 13 Oct 2016 21:50:07 +0530 Subject: [PATCH 0621/1167] s390/mm: use hugetlb_bad_size() Update setup_hugepagesz() to call hugetlb_bad_size() when unsupported hugepage size is found. Signed-off-by: Shyam Saini Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/hugetlbpage.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index cd404aa3931c1..4a0c5bce3552b 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c @@ -217,6 +217,7 @@ static __init int setup_hugepagesz(char *opt) } else if (MACHINE_HAS_EDAT2 && size == PUD_SIZE) { hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT); } else { + hugetlb_bad_size(); pr_err("hugepagesz= specifies an unsupported page size %s\n", string); return 0; -- GitLab From a07ce8d34eb3d9c6cec3aa25f7713e6aafad2260 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 14 Oct 2016 10:47:24 -0700 Subject: [PATCH 0622/1167] usb: dwc2: Add msleep for host-only Although a host-only controller should not have any associated delay, some rockchip SOC platforms will not show the correct host-values of registers until after a delay. So add a 50 ms sleep when in host-only mode. Signed-off-by: John Youn Signed-off-by: Heiko Stuebner Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index fa9b26b915071..4c0fa0b173538 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -463,9 +463,18 @@ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) */ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) { + bool ret; + switch (hsotg->dr_mode) { case USB_DR_MODE_HOST: - dwc2_force_mode(hsotg, true); + ret = dwc2_force_mode(hsotg, true); + /* + * NOTE: This is required for some rockchip soc based + * platforms on their host-only dwc2. + */ + if (!ret) + msleep(50); + break; case USB_DR_MODE_PERIPHERAL: dwc2_force_mode(hsotg, false); -- GitLab From 454915dde06a51133750c6745f0ba57361ba209d Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Tue, 4 Oct 2016 02:07:33 +0200 Subject: [PATCH 0623/1167] usb: gadget: f_fs: edit epfile->ep under lock epfile->ep is protected by ffs->eps_lock (not epfile->mutex) so clear it while holding the spin lock. Tested-by: John Stultz Tested-by: Chen Yu Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 54ad100af35b4..b31aa9572723e 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1725,17 +1725,17 @@ static void ffs_func_eps_disable(struct ffs_function *func) unsigned long flags; do { - if (epfile) - mutex_lock(&epfile->mutex); spin_lock_irqsave(&func->ffs->eps_lock, flags); /* pending requests get nuked */ if (likely(ep->ep)) usb_ep_disable(ep->ep); ++ep; + if (epfile) + epfile->ep = NULL; spin_unlock_irqrestore(&func->ffs->eps_lock, flags); if (epfile) { - epfile->ep = NULL; + mutex_lock(&epfile->mutex); kfree(epfile->read_buffer); epfile->read_buffer = NULL; mutex_unlock(&epfile->mutex); -- GitLab From a9e6f83c2df199187a5248f824f31b6787ae23ae Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Tue, 4 Oct 2016 02:07:34 +0200 Subject: [PATCH 0624/1167] usb: gadget: f_fs: stop sleeping in ffs_func_eps_disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ffs_func_eps_disable is called from atomic context so it cannot sleep thus cannot grab a mutex. Change the handling of epfile->read_buffer to use non-sleeping synchronisation method. Reported-by: Chen Yu Signed-off-by: Michał Nazarewicz Fixes: 9353afbbfa7b ("buffer data from ‘oversized’ OUT requests") Tested-by: John Stultz Tested-by: Chen Yu Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 109 ++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 16 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index b31aa9572723e..e40d47d47d82a 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -136,8 +136,60 @@ struct ffs_epfile { /* * Buffer for holding data from partial reads which may happen since * we’re rounding user read requests to a multiple of a max packet size. + * + * The pointer is initialised with NULL value and may be set by + * __ffs_epfile_read_data function to point to a temporary buffer. + * + * In normal operation, calls to __ffs_epfile_read_buffered will consume + * data from said buffer and eventually free it. Importantly, while the + * function is using the buffer, it sets the pointer to NULL. This is + * all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered + * can never run concurrently (they are synchronised by epfile->mutex) + * so the latter will not assign a new value to the pointer. + * + * Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is + * valid) and sets the pointer to READ_BUFFER_DROP value. This special + * value is crux of the synchronisation between ffs_func_eps_disable and + * __ffs_epfile_read_data. + * + * Once __ffs_epfile_read_data is about to finish it will try to set the + * pointer back to its old value (as described above), but seeing as the + * pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free + * the buffer. + * + * == State transitions == + * + * • ptr == NULL: (initial state) + * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP + * ◦ __ffs_epfile_read_buffered: nop + * ◦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf + * ◦ reading finishes: n/a, not in ‘and reading’ state + * • ptr == DROP: + * ◦ __ffs_epfile_read_buffer_free: nop + * ◦ __ffs_epfile_read_buffered: go to ptr == NULL + * ◦ __ffs_epfile_read_data allocates temp buffer: free buf, nop + * ◦ reading finishes: n/a, not in ‘and reading’ state + * • ptr == buf: + * ◦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP + * ◦ __ffs_epfile_read_buffered: go to ptr == NULL and reading + * ◦ __ffs_epfile_read_data: n/a, __ffs_epfile_read_buffered + * is always called first + * ◦ reading finishes: n/a, not in ‘and reading’ state + * • ptr == NULL and reading: + * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading + * ◦ __ffs_epfile_read_buffered: n/a, mutex is held + * ◦ __ffs_epfile_read_data: n/a, mutex is held + * ◦ reading finishes and … + * … all data read: free buf, go to ptr == NULL + * … otherwise: go to ptr == buf and reading + * • ptr == DROP and reading: + * ◦ __ffs_epfile_read_buffer_free: nop + * ◦ __ffs_epfile_read_buffered: n/a, mutex is held + * ◦ __ffs_epfile_read_data: n/a, mutex is held + * ◦ reading finishes: free buf, go to ptr == DROP */ - struct ffs_buffer *read_buffer; /* P: epfile->mutex */ + struct ffs_buffer *read_buffer; +#define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN)) char name[5]; @@ -736,25 +788,47 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, schedule_work(&io_data->work); } +static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile) +{ + /* + * See comment in struct ffs_epfile for full read_buffer pointer + * synchronisation story. + */ + struct ffs_buffer *buf = xchg(&epfile->read_buffer, READ_BUFFER_DROP); + if (buf && buf != READ_BUFFER_DROP) + kfree(buf); +} + /* Assumes epfile->mutex is held. */ static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile, struct iov_iter *iter) { - struct ffs_buffer *buf = epfile->read_buffer; + /* + * Null out epfile->read_buffer so ffs_func_eps_disable does not free + * the buffer while we are using it. See comment in struct ffs_epfile + * for full read_buffer pointer synchronisation story. + */ + struct ffs_buffer *buf = xchg(&epfile->read_buffer, NULL); ssize_t ret; - if (!buf) + if (!buf || buf == READ_BUFFER_DROP) return 0; ret = copy_to_iter(buf->data, buf->length, iter); if (buf->length == ret) { kfree(buf); - epfile->read_buffer = NULL; - } else if (unlikely(iov_iter_count(iter))) { + return ret; + } + + if (unlikely(iov_iter_count(iter))) { ret = -EFAULT; } else { buf->length -= ret; buf->data += ret; } + + if (cmpxchg(&epfile->read_buffer, NULL, buf)) + kfree(buf); + return ret; } @@ -783,7 +857,15 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, buf->length = data_len; buf->data = buf->storage; memcpy(buf->storage, data + ret, data_len); - epfile->read_buffer = buf; + + /* + * At this point read_buffer is NULL or READ_BUFFER_DROP (if + * ffs_func_eps_disable has been called in the meanwhile). See comment + * in struct ffs_epfile for full read_buffer pointer synchronisation + * story. + */ + if (unlikely(cmpxchg(&epfile->read_buffer, NULL, buf))) + kfree(buf); return ret; } @@ -1097,8 +1179,7 @@ ffs_epfile_release(struct inode *inode, struct file *file) ENTER(); - kfree(epfile->read_buffer); - epfile->read_buffer = NULL; + __ffs_epfile_read_buffer_free(epfile); ffs_data_closed(epfile->ffs); return 0; @@ -1724,24 +1805,20 @@ static void ffs_func_eps_disable(struct ffs_function *func) unsigned count = func->ffs->eps_count; unsigned long flags; + spin_lock_irqsave(&func->ffs->eps_lock, flags); do { - spin_lock_irqsave(&func->ffs->eps_lock, flags); /* pending requests get nuked */ if (likely(ep->ep)) usb_ep_disable(ep->ep); ++ep; - if (epfile) - epfile->ep = NULL; - spin_unlock_irqrestore(&func->ffs->eps_lock, flags); if (epfile) { - mutex_lock(&epfile->mutex); - kfree(epfile->read_buffer); - epfile->read_buffer = NULL; - mutex_unlock(&epfile->mutex); + epfile->ep = NULL; + __ffs_epfile_read_buffer_free(epfile); ++epfile; } } while (--count); + spin_unlock_irqrestore(&func->ffs->eps_lock, flags); } static int ffs_func_eps_enable(struct ffs_function *func) -- GitLab From 51fbc7c06c8900370c6da5fc4a4685add8fa4fb0 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 7 Oct 2016 22:12:39 +0200 Subject: [PATCH 0625/1167] usb: dwc3: Fix size used in dma_free_coherent() In commit 2abd9d5fa60f9 ("usb: dwc3: ep0: Add chained TRB support"), the size of the memory allocated with 'dma_alloc_coherent()' has been modified but the corresponding calls to 'dma_free_coherent()' have not been updated accordingly. This has been spotted with coccinelle, using the following script: //////////////////// @r@ expression x0, x1, y0, y1, z0, z1, t0, t1, ret; @@ * ret = dma_alloc_coherent(x0, y0, z0, t0); ... * dma_free_coherent(x1, y1, ret, t1); @script:python@ y0 << r.y0; y1 << r.y1; @@ if y1.find(y0) == -1: print "WARNING: sizes look different: '%s' vs '%s'" % (y0, y1) //////////////////// Fixes: 2abd9d5fa60f9 ("usb: dwc3: ep0: Add chained TRB support") Signed-off-by: Christophe JAILLET Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f15147f79d141..1dfa56a5f1c51 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2990,7 +2990,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) kfree(dwc->setup_buf); err2: - dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), + dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); err1: @@ -3015,7 +3015,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) kfree(dwc->setup_buf); kfree(dwc->zlp_buf); - dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), + dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), -- GitLab From a19b882c07a63174f09d1f7c036cc2aab7f04ad3 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 6 Oct 2016 10:25:38 -0700 Subject: [PATCH 0626/1167] wusb: Stop using the stack for sg crypto scratch space Pointing an sg list at the stack is verboten and, with CONFIG_VMAP_STACK=y, will malfunction. Use kmalloc for the wusb crypto stack space instead. Untested -- I'm not entirely convinced that this hardware exists in the wild. Signed-off-by: Andy Lutomirski Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/crypto.c | 59 ++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c index 79b2b628066d8..de089f3a82f3d 100644 --- a/drivers/usb/wusbcore/crypto.c +++ b/drivers/usb/wusbcore/crypto.c @@ -133,6 +133,13 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2, bo[itr] = bi1[itr] ^ bi2[itr]; } +/* Scratch space for MAC calculations. */ +struct wusb_mac_scratch { + struct aes_ccm_b0 b0; + struct aes_ccm_b1 b1; + struct aes_ccm_a ax; +}; + /* * CC-MAC function WUSB1.0[6.5] * @@ -197,16 +204,15 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2, * what sg[4] is for. Maybe there is a smarter way to do this. */ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, - struct crypto_cipher *tfm_aes, void *mic, + struct crypto_cipher *tfm_aes, + struct wusb_mac_scratch *scratch, + void *mic, const struct aes_ccm_nonce *n, const struct aes_ccm_label *a, const void *b, size_t blen) { int result = 0; SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc); - struct aes_ccm_b0 b0; - struct aes_ccm_b1 b1; - struct aes_ccm_a ax; struct scatterlist sg[4], sg_dst; void *dst_buf; size_t dst_size; @@ -218,16 +224,17 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, * These checks should be compile time optimized out * ensure @a fills b1's mac_header and following fields */ - WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la)); - WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block)); - WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block)); - WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block)); + WARN_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la)); + WARN_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block)); + WARN_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block)); + WARN_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block)); result = -ENOMEM; zero_padding = blen % sizeof(struct aes_ccm_block); if (zero_padding) zero_padding = sizeof(struct aes_ccm_block) - zero_padding; - dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding; + dst_size = blen + sizeof(scratch->b0) + sizeof(scratch->b1) + + zero_padding; dst_buf = kzalloc(dst_size, GFP_KERNEL); if (!dst_buf) goto error_dst_buf; @@ -235,9 +242,9 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, memset(iv, 0, sizeof(iv)); /* Setup B0 */ - b0.flags = 0x59; /* Format B0 */ - b0.ccm_nonce = *n; - b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */ + scratch->b0.flags = 0x59; /* Format B0 */ + scratch->b0.ccm_nonce = *n; + scratch->b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */ /* Setup B1 * @@ -246,12 +253,12 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, * 14'--after clarification, it means to use A's contents * for MAC Header, EO, sec reserved and padding. */ - b1.la = cpu_to_be16(blen + 14); - memcpy(&b1.mac_header, a, sizeof(*a)); + scratch->b1.la = cpu_to_be16(blen + 14); + memcpy(&scratch->b1.mac_header, a, sizeof(*a)); sg_init_table(sg, ARRAY_SIZE(sg)); - sg_set_buf(&sg[0], &b0, sizeof(b0)); - sg_set_buf(&sg[1], &b1, sizeof(b1)); + sg_set_buf(&sg[0], &scratch->b0, sizeof(scratch->b0)); + sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1)); sg_set_buf(&sg[2], b, blen); /* 0 if well behaved :) */ sg_set_buf(&sg[3], bzero, zero_padding); @@ -276,11 +283,12 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, * POS Crypto API: size is assumed to be AES's block size. * Thanks for documenting it -- tip taken from airo.c */ - ax.flags = 0x01; /* as per WUSB 1.0 spec */ - ax.ccm_nonce = *n; - ax.counter = 0; - crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax); - bytewise_xor(mic, &ax, iv, 8); + scratch->ax.flags = 0x01; /* as per WUSB 1.0 spec */ + scratch->ax.ccm_nonce = *n; + scratch->ax.counter = 0; + crypto_cipher_encrypt_one(tfm_aes, (void *)&scratch->ax, + (void *)&scratch->ax); + bytewise_xor(mic, &scratch->ax, iv, 8); result = 8; error_cbc_crypt: kfree(dst_buf); @@ -303,6 +311,7 @@ ssize_t wusb_prf(void *out, size_t out_size, struct aes_ccm_nonce n = *_n; struct crypto_skcipher *tfm_cbc; struct crypto_cipher *tfm_aes; + struct wusb_mac_scratch *scratch; u64 sfn = 0; __le64 sfn_le; @@ -329,17 +338,23 @@ ssize_t wusb_prf(void *out, size_t out_size, printk(KERN_ERR "E: can't set AES key: %d\n", (int)result); goto error_setkey_aes; } + scratch = kmalloc(sizeof(*scratch), GFP_KERNEL); + if (!scratch) + goto error_alloc_scratch; for (bitr = 0; bitr < (len + 63) / 64; bitr++) { sfn_le = cpu_to_le64(sfn++); memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */ - result = wusb_ccm_mac(tfm_cbc, tfm_aes, out + bytes, + result = wusb_ccm_mac(tfm_cbc, tfm_aes, scratch, out + bytes, &n, a, b, blen); if (result < 0) goto error_ccm_mac; bytes += result; } result = bytes; + + kfree(scratch); +error_alloc_scratch: error_ccm_mac: error_setkey_aes: crypto_free_cipher(tfm_aes); -- GitLab From 54e23845e965898f65f76aba79fa9db76d830fa9 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 17 Oct 2016 11:47:02 +0200 Subject: [PATCH 0627/1167] alarmtimer: Remove unused but set variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the set but unused variable base in alarm_clock_get to fix the following warning when building with 'W=1': kernel/time/alarmtimer.c: In function ‘alarm_timer_create’: kernel/time/alarmtimer.c:545:21: warning: variable ‘base’ set but not used [-Wunused-but-set-variable] Signed-off-by: Tobias Klauser Cc: John Stultz Link: http://lkml.kernel.org/r/20161017094702.10873-1-tklauser@distanz.ch Signed-off-by: Thomas Gleixner --- kernel/time/alarmtimer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index c3aad685bbc03..12dd190634ab3 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -542,7 +542,6 @@ static int alarm_clock_get(clockid_t which_clock, struct timespec *tp) static int alarm_timer_create(struct k_itimer *new_timer) { enum alarmtimer_type type; - struct alarm_base *base; if (!alarmtimer_get_rtcdev()) return -ENOTSUPP; @@ -551,7 +550,6 @@ static int alarm_timer_create(struct k_itimer *new_timer) return -EPERM; type = clock2alarm(new_timer->it_clock); - base = &alarm_bases[type]; alarm_init(&new_timer->it.alarm.alarmtimer, type, alarm_handle_timer); return 0; } -- GitLab From 589ce5f447b8610df0dbd6935b56d5cda17b9cec Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 14 Oct 2016 15:13:07 +0100 Subject: [PATCH 0628/1167] irqchip/gic-v3-its: Fix 64bit GIC{R,ITS}_TYPER accesses The GICv3 architecture specification mentions that a 64bit register can be accessed using two 32bit accesses. What it doesn't mention is that this is only guaranteed on a system that implements AArch32, and a pure AArch64 system is allowed not to support this. This causes issues with the GICR_TYPER and GITS_TYPER registers, which are both RO 64bit registers. In order to solve this, this patch switches the TYPER accesses to the gic_read_typer macro already used in other parts of the driver. This makes sure that we always use a 64bit access on 64bit systems, and two 32bit accesses on 32bit system. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 003495d91f9cf..c5dee300e8a3e 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1023,7 +1023,7 @@ static void its_free_tables(struct its_node *its) static int its_alloc_tables(struct its_node *its) { - u64 typer = readq_relaxed(its->base + GITS_TYPER); + u64 typer = gic_read_typer(its->base + GITS_TYPER); u32 ids = GITS_TYPER_DEVBITS(typer); u64 shr = GITS_BASER_InnerShareable; u64 cache = GITS_BASER_WaWb; @@ -1198,7 +1198,7 @@ static void its_cpu_init_collection(void) * We now have to bind each collection to its target * redistributor. */ - if (readq_relaxed(its->base + GITS_TYPER) & GITS_TYPER_PTA) { + if (gic_read_typer(its->base + GITS_TYPER) & GITS_TYPER_PTA) { /* * This ITS wants the physical address of the * redistributor. @@ -1208,7 +1208,7 @@ static void its_cpu_init_collection(void) /* * This ITS wants a linear CPU number. */ - target = readq_relaxed(gic_data_rdist_rd_base() + GICR_TYPER); + target = gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER); target = GICR_TYPER_CPU_NUMBER(target) << 16; } @@ -1691,7 +1691,7 @@ static int __init its_probe_one(struct resource *res, INIT_LIST_HEAD(&its->its_device_list); its->base = its_base; its->phys_base = res->start; - its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1; + its->ite_size = ((gic_read_typer(its_base + GITS_TYPER) >> 4) & 0xf) + 1; its->numa_node = numa_node; its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL); @@ -1763,7 +1763,7 @@ static int __init its_probe_one(struct resource *res, static bool gic_rdists_supports_plpis(void) { - return !!(readl_relaxed(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS); + return !!(gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS); } int its_cpu_init(void) -- GitLab From 9c0e83c371cf4696926c95f9c8c77cd6ea803426 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 13 Oct 2016 17:42:09 +0100 Subject: [PATCH 0629/1167] arm64: kaslr: fix breakage with CONFIG_MODVERSIONS=y As it turns out, the KASLR code breaks CONFIG_MODVERSIONS, since the kcrctab has an absolute address field that is relocated at runtime when the kernel offset is randomized. This has been fixed already for PowerPC in the past, so simply wire up the existing code dealing with this issue. Cc: Fixes: f80fb3a3d508 ("arm64: add support for kernel ASLR") Tested-by: Timur Tabi Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm64/include/asm/module.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h index e12af6754634b..06ff7fd9e81fe 100644 --- a/arch/arm64/include/asm/module.h +++ b/arch/arm64/include/asm/module.h @@ -17,6 +17,7 @@ #define __ASM_MODULE_H #include +#include #define MODULE_ARCH_VERMAGIC "aarch64" @@ -32,6 +33,10 @@ u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela, Elf64_Sym *sym); #ifdef CONFIG_RANDOMIZE_BASE +#ifdef CONFIG_MODVERSIONS +#define ARCH_RELOCATES_KCRCTAB +#define reloc_start (kimage_vaddr - KIMAGE_VADDR) +#endif extern u64 module_alloc_base; #else #define module_alloc_base ((u64)_etext - MODULES_VSIZE) -- GitLab From d0679cfaf54c9e42e3ba4f8d5e67969932040d16 Mon Sep 17 00:00:00 2001 From: Hoan Tran Date: Fri, 14 Oct 2016 16:20:21 -0700 Subject: [PATCH 0630/1167] mailbox: PCC: Fix return value of pcc_mbox_request_channel() When CONFIG_PCC is disabled, pcc_mbox_request_channel() needs to return ERR_PTR(-ENODEV), not a NULL pointer, as the callers of this function use IS_ERR() to check for error code. Signed-off-by: Duc Dang Signed-off-by: Hoan Tran Signed-off-by: Rafael J. Wysocki --- include/acpi/pcc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/pcc.h b/include/acpi/pcc.h index 17a940a144771..8caa79c617035 100644 --- a/include/acpi/pcc.h +++ b/include/acpi/pcc.h @@ -21,7 +21,7 @@ extern void pcc_mbox_free_channel(struct mbox_chan *chan); static inline struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id) { - return NULL; + return ERR_PTR(-ENODEV); } static inline void pcc_mbox_free_channel(struct mbox_chan *chan) { } #endif -- GitLab From d0208639dbc6fe97a25054df44faa2d19aca9380 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 17 Oct 2016 11:08:31 +0200 Subject: [PATCH 0631/1167] s390/dumpstack: restore reliable indicator for call traces Before merging all different stack tracers the call traces printed had an indicator if an entry can be considered reliable or not. Unreliable entries were put in braces, reliable not. Currently all lines contain these extra braces. This patch restores the old behaviour by adding an extra "reliable" parameter to the callback functions. Only show_trace makes currently use of it. Before: [ 0.804751] Call Trace: [ 0.804753] ([<000000000017d0e0>] try_to_wake_up+0x318/0x5e0) [ 0.804756] ([<0000000000161d64>] create_worker+0x174/0x1c0) After: [ 0.804751] Call Trace: [ 0.804753] ([<000000000017d0e0>] try_to_wake_up+0x318/0x5e0) [ 0.804756] [<0000000000161d64>] create_worker+0x174/0x1c0 Fixes: 758d39ebd3d5 ("s390/dumpstack: merge all four stack tracers") Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/processor.h | 2 +- arch/s390/kernel/dumpstack.c | 17 +++++++++++------ arch/s390/kernel/perf_event.c | 2 +- arch/s390/kernel/stacktrace.c | 4 ++-- arch/s390/oprofile/init.c | 2 +- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 03323175de308..602af692efdc1 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -192,7 +192,7 @@ struct task_struct; struct mm_struct; struct seq_file; -typedef int (*dump_trace_func_t)(void *data, unsigned long address); +typedef int (*dump_trace_func_t)(void *data, unsigned long address, int reliable); void dump_trace(dump_trace_func_t func, void *data, struct task_struct *task, unsigned long sp); diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c index 6693383bc01bc..518f615ad0a26 100644 --- a/arch/s390/kernel/dumpstack.c +++ b/arch/s390/kernel/dumpstack.c @@ -38,10 +38,10 @@ __dump_trace(dump_trace_func_t func, void *data, unsigned long sp, if (sp < low || sp > high - sizeof(*sf)) return sp; sf = (struct stack_frame *) sp; + if (func(data, sf->gprs[8], 0)) + return sp; /* Follow the backchain. */ while (1) { - if (func(data, sf->gprs[8])) - return sp; low = sp; sp = sf->back_chain; if (!sp) @@ -49,6 +49,8 @@ __dump_trace(dump_trace_func_t func, void *data, unsigned long sp, if (sp <= low || sp > high - sizeof(*sf)) return sp; sf = (struct stack_frame *) sp; + if (func(data, sf->gprs[8], 1)) + return sp; } /* Zero backchain detected, check for interrupt frame. */ sp = (unsigned long) (sf + 1); @@ -56,7 +58,7 @@ __dump_trace(dump_trace_func_t func, void *data, unsigned long sp, return sp; regs = (struct pt_regs *) sp; if (!user_mode(regs)) { - if (func(data, regs->psw.addr)) + if (func(data, regs->psw.addr, 1)) return sp; } low = sp; @@ -90,7 +92,7 @@ struct return_address_data { int depth; }; -static int __return_address(void *data, unsigned long address) +static int __return_address(void *data, unsigned long address, int reliable) { struct return_address_data *rd = data; @@ -109,9 +111,12 @@ unsigned long return_address(int depth) } EXPORT_SYMBOL_GPL(return_address); -static int show_address(void *data, unsigned long address) +static int show_address(void *data, unsigned long address, int reliable) { - printk("([<%016lx>] %pSR)\n", address, (void *)address); + if (reliable) + printk(" [<%016lx>] %pSR \n", address, (void *)address); + else + printk("([<%016lx>] %pSR)\n", address, (void *)address); return 0; } diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c index 17431f63de002..955a7b6fa0a45 100644 --- a/arch/s390/kernel/perf_event.c +++ b/arch/s390/kernel/perf_event.c @@ -222,7 +222,7 @@ static int __init service_level_perf_register(void) } arch_initcall(service_level_perf_register); -static int __perf_callchain_kernel(void *data, unsigned long address) +static int __perf_callchain_kernel(void *data, unsigned long address, int reliable) { struct perf_callchain_entry_ctx *entry = data; diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 44f84b23d4e59..355db9db82104 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -27,12 +27,12 @@ static int __save_address(void *data, unsigned long address, int nosched) return 1; } -static int save_address(void *data, unsigned long address) +static int save_address(void *data, unsigned long address, int reliable) { return __save_address(data, address, 0); } -static int save_address_nosched(void *data, unsigned long address) +static int save_address_nosched(void *data, unsigned long address, int reliable) { return __save_address(data, address, 1); } diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index 16f4c3960b874..9a4de4599c7b9 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c @@ -13,7 +13,7 @@ #include #include -static int __s390_backtrace(void *data, unsigned long address) +static int __s390_backtrace(void *data, unsigned long address, int reliable) { unsigned int *depth = data; -- GitLab From a790634544f5f98364b0aafe9d7e669810d96360 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 17 Oct 2016 11:59:58 +0200 Subject: [PATCH 0632/1167] s390/dumpstack: use pr_cont where appropriate Use pr_cont instead of simple printk calls when lines will be continued. This fixes the kernel output of various lines printed on e.g. a warning: Before: [ 0.840604] Krnl PSW : 0404c00180000000 000000000017d1d2 [ 0.840606] (try_to_wake_up+0x382/0x5e0) [ 0.840610] R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:0 PM:0 [ 0.840611] RI:0 EA:3 After: [ 0.831772] Krnl PSW : 0404c00180000000 000000000017d14a (try_to_wake_up+0x382/0x5e0) [ 0.831776] R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:0 PM:0 RI:0 EA:3 Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/dumpstack.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c index 518f615ad0a26..4bebe72b77802 100644 --- a/arch/s390/kernel/dumpstack.c +++ b/arch/s390/kernel/dumpstack.c @@ -168,13 +168,13 @@ void show_registers(struct pt_regs *regs) mode = user_mode(regs) ? "User" : "Krnl"; printk("%s PSW : %p %p", mode, (void *)regs->psw.mask, (void *)regs->psw.addr); if (!user_mode(regs)) - printk(" (%pSR)", (void *)regs->psw.addr); - printk("\n"); + pr_cont(" (%pSR)", (void *)regs->psw.addr); + pr_cont("\n"); printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x " "P:%x AS:%x CC:%x PM:%x", psw->r, psw->t, psw->i, psw->e, psw->key, psw->m, psw->w, psw->p, psw->as, psw->cc, psw->pm); - printk(" RI:%x EA:%x", psw->ri, psw->eaba); - printk("\n%s GPRS: %016lx %016lx %016lx %016lx\n", mode, + pr_cont(" RI:%x EA:%x\n", psw->ri, psw->eaba); + printk("%s GPRS: %016lx %016lx %016lx %016lx\n", mode, regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); printk(" %016lx %016lx %016lx %016lx\n", regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); -- GitLab From 4d062487f3431f124e3a2420c0da0b7a2388dc80 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 17 Oct 2016 12:07:35 +0200 Subject: [PATCH 0633/1167] s390/disassambler: use pr_cont where appropriate Just like for dumpstack use pr_cont instead of simple printk calls to fix the output when disassembling a piece of code. Before: [ 0.840627] Krnl Code: 000000000017d1c6: a77400f7 brc 7,17d3b4 [ 0.840630] 000000000017d1ca: 92015000 mvi 0(%r5),1 [ 0.840634] #000000000017d1ce: a7f40001 brc 15,17d1d0 After: [ 0.831792] Krnl Code: 000000000017d13e: a77400f7 brc 7,17d32c 000000000017d142: 92015000 mvi 0(%r5),1 #000000000017d146: a7f40001 brc 15,17d148 Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/dis.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index 43446fa2a4e55..c74c59236f441 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -2014,12 +2014,12 @@ void show_code(struct pt_regs *regs) *ptr++ = '\t'; ptr += print_insn(ptr, code + start, addr); start += opsize; - printk("%s", buffer); + pr_cont("%s", buffer); ptr = buffer; ptr += sprintf(ptr, "\n "); hops++; } - printk("\n"); + pr_cont("\n"); } void print_fn_code(unsigned char *code, unsigned long len) -- GitLab From dcddba96cdbc5d0e4d4a17bf22cfd9b2f038a4ca Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 17 Oct 2016 13:07:46 +0200 Subject: [PATCH 0634/1167] s390/dumpstack: get rid of return_address again With commit ef6000b4c670 ("Disable the __builtin_return_address() warning globally after all)" the kernel does not warn at all again if __builtin_return_address(n) is called with n > 0. Besides the fact that this was a false warning on s390 anyway, due to the always present backchain, we can now revert commit 5606330627ab ("s390/dumpstack: implement and use return_address()") again, to simplify the code again. After all I shouldn't have had return_address() implememted at all to workaround this issue. So get rid of this again. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/ftrace.h | 4 +--- arch/s390/kernel/dumpstack.c | 24 ------------------------ 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h index 64053d9ac3f23..836c56290499b 100644 --- a/arch/s390/include/asm/ftrace.h +++ b/arch/s390/include/asm/ftrace.h @@ -12,9 +12,7 @@ #ifndef __ASSEMBLY__ -unsigned long return_address(int depth); - -#define ftrace_return_address(n) return_address(n) +#define ftrace_return_address(n) __builtin_return_address(n) void _mcount(void); void ftrace_caller(void); diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c index 4bebe72b77802..34345c0a3c468 100644 --- a/arch/s390/kernel/dumpstack.c +++ b/arch/s390/kernel/dumpstack.c @@ -87,30 +87,6 @@ void dump_trace(dump_trace_func_t func, void *data, struct task_struct *task, } EXPORT_SYMBOL_GPL(dump_trace); -struct return_address_data { - unsigned long address; - int depth; -}; - -static int __return_address(void *data, unsigned long address, int reliable) -{ - struct return_address_data *rd = data; - - if (rd->depth--) - return 0; - rd->address = address; - return 1; -} - -unsigned long return_address(int depth) -{ - struct return_address_data rd = { .depth = depth + 2 }; - - dump_trace(__return_address, &rd, NULL, current_stack_pointer()); - return rd.address; -} -EXPORT_SYMBOL_GPL(return_address); - static int show_address(void *data, unsigned long address, int reliable) { if (reliable) -- GitLab From dabe7ecc572447c6f8a052cc77e220998c7f9c38 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Thu, 13 Oct 2016 18:26:13 +0100 Subject: [PATCH 0635/1167] PCI: designware-plat: Change maintainer to Jose Abreu Change designware-plat maintainer to Jose Abreu. Signed-off-by: Joao Pinto Signed-off-by: Bjorn Helgaas --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1cd38a7e0064e..906e969485200 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9299,7 +9299,7 @@ S: Maintained F: drivers/pci/host/*designware* PCI DRIVER FOR SYNOPSYS PROTOTYPING DEVICE -M: Joao Pinto +M: Jose Abreu L: linux-pci@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/pci/designware-pcie.txt -- GitLab From 15480f3ab7a8b5333e170d7168ce8a1012cc735e Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 17 Oct 2016 11:39:32 +0100 Subject: [PATCH 0636/1167] PCI: layerscape: Fix drvdata usage before assignment Commit fefe6733e516 ("PCI: layerscape: Move struct pcie_port setup to probe function") changed the init ordering of the pcie structure, but started to use the pcie->drvdata field before initializing it. Mayhem follows. Fix this by moving the drvdata assignment right before the first use. Tested on LS2085a. Fixes: efe6733e516 ("PCI: layerscape: Move struct pcie_port setup to probe function") Signed-off-by: Marc Zyngier Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-layerscape.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c index 2cb7315e26d08..6537079963424 100644 --- a/drivers/pci/host/pci-layerscape.c +++ b/drivers/pci/host/pci-layerscape.c @@ -247,6 +247,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev) pp = &pcie->pp; pp->dev = dev; + pcie->drvdata = match->data; pp->ops = pcie->drvdata->ops; dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); @@ -256,7 +257,6 @@ static int __init ls_pcie_probe(struct platform_device *pdev) return PTR_ERR(pcie->pp.dbi_base); } - pcie->drvdata = match->data; pcie->lut = pcie->pp.dbi_base + pcie->drvdata->lut_offset; if (!ls_pcie_is_bridge(pcie)) -- GitLab From 02265cd60335a2c1417abae4192611e1fc05a6e5 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Mon, 17 Oct 2016 10:18:37 +0200 Subject: [PATCH 0637/1167] mmc: sdhci: cast unsigned int to unsigned long long to avoid unexpeted error Potentially overflowing expression 1000000 * data->timeout_clks with type unsigned int is evaluated using 32-bit arithmetic, and then used in a context that expects an expression of type unsigned long long. To avoid overflow, cast 1000000U to type unsigned long long. Special thanks to Coverity. Fixes: 7f05538af71c ("mmc: sdhci: fix data timeout (part 2)") Signed-off-by: Haibo Chen Cc: stable@vger.kernel.org # v3.15+ Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 223a91e039dc8..71654b90227f6 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -687,7 +687,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) * host->clock is in Hz. target_timeout is in us. * Hence, us = 1000000 * cycles / Hz. Round up. */ - val = 1000000 * data->timeout_clks; + val = 1000000ULL * data->timeout_clks; if (do_div(val, host->clock)) target_timeout++; target_timeout += val; -- GitLab From 31cf742f515c275d22843c4c756e048d2b6d716c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 27 Sep 2016 08:44:33 -0700 Subject: [PATCH 0638/1167] mmc: rtsx_usb_sdmmc: Avoid keeping the device runtime resumed when unused The rtsx_usb_sdmmc driver may bail out in its ->set_ios() callback when no SD card is inserted. This is wrong, as it could cause the device to remain runtime resumed when it's unused. Fix this behaviour. Tested-by: Ritesh Raj Sarraf Cc: Cc: Alan Stern Signed-off-by: Ulf Hansson --- drivers/mmc/host/rtsx_usb_sdmmc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index 4106295527b9d..e0b85904c9bbb 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -1138,11 +1138,6 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) dev_dbg(sdmmc_dev(host), "%s\n", __func__); mutex_lock(&ucr->dev_mutex); - if (rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD)) { - mutex_unlock(&ucr->dev_mutex); - return; - } - sd_set_power_mode(host, ios->power_mode); sd_set_bus_width(host, ios->bus_width); sd_set_timing(host, ios->timing, &host->ddr_mode); -- GitLab From 4f48aa7a11bfed9502a7c85a5b68cd40ea827f73 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 15 Sep 2016 14:46:21 +0200 Subject: [PATCH 0639/1167] mmc: rtsx_usb_sdmmc: Handle runtime PM while changing the led Accesses of the rtsx sdmmc's parent device, which is the rtsx usb device, must be done when it's runtime resumed. Currently this isn't case when changing the led, so let's fix this by adding a pm_runtime_get_sync() and a pm_runtime_put() around those operations. Reported-by: Ritesh Raj Sarraf Tested-by: Ritesh Raj Sarraf Cc: Cc: Alan Stern Signed-off-by: Ulf Hansson --- drivers/mmc/host/rtsx_usb_sdmmc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index e0b85904c9bbb..6e9c0f8fddb10 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -1309,6 +1309,7 @@ static void rtsx_usb_update_led(struct work_struct *work) container_of(work, struct rtsx_usb_sdmmc, led_work); struct rtsx_ucr *ucr = host->ucr; + pm_runtime_get_sync(sdmmc_dev(host)); mutex_lock(&ucr->dev_mutex); if (host->led.brightness == LED_OFF) @@ -1317,6 +1318,7 @@ static void rtsx_usb_update_led(struct work_struct *work) rtsx_usb_turn_on_led(ucr); mutex_unlock(&ucr->dev_mutex); + pm_runtime_put(sdmmc_dev(host)); } #endif -- GitLab From 796aa46adf1d90eab36ae06a42e6d3f10b28a75c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 26 Sep 2016 15:45:41 -0700 Subject: [PATCH 0640/1167] memstick: rtsx_usb_ms: Runtime resume the device when polling for cards Accesses to the rtsx usb device, which is the parent of the rtsx memstick device, must not be done unless it's runtime resumed. Therefore when the rtsx_usb_ms driver polls for inserted memstick cards, let's add pm_runtime_get|put*() to make sure accesses is done when the rtsx usb device is runtime resumed. Reported-by: Ritesh Raj Sarraf Tested-by: Ritesh Raj Sarraf Signed-off-by: Alan Stern Cc: Signed-off-by: Ulf Hansson --- drivers/memstick/host/rtsx_usb_ms.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c index d34bc35303851..1b994897f0ff7 100644 --- a/drivers/memstick/host/rtsx_usb_ms.c +++ b/drivers/memstick/host/rtsx_usb_ms.c @@ -681,6 +681,7 @@ static int rtsx_usb_detect_ms_card(void *__host) int err; for (;;) { + pm_runtime_get_sync(ms_dev(host)); mutex_lock(&ucr->dev_mutex); /* Check pending MS card changes */ @@ -703,6 +704,7 @@ static int rtsx_usb_detect_ms_card(void *__host) } poll_again: + pm_runtime_put(ms_dev(host)); if (host->eject) break; -- GitLab From 9158cb29e7c2f10dd325eb1589f0fe745a271257 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 28 Sep 2016 11:33:28 -0700 Subject: [PATCH 0641/1167] memstick: rtsx_usb_ms: Manage runtime PM when accessing the device Accesses to the rtsx usb device, which is the parent of the rtsx memstick device, must not be done unless it's runtime resumed. This is currently not the case and it could trigger various errors. Fix this by properly deal with runtime PM in this regards. This means making sure the device is runtime resumed, when serving requests via the ->request() callback or changing settings via the ->set_param() callbacks. Cc: Cc: Ritesh Raj Sarraf Cc: Alan Stern Signed-off-by: Ulf Hansson --- drivers/memstick/host/rtsx_usb_ms.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c index 1b994897f0ff7..2e3cf012ef485 100644 --- a/drivers/memstick/host/rtsx_usb_ms.c +++ b/drivers/memstick/host/rtsx_usb_ms.c @@ -524,6 +524,7 @@ static void rtsx_usb_ms_handle_req(struct work_struct *work) int rc; if (!host->req) { + pm_runtime_get_sync(ms_dev(host)); do { rc = memstick_next_req(msh, &host->req); dev_dbg(ms_dev(host), "next req %d\n", rc); @@ -544,6 +545,7 @@ static void rtsx_usb_ms_handle_req(struct work_struct *work) host->req->error); } } while (!rc); + pm_runtime_put(ms_dev(host)); } } @@ -570,6 +572,7 @@ static int rtsx_usb_ms_set_param(struct memstick_host *msh, dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n", __func__, param, value); + pm_runtime_get_sync(ms_dev(host)); mutex_lock(&ucr->dev_mutex); err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_MS_CARD); @@ -635,6 +638,7 @@ static int rtsx_usb_ms_set_param(struct memstick_host *msh, } out: mutex_unlock(&ucr->dev_mutex); + pm_runtime_put(ms_dev(host)); /* power-on delay */ if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON) -- GitLab From 82bb095ee9dcd9380b6ab608b5fa9f64e65f3a3b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 17 Oct 2016 12:19:38 +0200 Subject: [PATCH 0642/1167] MAINTAINERS: mmc: Move the mmc tree to kernel.org Signed-off-by: Ulf Hansson --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a009e004f8f77..e6857248d3a8a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8164,7 +8164,7 @@ F: include/linux/mfd/ MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM M: Ulf Hansson L: linux-mmc@vger.kernel.org -T: git git://git.linaro.org/people/ulf.hansson/mmc.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git S: Maintained F: Documentation/devicetree/bindings/mmc/ F: drivers/mmc/ -- GitLab From 9ca488dd53088d4fcc97258aeeccf21f63b7da1e Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 29 Sep 2016 17:22:58 +0200 Subject: [PATCH 0643/1167] batman-adv: Modify neigh_list only with rcu-list functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The batadv_hard_iface::neigh_list is accessed via rcu based primitives. Thus all operations done on it have to fulfill the requirements by RCU. So using non-RCU mechanisms like hlist_add_head is not allowed because it misses the barriers required to protect concurrent readers when accessing the data behind the pointer. Fixes: cef63419f7db ("batman-adv: add list of unique single hop neighbors per hard-interface") Signed-off-by: Sven Eckelmann Acked-by: Linus Lüssing Signed-off-by: Simon Wunderlich --- net/batman-adv/originator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 5f3bfc41aeb1c..7c8d16086f0fd 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -544,7 +544,7 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface, if (bat_priv->algo_ops->neigh.hardif_init) bat_priv->algo_ops->neigh.hardif_init(hardif_neigh); - hlist_add_head(&hardif_neigh->list, &hard_iface->neigh_list); + hlist_add_head_rcu(&hardif_neigh->list, &hard_iface->neigh_list); out: spin_unlock_bh(&hard_iface->neigh_list_lock); -- GitLab From 611b975b5c868639b7cb0e89e22d1c8c561bf3a1 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 16 Jul 2016 21:30:20 +0200 Subject: [PATCH 0644/1167] batman-adv: Add BATADV_DBG_TP_METER to BATADV_DBG_ALL The BATADV_DBG_ALL has to contain the bit of BATADV_DBG_TP_METER to really support all available debug messages. Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation") Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/log.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/log.h b/net/batman-adv/log.h index e0e1a88c3e580..d2905a855d1b9 100644 --- a/net/batman-adv/log.h +++ b/net/batman-adv/log.h @@ -63,7 +63,7 @@ enum batadv_dbg_level { BATADV_DBG_NC = BIT(5), BATADV_DBG_MCAST = BIT(6), BATADV_DBG_TP_METER = BIT(7), - BATADV_DBG_ALL = 127, + BATADV_DBG_ALL = 255, }; #ifdef CONFIG_BATMAN_ADV_DEBUG -- GitLab From f4a067f9ffca603b45f7e82ddd2ba50e5904cea3 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 17 Oct 2016 15:05:33 +0100 Subject: [PATCH 0645/1167] mac80211: move struct aead_req off the stack Some crypto implementations (such as the generic CCM wrapper in crypto/) use scatterlists to map fields of private data in their struct aead_req. This means these data structures cannot live in the vmalloc area, which means that they cannot live on the stack (with CONFIG_VMAP_STACK.) This currently occurs only with the generic software implementation, but the private data and usage is implementation specific, so move the whole data structures off the stack into heap by allocating every time we need to use them. In addition, take care not to put any of our own stack allocations into scatterlists. This involves reserving some extra room when allocating the aead_request structures, and referring to those allocations in the scatter- lists (while copying the data from the stack before the crypto operation) Signed-off-by: Ard Biesheuvel Signed-off-by: Johannes Berg --- net/mac80211/aes_ccm.c | 46 +++++++++++++++++++++++++++-------------- net/mac80211/aes_ccm.h | 8 ++++--- net/mac80211/aes_gcm.c | 43 ++++++++++++++++++++++++-------------- net/mac80211/aes_gcm.h | 6 ++++-- net/mac80211/aes_gmac.c | 26 +++++++++++------------ net/mac80211/aes_gmac.h | 4 ++++ net/mac80211/wpa.c | 22 ++++++++------------ 7 files changed, 93 insertions(+), 62 deletions(-) diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 7663c28ba3539..a4e0d59a40dd5 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -18,21 +18,24 @@ #include "key.h" #include "aes_ccm.h" -void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, - u8 *data, size_t data_len, u8 *mic, - size_t mic_len) +int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic, + size_t mic_len) { struct scatterlist sg[3]; + struct aead_request *aead_req; + int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); + u8 *__aad; - char aead_req_data[sizeof(struct aead_request) + - crypto_aead_reqsize(tfm)] - __aligned(__alignof__(struct aead_request)); - struct aead_request *aead_req = (void *) aead_req_data; + aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC); + if (!aead_req) + return -ENOMEM; - memset(aead_req, 0, sizeof(aead_req_data)); + __aad = (u8 *)aead_req + reqsize; + memcpy(__aad, aad, CCM_AAD_LEN); sg_init_table(sg, 3); - sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); + sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad)); sg_set_buf(&sg[1], data, data_len); sg_set_buf(&sg[2], mic, mic_len); @@ -41,6 +44,9 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, aead_request_set_ad(aead_req, sg[0].length); crypto_aead_encrypt(aead_req); + kzfree(aead_req); + + return 0; } int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, @@ -48,18 +54,23 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t mic_len) { struct scatterlist sg[3]; - char aead_req_data[sizeof(struct aead_request) + - crypto_aead_reqsize(tfm)] - __aligned(__alignof__(struct aead_request)); - struct aead_request *aead_req = (void *) aead_req_data; + struct aead_request *aead_req; + int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); + u8 *__aad; + int err; if (data_len == 0) return -EINVAL; - memset(aead_req, 0, sizeof(aead_req_data)); + aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC); + if (!aead_req) + return -ENOMEM; + + __aad = (u8 *)aead_req + reqsize; + memcpy(__aad, aad, CCM_AAD_LEN); sg_init_table(sg, 3); - sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); + sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad)); sg_set_buf(&sg[1], data, data_len); sg_set_buf(&sg[2], mic, mic_len); @@ -67,7 +78,10 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0); aead_request_set_ad(aead_req, sg[0].length); - return crypto_aead_decrypt(aead_req); + err = crypto_aead_decrypt(aead_req); + kzfree(aead_req); + + return err; } struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[], diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h index 6a73d1e4d186d..fcd3254c5cf08 100644 --- a/net/mac80211/aes_ccm.h +++ b/net/mac80211/aes_ccm.h @@ -12,12 +12,14 @@ #include +#define CCM_AAD_LEN 32 + struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[], size_t key_len, size_t mic_len); -void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, - u8 *data, size_t data_len, u8 *mic, - size_t mic_len); +int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic, + size_t mic_len); int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, u8 *data, size_t data_len, u8 *mic, size_t mic_len); diff --git a/net/mac80211/aes_gcm.c b/net/mac80211/aes_gcm.c index 3afe361fd27ca..8a4397cc1b08b 100644 --- a/net/mac80211/aes_gcm.c +++ b/net/mac80211/aes_gcm.c @@ -15,20 +15,23 @@ #include "key.h" #include "aes_gcm.h" -void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, - u8 *data, size_t data_len, u8 *mic) +int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic) { struct scatterlist sg[3]; + struct aead_request *aead_req; + int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); + u8 *__aad; - char aead_req_data[sizeof(struct aead_request) + - crypto_aead_reqsize(tfm)] - __aligned(__alignof__(struct aead_request)); - struct aead_request *aead_req = (void *)aead_req_data; + aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC); + if (!aead_req) + return -ENOMEM; - memset(aead_req, 0, sizeof(aead_req_data)); + __aad = (u8 *)aead_req + reqsize; + memcpy(__aad, aad, GCM_AAD_LEN); sg_init_table(sg, 3); - sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); + sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad)); sg_set_buf(&sg[1], data, data_len); sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN); @@ -37,24 +40,31 @@ void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, aead_request_set_ad(aead_req, sg[0].length); crypto_aead_encrypt(aead_req); + kzfree(aead_req); + return 0; } int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, u8 *data, size_t data_len, u8 *mic) { struct scatterlist sg[3]; - char aead_req_data[sizeof(struct aead_request) + - crypto_aead_reqsize(tfm)] - __aligned(__alignof__(struct aead_request)); - struct aead_request *aead_req = (void *)aead_req_data; + struct aead_request *aead_req; + int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); + u8 *__aad; + int err; if (data_len == 0) return -EINVAL; - memset(aead_req, 0, sizeof(aead_req_data)); + aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC); + if (!aead_req) + return -ENOMEM; + + __aad = (u8 *)aead_req + reqsize; + memcpy(__aad, aad, GCM_AAD_LEN); sg_init_table(sg, 3); - sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); + sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad)); sg_set_buf(&sg[1], data, data_len); sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN); @@ -63,7 +73,10 @@ int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, data_len + IEEE80211_GCMP_MIC_LEN, j_0); aead_request_set_ad(aead_req, sg[0].length); - return crypto_aead_decrypt(aead_req); + err = crypto_aead_decrypt(aead_req); + kzfree(aead_req); + + return err; } struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], diff --git a/net/mac80211/aes_gcm.h b/net/mac80211/aes_gcm.h index 1347fda6b76a8..55aed5352494f 100644 --- a/net/mac80211/aes_gcm.h +++ b/net/mac80211/aes_gcm.h @@ -11,8 +11,10 @@ #include -void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, - u8 *data, size_t data_len, u8 *mic); +#define GCM_AAD_LEN 32 + +int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic); int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, u8 *data, size_t data_len, u8 *mic); struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], diff --git a/net/mac80211/aes_gmac.c b/net/mac80211/aes_gmac.c index 3ddd927aaf306..bd72a862ddb79 100644 --- a/net/mac80211/aes_gmac.c +++ b/net/mac80211/aes_gmac.c @@ -17,28 +17,27 @@ #include "key.h" #include "aes_gmac.h" -#define GMAC_MIC_LEN 16 -#define GMAC_NONCE_LEN 12 -#define AAD_LEN 20 - int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, const u8 *data, size_t data_len, u8 *mic) { struct scatterlist sg[4]; - char aead_req_data[sizeof(struct aead_request) + - crypto_aead_reqsize(tfm)] - __aligned(__alignof__(struct aead_request)); - struct aead_request *aead_req = (void *)aead_req_data; - u8 zero[GMAC_MIC_LEN], iv[AES_BLOCK_SIZE]; + u8 *zero, *__aad, iv[AES_BLOCK_SIZE]; + struct aead_request *aead_req; + int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); if (data_len < GMAC_MIC_LEN) return -EINVAL; - memset(aead_req, 0, sizeof(aead_req_data)); + aead_req = kzalloc(reqsize + GMAC_MIC_LEN + GMAC_AAD_LEN, GFP_ATOMIC); + if (!aead_req) + return -ENOMEM; + + zero = (u8 *)aead_req + reqsize; + __aad = zero + GMAC_MIC_LEN; + memcpy(__aad, aad, GMAC_AAD_LEN); - memset(zero, 0, GMAC_MIC_LEN); sg_init_table(sg, 4); - sg_set_buf(&sg[0], aad, AAD_LEN); + sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN); sg_set_buf(&sg[1], data, data_len - GMAC_MIC_LEN); sg_set_buf(&sg[2], zero, GMAC_MIC_LEN); sg_set_buf(&sg[3], mic, GMAC_MIC_LEN); @@ -49,9 +48,10 @@ int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, aead_request_set_tfm(aead_req, tfm); aead_request_set_crypt(aead_req, sg, sg, 0, iv); - aead_request_set_ad(aead_req, AAD_LEN + data_len); + aead_request_set_ad(aead_req, GMAC_AAD_LEN + data_len); crypto_aead_encrypt(aead_req); + kzfree(aead_req); return 0; } diff --git a/net/mac80211/aes_gmac.h b/net/mac80211/aes_gmac.h index d328204d73a8a..32e6442c95be4 100644 --- a/net/mac80211/aes_gmac.h +++ b/net/mac80211/aes_gmac.h @@ -11,6 +11,10 @@ #include +#define GMAC_AAD_LEN 20 +#define GMAC_MIC_LEN 16 +#define GMAC_NONCE_LEN 12 + struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[], size_t key_len); int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index b48c1e13e2817..42ce9bd4426f1 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -405,7 +405,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb, u8 *pos; u8 pn[6]; u64 pn64; - u8 aad[2 * AES_BLOCK_SIZE]; + u8 aad[CCM_AAD_LEN]; u8 b_0[AES_BLOCK_SIZE]; if (info->control.hw_key && @@ -461,10 +461,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb, pos += IEEE80211_CCMP_HDR_LEN; ccmp_special_blocks(skb, pn, b_0, aad); - ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, - skb_put(skb, mic_len), mic_len); - - return 0; + return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, + skb_put(skb, mic_len), mic_len); } @@ -639,7 +637,7 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) u8 *pos; u8 pn[6]; u64 pn64; - u8 aad[2 * AES_BLOCK_SIZE]; + u8 aad[GCM_AAD_LEN]; u8 j_0[AES_BLOCK_SIZE]; if (info->control.hw_key && @@ -696,10 +694,8 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) pos += IEEE80211_GCMP_HDR_LEN; gcmp_special_blocks(skb, pn, j_0, aad); - ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len, - skb_put(skb, IEEE80211_GCMP_MIC_LEN)); - - return 0; + return ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len, + skb_put(skb, IEEE80211_GCMP_MIC_LEN)); } ieee80211_tx_result @@ -1123,9 +1119,9 @@ ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx) struct ieee80211_key *key = tx->key; struct ieee80211_mmie_16 *mmie; struct ieee80211_hdr *hdr; - u8 aad[20]; + u8 aad[GMAC_AAD_LEN]; u64 pn64; - u8 nonce[12]; + u8 nonce[GMAC_NONCE_LEN]; if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) return TX_DROP; @@ -1171,7 +1167,7 @@ ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx) struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_key *key = rx->key; struct ieee80211_mmie_16 *mmie; - u8 aad[20], mic[16], ipn[6], nonce[12]; + u8 aad[GMAC_AAD_LEN], mic[GMAC_MIC_LEN], ipn[6], nonce[GMAC_NONCE_LEN]; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (!ieee80211_is_mgmt(hdr->frame_control)) -- GitLab From a04a480d4392ea6efd117be2de564117b2a009c0 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 16 Oct 2016 20:02:52 -0700 Subject: [PATCH 0646/1167] net: Require exact match for TCP socket lookups if dif is l3mdev Currently, socket lookups for l3mdev (vrf) use cases can match a socket that is bound to a port but not a device (ie., a global socket). If the sysctl tcp_l3mdev_accept is not set this leads to ack packets going out based on the main table even though the packet came in from an L3 domain. The end result is that the connection does not establish creating confusion for users since the service is running and a socket shows in ss output. Fix by requiring an exact dif to sk_bound_dev_if match if the skb came through an interface enslaved to an l3mdev device and the tcp_l3mdev_accept is not set. skb's through an l3mdev interface are marked by setting a flag in inet{6}_skb_parm. The IPv6 variant is already set; this patch adds the flag for IPv4. Using an skb flag avoids a device lookup on the dif. The flag is set in the VRF driver using the IP{6}CB macros. For IPv4, the inet_skb_parm struct is moved in the cb per commit 971f10eca186, so the match function in the TCP stack needs to use TCP_SKB_CB. For IPv6, the move is done after the socket lookup, so IP6CB is used. The flags field in inet_skb_parm struct needs to be increased to add another flag. There is currently a 1-byte hole following the flags, so it can be expanded to u16 without increasing the size of the struct. Fixes: 193125dbd8eb ("net: Introduce VRF device driver") Signed-off-by: David Ahern Signed-off-by: David S. Miller --- drivers/net/vrf.c | 2 ++ include/linux/ipv6.h | 17 ++++++++++++++--- include/net/ip.h | 8 +++++++- include/net/tcp.h | 13 ++++++++++++- net/ipv4/inet_hashtables.c | 8 +++++--- net/ipv6/inet6_hashtables.c | 7 ++++--- 6 files changed, 44 insertions(+), 11 deletions(-) diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 85c271c70d42f..820de6a9ddde1 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -956,6 +956,7 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, if (skb->pkt_type == PACKET_LOOPBACK) { skb->dev = vrf_dev; skb->skb_iif = vrf_dev->ifindex; + IP6CB(skb)->flags |= IP6SKB_L3SLAVE; skb->pkt_type = PACKET_HOST; goto out; } @@ -996,6 +997,7 @@ static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev, { skb->dev = vrf_dev; skb->skb_iif = vrf_dev->ifindex; + IPCB(skb)->flags |= IPSKB_L3SLAVE; /* loopback traffic; do not push through packet taps again. * Reset pkt_type for upper layers to process skb diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 7e9a789be5e0d..ca1ad9ebbc92b 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -123,12 +123,12 @@ struct inet6_skb_parm { }; #if defined(CONFIG_NET_L3_MASTER_DEV) -static inline bool skb_l3mdev_slave(__u16 flags) +static inline bool ipv6_l3mdev_skb(__u16 flags) { return flags & IP6SKB_L3SLAVE; } #else -static inline bool skb_l3mdev_slave(__u16 flags) +static inline bool ipv6_l3mdev_skb(__u16 flags) { return false; } @@ -139,11 +139,22 @@ static inline bool skb_l3mdev_slave(__u16 flags) static inline int inet6_iif(const struct sk_buff *skb) { - bool l3_slave = skb_l3mdev_slave(IP6CB(skb)->flags); + bool l3_slave = ipv6_l3mdev_skb(IP6CB(skb)->flags); return l3_slave ? skb->skb_iif : IP6CB(skb)->iif; } +/* can not be used in TCP layer after tcp_v6_fill_cb */ +static inline bool inet6_exact_dif_match(struct net *net, struct sk_buff *skb) +{ +#if defined(CONFIG_NET_L3_MASTER_DEV) + if (!net->ipv4.sysctl_tcp_l3mdev_accept && + ipv6_l3mdev_skb(IP6CB(skb)->flags)) + return true; +#endif + return false; +} + struct tcp6_request_sock { struct tcp_request_sock tcp6rsk_tcp; }; diff --git a/include/net/ip.h b/include/net/ip.h index bc43c0fcae122..c9d07988911ea 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -38,7 +38,7 @@ struct sock; struct inet_skb_parm { int iif; struct ip_options opt; /* Compiled IP options */ - unsigned char flags; + u16 flags; #define IPSKB_FORWARDED BIT(0) #define IPSKB_XFRM_TUNNEL_SIZE BIT(1) @@ -48,10 +48,16 @@ struct inet_skb_parm { #define IPSKB_DOREDIRECT BIT(5) #define IPSKB_FRAG_PMTU BIT(6) #define IPSKB_FRAG_SEGS BIT(7) +#define IPSKB_L3SLAVE BIT(8) u16 frag_max_size; }; +static inline bool ipv4_l3mdev_skb(u16 flags) +{ + return !!(flags & IPSKB_L3SLAVE); +} + static inline unsigned int ip_hdrlen(const struct sk_buff *skb) { return ip_hdr(skb)->ihl * 4; diff --git a/include/net/tcp.h b/include/net/tcp.h index f83b7f220a65e..5b82d4d948340 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -794,12 +794,23 @@ struct tcp_skb_cb { */ static inline int tcp_v6_iif(const struct sk_buff *skb) { - bool l3_slave = skb_l3mdev_slave(TCP_SKB_CB(skb)->header.h6.flags); + bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); return l3_slave ? skb->skb_iif : TCP_SKB_CB(skb)->header.h6.iif; } #endif +/* TCP_SKB_CB reference means this can not be used from early demux */ +static inline bool inet_exact_dif_match(struct net *net, struct sk_buff *skb) +{ +#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) + if (!net->ipv4.sysctl_tcp_l3mdev_accept && + ipv4_l3mdev_skb(TCP_SKB_CB(skb)->header.h4.flags)) + return true; +#endif + return false; +} + /* Due to TSO, an SKB can be composed of multiple actual * packets. To keep these tracked properly, we use this. */ diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 77c20a489218c..ca97835bfec4b 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -25,6 +25,7 @@ #include #include #include +#include #include static u32 inet_ehashfn(const struct net *net, const __be32 laddr, @@ -172,7 +173,7 @@ EXPORT_SYMBOL_GPL(__inet_inherit_port); static inline int compute_score(struct sock *sk, struct net *net, const unsigned short hnum, const __be32 daddr, - const int dif) + const int dif, bool exact_dif) { int score = -1; struct inet_sock *inet = inet_sk(sk); @@ -186,7 +187,7 @@ static inline int compute_score(struct sock *sk, struct net *net, return -1; score += 4; } - if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if || exact_dif) { if (sk->sk_bound_dev_if != dif) return -1; score += 4; @@ -215,11 +216,12 @@ struct sock *__inet_lookup_listener(struct net *net, unsigned int hash = inet_lhashfn(net, hnum); struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; int score, hiscore = 0, matches = 0, reuseport = 0; + bool exact_dif = inet_exact_dif_match(net, skb); struct sock *sk, *result = NULL; u32 phash = 0; sk_for_each_rcu(sk, &ilb->head) { - score = compute_score(sk, net, hnum, daddr, dif); + score = compute_score(sk, net, hnum, daddr, dif, exact_dif); if (score > hiscore) { reuseport = sk->sk_reuseport; if (reuseport) { diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 00cf28ad45650..2fd0374a35b17 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -96,7 +96,7 @@ EXPORT_SYMBOL(__inet6_lookup_established); static inline int compute_score(struct sock *sk, struct net *net, const unsigned short hnum, const struct in6_addr *daddr, - const int dif) + const int dif, bool exact_dif) { int score = -1; @@ -109,7 +109,7 @@ static inline int compute_score(struct sock *sk, struct net *net, return -1; score++; } - if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if || exact_dif) { if (sk->sk_bound_dev_if != dif) return -1; score++; @@ -131,11 +131,12 @@ struct sock *inet6_lookup_listener(struct net *net, unsigned int hash = inet_lhashfn(net, hnum); struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; int score, hiscore = 0, matches = 0, reuseport = 0; + bool exact_dif = inet6_exact_dif_match(net, skb); struct sock *sk, *result = NULL; u32 phash = 0; sk_for_each(sk, &ilb->head) { - score = compute_score(sk, net, hnum, daddr, dif); + score = compute_score(sk, net, hnum, daddr, dif, exact_dif); if (score > hiscore) { reuseport = sk->sk_reuseport; if (reuseport) { -- GitLab From 2d470b62fa24f8d0024e8d392d28814c287ee1f1 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Sat, 8 Oct 2016 04:16:25 +0000 Subject: [PATCH 0647/1167] perf jevents: Handle events including .c and .o This patch helps with Sukadev's vendor event tree where such events can happen. >From Andi Kleen: Any event including a .c/.o/.bpf currently triggers BPF compilation or loading and then an error. This can happen for some Intel vendor events, which cannot be used. This patch fixes this problem by forbidding BPF file patch containing '{', '}' and ',', make sure flex consumes the leading '{', instead of matching it using a BPF file path. Tested result: $ perf stat -e '{unc_p_clockticks,unc_p_power_state_occupancy.cores_c0}' -a -I 1000 invalid or unsupported event: '{unc_p_clockticks,unc_p_power_state_occupancy.cores_c0}' Run 'perf list' for a list of valid events (as expected, interperted as event) $ perf stat -e 'aaa.c' -a -I 1000 ERROR: problems with path aaa.c: No such file or directory (as expected, interpreted as BPF source) $ perf stat -e 'aaa.ccc' -a -I 1000 invalid or unsupported event: 'aaa.ccc' (as expected, interpreted as event) $ perf stat -e '{aaa.c}' -a -I 1000 ERROR: problems with path aaa.c: No such file or directory event syntax error: '{aaa.c}' (as expected, interpreted as BPF source) $ perf stat -e '{cycles,aaa.c}' -a -I 1000 ERROR: problems with path aaa.c: No such file or directory event syntax error: '{cycles,aaa.c}' (as expected, interpreted as BPF source) Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Reported-by: Andi Kleen Cc: Jiri Olsa Cc: Sukadev Bhattiprolu Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1475900185-37967-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.l | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 9f43fda2570f9..660fca05bc93b 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -136,8 +136,8 @@ do { \ group [^,{}/]*[{][^}]*[}][^,{}/]* event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* event [^,{}/]+ -bpf_object .*\.(o|bpf) -bpf_source .*\.c +bpf_object [^,{}]+\.(o|bpf) +bpf_source [^,{}]+\.c num_dec [0-9]+ num_hex 0x[a-fA-F0-9]+ -- GitLab From 53613e005496234bb684e5db551fbcededa73999 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 13 Oct 2016 13:20:43 +1100 Subject: [PATCH 0648/1167] perf jit: Fix build issue on Ubuntu When building on Ubuntu 16.04, I get the following error: Makefile:49: *** the openjdk development package appears to me missing, install and try again. Stop. The problem is that update-java-alternatives has multiple spaces between fields, and cut treats each space as a new delimiter: java-1.8.0-openjdk-ppc64el 1081 /usr/lib/jvm/java-1.8.0-openjdk-ppc64el Fix this by using awk, which handles this fine. Signed-off-by: Anton Blanchard Reviewed-by: Stephane Eranian Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1476325243-15788-1-git-send-email-anton@ozlabs.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/jvmti/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile index 5ce61a1bda9ca..df14e6b67b63b 100644 --- a/tools/perf/jvmti/Makefile +++ b/tools/perf/jvmti/Makefile @@ -36,7 +36,7 @@ SOLIBEXT=so # The following works at least on fedora 23, you may need the next # line for other distros. ifneq (,$(wildcard /usr/sbin/update-java-alternatives)) -JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3) +JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | awk '{print $$3}') else ifneq (,$(wildcard /usr/sbin/alternatives)) JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g') -- GitLab From ca006f785fbfd7a5c901900bd3fe2b26e946a1ee Mon Sep 17 00:00:00 2001 From: Stefan Tauner Date: Thu, 6 Oct 2016 18:40:11 +0200 Subject: [PATCH 0649/1167] USB: serial: ftdi_sio: add support for Infineon TriBoard TC2X7 This adds support to ftdi_sio for the Infineon TriBoard TC2X7 engineering board for first-generation Aurix SoCs with Tricore CPUs. Mere addition of the device IDs does the job. Signed-off-by: Stefan Tauner Cc: stable Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 3 ++- drivers/usb/serial/ftdi_sio_ids.h | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b2d767e743fc2..0ff7f38d78005 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -986,7 +986,8 @@ static const struct usb_device_id id_table_combined[] = { /* ekey Devices */ { USB_DEVICE(FTDI_VID, FTDI_EKEY_CONV_USB_PID) }, /* Infineon Devices */ - { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_TC1798_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_TC2X7_PID, 1) }, /* GE Healthcare devices */ { USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) }, /* Active Research (Actisense) devices */ diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index f87a938cf0057..21011c0a4c640 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -626,8 +626,9 @@ /* * Infineon Technologies */ -#define INFINEON_VID 0x058b -#define INFINEON_TRIBOARD_PID 0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */ +#define INFINEON_VID 0x058b +#define INFINEON_TRIBOARD_TC1798_PID 0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */ +#define INFINEON_TRIBOARD_TC2X7_PID 0x0043 /* DAS JTAG TriBoard TC2X7 V1.0 */ /* * Acton Research Corp. -- GitLab From baa5567c18d17843815d1d9150424d31f238e363 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 17 Oct 2016 15:18:48 +0100 Subject: [PATCH 0650/1167] arm64: kernel: numa: fix ACPI boot cpu numa node mapping Commit 7ba5f605f3a0 ("arm64/numa: remove the limitation that cpu0 must bind to node0") removed the numa cpu<->node mapping restriction whereby logical cpu 0 always corresponds to numa node 0; removing the restriction was correct, in that it does not really exist in practice but the commit only updated the early mapping of logical cpu 0 to its real numa node for the DT boot path, missing the ACPI one, leading to boot failures on ACPI systems owing to missing node<->cpu map for logical cpu 0. Fix the issue by updating the ACPI boot path with code that carries out the early cpu<->node mapping also for the boot cpu (ie cpu 0), mirroring what is currently done in the DT boot path. Fixes: 7ba5f605f3a0 ("arm64/numa: remove the limitation that cpu0 must bind to node0") Signed-off-by: Lorenzo Pieralisi Tested-by: Laszlo Ersek Reported-by: Laszlo Ersek Cc: Will Deacon Cc: Laszlo Ersek Cc: Hanjun Guo Cc: Andrew Jones Cc: Zhen Lei Cc: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/kernel/smp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index d3f151cfd4a1f..8507703dabe4a 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -544,6 +544,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) return; } bootcpu_valid = true; + early_map_cpu_to_node(0, acpi_numa_get_nid(0, hwid)); return; } -- GitLab From 9a1a1f404be55b07aea64864f98d7306cc493360 Mon Sep 17 00:00:00 2001 From: Tai Nguyen Date: Thu, 13 Oct 2016 11:09:16 -0700 Subject: [PATCH 0651/1167] perf: xgene: Remove bogus IS_ERR() check In acpi_get_pmu_hw_inf we pass the address of a local variable to IS_ERR(), which doesn't make sense, as the pointer must be a real, valid pointer. This doesn't cause a functional problem, as IS_ERR() will evaluate as false, but the check is bogus and causes static checkers to complain. Remove the bogus check. The bug is reported by Dan Carpenter in [1] [1] https://www.spinics.net/lists/arm-kernel/msg535957.html Signed-off-by: Tai Nguyen Acked-by: Mark Rutland Signed-off-by: Will Deacon --- drivers/perf/xgene_pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c index c2ac7646b99f4..a8ac4bcef2c04 100644 --- a/drivers/perf/xgene_pmu.c +++ b/drivers/perf/xgene_pmu.c @@ -1011,7 +1011,7 @@ xgene_pmu_dev_ctx *acpi_get_pmu_hw_inf(struct xgene_pmu *xgene_pmu, rc = acpi_dev_get_resources(adev, &resource_list, acpi_pmu_dev_add_resource, &res); acpi_dev_free_resource_list(&resource_list); - if (rc < 0 || IS_ERR(&res)) { + if (rc < 0) { dev_err(dev, "PMU type %d: No resource address found\n", type); goto err; } -- GitLab From 9a0b1e8ba4061778897b544afc898de2163382f7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 15 Oct 2016 17:50:49 +0200 Subject: [PATCH 0652/1167] net: pktgen: remove rcu locking in pktgen_change_name() After Jesper commit back in linux-3.18, we trigger a lockdep splat in proc_create_data() while allocating memory from pktgen_change_name(). This patch converts t->if_lock to a mutex, since it is now only used from control path, and adds proper locking to pktgen_change_name() 1) pktgen_thread_lock to protect the outer loop (iterating threads) 2) t->if_lock to protect the inner loop (iterating devices) Note that before Jesper patch, pktgen_change_name() was lacking proper protection, but lockdep was not able to detect the problem. Fixes: 8788370a1d4b ("pktgen: RCU-ify "if_list" to remove lock in next_to_run()") Reported-by: John Sperbeck Signed-off-by: Eric Dumazet Cc: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- net/core/pktgen.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 5219a9e2127ae..306b8f0e03c18 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -216,8 +216,8 @@ #define M_QUEUE_XMIT 2 /* Inject packet into qdisc */ /* If lock -- protects updating of if_list */ -#define if_lock(t) spin_lock(&(t->if_lock)); -#define if_unlock(t) spin_unlock(&(t->if_lock)); +#define if_lock(t) mutex_lock(&(t->if_lock)); +#define if_unlock(t) mutex_unlock(&(t->if_lock)); /* Used to help with determining the pkts on receive */ #define PKTGEN_MAGIC 0xbe9be955 @@ -423,7 +423,7 @@ struct pktgen_net { }; struct pktgen_thread { - spinlock_t if_lock; /* for list of devices */ + struct mutex if_lock; /* for list of devices */ struct list_head if_list; /* All device here */ struct list_head th_list; struct task_struct *tsk; @@ -2010,11 +2010,13 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d { struct pktgen_thread *t; + mutex_lock(&pktgen_thread_lock); + list_for_each_entry(t, &pn->pktgen_threads, th_list) { struct pktgen_dev *pkt_dev; - rcu_read_lock(); - list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { + if_lock(t); + list_for_each_entry(pkt_dev, &t->if_list, list) { if (pkt_dev->odev != dev) continue; @@ -2029,8 +2031,9 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d dev->name); break; } - rcu_read_unlock(); + if_unlock(t); } + mutex_unlock(&pktgen_thread_lock); } static int pktgen_device_event(struct notifier_block *unused, @@ -3762,7 +3765,7 @@ static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn) return -ENOMEM; } - spin_lock_init(&t->if_lock); + mutex_init(&t->if_lock); t->cpu = cpu; INIT_LIST_HEAD(&t->if_list); -- GitLab From 850540351bb1a4fa5f192e5ce55b89928cc57f42 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 17 Oct 2016 13:47:34 +0100 Subject: [PATCH 0653/1167] arm64: kernel: Init MDCR_EL2 even in the absence of a PMU Commit f436b2ac90a0 ("arm64: kernel: fix architected PMU registers unconditional access") made sure we wouldn't access unimplemented PMU registers, but also left MDCR_EL2 uninitialized in that case, leading to trap bits being potentially left set. Make sure we always write something in that register. Fixes: f436b2ac90a0 ("arm64: kernel: fix architected PMU registers unconditional access") Cc: Lorenzo Pieralisi Cc: Will Deacon Cc: Signed-off-by: Marc Zyngier Signed-off-by: Will Deacon --- arch/arm64/kernel/head.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 427f6d3f084c3..332e33193ccf1 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -586,8 +586,9 @@ CPU_LE( movk x0, #0x30d0, lsl #16 ) // Clear EE and E0E on LE systems b.lt 4f // Skip if no PMU present mrs x0, pmcr_el0 // Disable debug access traps ubfx x0, x0, #11, #5 // to EL2 and allow access to - msr mdcr_el2, x0 // all PMU counters from EL1 4: + csel x0, xzr, x0, lt // all PMU counters from EL1 + msr mdcr_el2, x0 // (if they exist) /* Stage-2 translation */ msr vttbr_el2, xzr -- GitLab From 8fe88a4145cdeee486af60e61f5d5a14f804fa45 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 17 Oct 2016 16:18:39 +0100 Subject: [PATCH 0654/1167] arm64: kaslr: keep modules close to the kernel when DYNAMIC_FTRACE=y The RANDOMIZE_MODULE_REGION_FULL Kconfig option allows KASLR to be configured in such a way that kernel modules and the core kernel are allocated completely independently, which implies that modules are likely to require branches via PLT entries to reach the core kernel. The dynamic ftrace code does not expect that, and assumes that it can patch module code to perform a relative branch to anywhere in the core kernel. This may result in errors such as branch_imm_common: offset out of range ------------[ cut here ]------------ WARNING: CPU: 3 PID: 196 at kernel/trace/ftrace.c:1995 ftrace_bug+0x220/0x2e8 Modules linked in: CPU: 3 PID: 196 Comm: systemd-udevd Not tainted 4.8.0-22-generic #24 Hardware name: AMD Seattle/Seattle, BIOS 10:34:40 Oct 6 2016 task: ffff8d1bef7dde80 task.stack: ffff8d1bef6b0000 PC is at ftrace_bug+0x220/0x2e8 LR is at ftrace_process_locs+0x330/0x430 So make RANDOMIZE_MODULE_REGION_FULL mutually exclusive with DYNAMIC_FTRACE at the Kconfig level. Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 30398dbc940a2..969ef880d234e 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -915,7 +915,7 @@ config RANDOMIZE_BASE config RANDOMIZE_MODULE_REGION_FULL bool "Randomize the module region independently from the core kernel" - depends on RANDOMIZE_BASE + depends on RANDOMIZE_BASE && !DYNAMIC_FTRACE default y help Randomizes the location of the module region without considering the -- GitLab From 67b11e2ea704f99953f18585609df17b6e189e53 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 16 Oct 2016 23:54:03 +0100 Subject: [PATCH 0655/1167] cxgb4: fix memory leak of qe on error exit path A memory leak of qe occurs when t4_sched_queue_unbind fails, so fix this by free'ing qe on the error exit path. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sched.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.c b/drivers/net/ethernet/chelsio/cxgb4/sched.c index 539de764bbd30..cbd68a8fe2e48 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sched.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sched.c @@ -210,8 +210,10 @@ static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p) /* Unbind queue from any existing class */ err = t4_sched_queue_unbind(pi, p); - if (err) + if (err) { + t4_free_mem(qe); goto out; + } /* Bind queue to specified class */ memset(qe, 0, sizeof(*qe)); -- GitLab From 1b203c138c5a0d78aa34d1c4346ff6b32ac74869 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Oct 2016 15:40:14 +0200 Subject: [PATCH 0656/1167] netfilter: xt_hashlimit: Add missing ULL suffixes for 64-bit constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On 32-bit (e.g. with m68k-linux-gnu-gcc-4.1): net/netfilter/xt_hashlimit.c: In function ‘user2credits’: net/netfilter/xt_hashlimit.c:476: warning: integer constant is too large for ‘long’ type ... net/netfilter/xt_hashlimit.c:478: warning: integer constant is too large for ‘long’ type ... net/netfilter/xt_hashlimit.c:480: warning: integer constant is too large for ‘long’ type ... net/netfilter/xt_hashlimit.c: In function ‘rateinfo_recalc’: net/netfilter/xt_hashlimit.c:513: warning: integer constant is too large for ‘long’ type Fixes: 11d5f15723c9f39d ("netfilter: xt_hashlimit: Create revision 2 to support higher pps rates") Signed-off-by: Geert Uytterhoeven Acked-by: Vishwanath Pai Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_hashlimit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 2fab0c65aa94b..b89b688e9d01a 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -431,7 +431,7 @@ static void htable_put(struct xt_hashlimit_htable *hinfo) CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie. */ #define MAX_CPJ_v1 (0xFFFFFFFF / (HZ*60*60*24)) -#define MAX_CPJ (0xFFFFFFFFFFFFFFFF / (HZ*60*60*24)) +#define MAX_CPJ (0xFFFFFFFFFFFFFFFFULL / (HZ*60*60*24)) /* Repeated shift and or gives us all 1s, final shift and add 1 gives * us the power of 2 below the theoretical max, so GCC simply does a @@ -473,7 +473,7 @@ static u64 user2credits(u64 user, int revision) return div64_u64(user * HZ * CREDITS_PER_JIFFY_v1, XT_HASHLIMIT_SCALE); } else { - if (user > 0xFFFFFFFFFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) + if (user > 0xFFFFFFFFFFFFFFFFULL / (HZ*CREDITS_PER_JIFFY)) return div64_u64(user, XT_HASHLIMIT_SCALE_v2) * HZ * CREDITS_PER_JIFFY; -- GitLab From 9224eb77e63f70f16c0b6b7a20ca7d395f3bc077 Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Mon, 17 Oct 2016 16:00:46 +0100 Subject: [PATCH 0657/1167] irqchip/gic-v3-its: Fix entry size mask for GITS_BASER Entry Size in GITS_BASER occupies 5 bits [52:48], but we mask out 8 bits. Fixes: cc2d3216f53c ("irqchip: GICv3: ITS command queue") Cc: stable@vger.kernel.org Signed-off-by: Vladimir Murzin Signed-off-by: Marc Zyngier --- include/linux/irqchip/arm-gic-v3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 8361c8d3edd10..b7e34313cdfe4 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -290,7 +290,7 @@ #define GITS_BASER_TYPE_SHIFT (56) #define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7) #define GITS_BASER_ENTRY_SIZE_SHIFT (48) -#define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1) +#define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1) #define GITS_BASER_SHAREABILITY_SHIFT (10) #define GITS_BASER_InnerShareable \ GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable) -- GitLab From a8b1e36d0d1d6f51490e7adce35367ed6adb10e7 Mon Sep 17 00:00:00 2001 From: "Anders K. Pedersen" Date: Sun, 9 Oct 2016 13:49:02 +0000 Subject: [PATCH 0658/1167] netfilter: nft_dynset: fix element timeout for HZ != 1000 With HZ=100 element timeout in dynamic sets (i.e. flow tables) is 10 times higher than configured. Add proper conversion to/from jiffies, when interacting with userspace. I tested this on Linux 4.8.1, and it applies cleanly to current nf and nf-next trees. Fixes: 22fe54d5fefc ("netfilter: nf_tables: add support for dynamic set updates") Signed-off-by: Anders K. Pedersen Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_dynset.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c index e3b83c31da2e5..517f08767a3cd 100644 --- a/net/netfilter/nft_dynset.c +++ b/net/netfilter/nft_dynset.c @@ -158,7 +158,8 @@ static int nft_dynset_init(const struct nft_ctx *ctx, if (tb[NFTA_DYNSET_TIMEOUT] != NULL) { if (!(set->flags & NFT_SET_TIMEOUT)) return -EINVAL; - timeout = be64_to_cpu(nla_get_be64(tb[NFTA_DYNSET_TIMEOUT])); + timeout = msecs_to_jiffies(be64_to_cpu(nla_get_be64( + tb[NFTA_DYNSET_TIMEOUT]))); } priv->sreg_key = nft_parse_register(tb[NFTA_DYNSET_SREG_KEY]); @@ -246,7 +247,8 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr) goto nla_put_failure; if (nla_put_string(skb, NFTA_DYNSET_SET_NAME, priv->set->name)) goto nla_put_failure; - if (nla_put_be64(skb, NFTA_DYNSET_TIMEOUT, cpu_to_be64(priv->timeout), + if (nla_put_be64(skb, NFTA_DYNSET_TIMEOUT, + cpu_to_be64(jiffies_to_msecs(priv->timeout)), NFTA_DYNSET_PAD)) goto nla_put_failure; if (priv->expr && nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr)) -- GitLab From 4f76de5f237615643d2243582cee331815312ad0 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 10 Oct 2016 12:18:23 +0200 Subject: [PATCH 0659/1167] netfilter: conntrack: remove obsolete sysctl (nf_conntrack_events_retry_timeout) This entry has been removed in commit 9500507c6138. Fixes: 9500507c6138 ("netfilter: conntrack: remove timer from ecache extension") Signed-off-by: Nicolas Dichtel Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- .../networking/nf_conntrack-sysctl.txt | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Documentation/networking/nf_conntrack-sysctl.txt b/Documentation/networking/nf_conntrack-sysctl.txt index 4fb51d32fccc2..399e4e866a9c4 100644 --- a/Documentation/networking/nf_conntrack-sysctl.txt +++ b/Documentation/networking/nf_conntrack-sysctl.txt @@ -33,24 +33,6 @@ nf_conntrack_events - BOOLEAN If this option is enabled, the connection tracking code will provide userspace with connection tracking events via ctnetlink. -nf_conntrack_events_retry_timeout - INTEGER (seconds) - default 15 - - This option is only relevant when "reliable connection tracking - events" are used. Normally, ctnetlink is "lossy", that is, - events are normally dropped when userspace listeners can't keep up. - - Userspace can request "reliable event mode". When this mode is - active, the conntrack will only be destroyed after the event was - delivered. If event delivery fails, the kernel periodically - re-tries to send the event to userspace. - - This is the maximum interval the kernel should use when re-trying - to deliver the destroy event. - - A higher number means there will be fewer delivery retries and it - will take longer for a backlog to be processed. - nf_conntrack_expect_max - INTEGER Maximum size of expectation table. Default value is nf_conntrack_buckets / 256. Minimum is 1. -- GitLab From 6d19375b58763fefc2f215fb45117d3353ced888 Mon Sep 17 00:00:00 2001 From: Liping Zhang Date: Tue, 11 Oct 2016 21:03:45 +0800 Subject: [PATCH 0660/1167] netfilter: xt_NFLOG: fix unexpected truncated packet Justin and Chris spotted that iptables NFLOG target was broken when they upgraded the kernel to 4.8: "ulogd-2.0.5- IPs are no longer logged" or "results in segfaults in ulogd-2.0.5". Because "struct nf_loginfo li;" is a local variable, and flags will be filled with garbage value, not inited to zero. So if it contains 0x1, packets will not be logged to the userspace anymore. Fixes: 7643507fe8b5 ("netfilter: xt_NFLOG: nflog-range does not truncate packets") Reported-by: Justin Piszcz Reported-by: Chris Caputo Tested-by: Chris Caputo Signed-off-by: Liping Zhang Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_NFLOG.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/xt_NFLOG.c b/net/netfilter/xt_NFLOG.c index 018eed7e1ff1e..8668a5c18dc3f 100644 --- a/net/netfilter/xt_NFLOG.c +++ b/net/netfilter/xt_NFLOG.c @@ -32,6 +32,7 @@ nflog_tg(struct sk_buff *skb, const struct xt_action_param *par) li.u.ulog.copy_len = info->len; li.u.ulog.group = info->group; li.u.ulog.qthreshold = info->threshold; + li.u.ulog.flags = 0; if (info->flags & XT_NFLOG_F_COPY_LEN) li.u.ulog.flags |= NF_LOG_F_COPY_LEN; -- GitLab From f434ed0a00b232efc9843c869d05048c7cd79bb7 Mon Sep 17 00:00:00 2001 From: Liping Zhang Date: Wed, 12 Oct 2016 21:09:22 +0800 Subject: [PATCH 0661/1167] netfilter: xt_ipcomp: add "ip[6]t_ipcomp" module alias name Otherwise, user cannot add related rules if xt_ipcomp.ko is not loaded: # iptables -A OUTPUT -p 108 -m ipcomp --ipcompspi 1 iptables: No chain/target/match by that name. Signed-off-by: Liping Zhang Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_ipcomp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/netfilter/xt_ipcomp.c b/net/netfilter/xt_ipcomp.c index 89d53104c6b36..000e70377f85d 100644 --- a/net/netfilter/xt_ipcomp.c +++ b/net/netfilter/xt_ipcomp.c @@ -26,6 +26,8 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Fan Du "); MODULE_DESCRIPTION("Xtables: IPv4/6 IPsec-IPComp SPI match"); +MODULE_ALIAS("ipt_ipcomp"); +MODULE_ALIAS("ip6t_ipcomp"); /* Returns 1 if the spi is matched by the range, 0 otherwise */ static inline bool -- GitLab From 5751e175c60be1b4113d1e9bfa011b58ec01f104 Mon Sep 17 00:00:00 2001 From: Liping Zhang Date: Wed, 12 Oct 2016 21:10:45 +0800 Subject: [PATCH 0662/1167] netfilter: nft_hash: add missing NFTA_HASH_OFFSET's nla_policy Missing the nla_policy description will also miss the validation check in kernel. Fixes: 70ca767ea1b2 ("netfilter: nft_hash: Add hash offset value") Signed-off-by: Liping Zhang Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_hash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index 09473b415b95b..baf694de3935a 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c @@ -44,6 +44,7 @@ static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = { [NFTA_HASH_LEN] = { .type = NLA_U32 }, [NFTA_HASH_MODULUS] = { .type = NLA_U32 }, [NFTA_HASH_SEED] = { .type = NLA_U32 }, + [NFTA_HASH_OFFSET] = { .type = NLA_U32 }, }; static int nft_hash_init(const struct nft_ctx *ctx, -- GitLab From 09525a09ad3099efd9ba49b0b90bddc350d6b53a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2016 12:14:29 +0300 Subject: [PATCH 0663/1167] netfilter: nf_tables: underflow in nft_parse_u32_check() We don't want to allow negatives here. Fixes: 36b701fae12a ('netfilter: nf_tables: validate maximum value of u32 netlink attributes') Signed-off-by: Dan Carpenter Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index b70d3ea1430e7..24db22257586b 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -4423,7 +4423,7 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx, */ unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest) { - int val; + u32 val; val = ntohl(nla_get_be32(attr)); if (val > max) -- GitLab From 21a9e0f1568eaa0aad970c06e4cc8d77de8d9fa1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2016 09:09:12 +0300 Subject: [PATCH 0664/1167] netfilter: nft_exthdr: fix error handling in nft_exthdr_init() "err" needs to be signed for the error handling to work. Fixes: 36b701fae12a ('netfilter: nf_tables: validate maximum value of u32 netlink attributes') Signed-off-by: Dan Carpenter Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_exthdr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c index a84cf3d660566..47beb3abcc9da 100644 --- a/net/netfilter/nft_exthdr.c +++ b/net/netfilter/nft_exthdr.c @@ -59,7 +59,8 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, const struct nlattr * const tb[]) { struct nft_exthdr *priv = nft_expr_priv(expr); - u32 offset, len, err; + u32 offset, len; + int err; if (tb[NFTA_EXTHDR_DREG] == NULL || tb[NFTA_EXTHDR_TYPE] == NULL || -- GitLab From 71757904efadefdf5505712f675218ce59483c5d Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Mon, 17 Oct 2016 08:18:15 -0700 Subject: [PATCH 0665/1167] generic syscalls: kill cruft from removed pkey syscalls pkey_set() and pkey_get() were syscalls present in older versions of the protection keys patches. They were fully excised from the x86 code, but some cruft was left in the generic syscall code. The C++ comments were intended to help to make it more glaring to me to fix them before actually submitting them. That technique worked, but later than I would have liked. I test-compiled this for arm64. Fixes: a60f7b69d92c0 ("generic syscalls: Wire up memory protection keys syscalls") Signed-off-by: Dave Hansen Acked-by: Arnd Bergmann Cc: Thomas Gleixner Cc: x86@kernel.org Cc: linux-arch@vger.kernel.org Cc: mgorman@techsingularity.net Cc: linux-api@vger.kernel.org Cc: linux-mm@kvack.org Cc: luto@kernel.org Cc: akpm@linux-foundation.org Signed-off-by: Linus Torvalds --- include/linux/syscalls.h | 3 --- include/uapi/asm-generic/unistd.h | 4 ---- 2 files changed, 7 deletions(-) diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 0d7abb8b7315c..91a740f6b8842 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -902,8 +902,5 @@ asmlinkage long sys_pkey_mprotect(unsigned long start, size_t len, unsigned long prot, int pkey); asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val); asmlinkage long sys_pkey_free(int pkey); -//asmlinkage long sys_pkey_get(int pkey, unsigned long flags); -//asmlinkage long sys_pkey_set(int pkey, unsigned long access_rights, -// unsigned long flags); #endif diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index dbfee7e86ba64..9b1462e38b821 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -730,10 +730,6 @@ __SYSCALL(__NR_pkey_mprotect, sys_pkey_mprotect) __SYSCALL(__NR_pkey_alloc, sys_pkey_alloc) #define __NR_pkey_free 290 __SYSCALL(__NR_pkey_free, sys_pkey_free) -#define __NR_pkey_get 291 -//__SYSCALL(__NR_pkey_get, sys_pkey_get) -#define __NR_pkey_set 292 -//__SYSCALL(__NR_pkey_set, sys_pkey_set) #undef __NR_syscalls #define __NR_syscalls 291 -- GitLab From ccca6607c545534e5b74ef04e0f2f6ba11344be4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 13 Oct 2016 08:42:17 +0200 Subject: [PATCH 0666/1167] netfilter: nft_range: validate operation netlink attribute Use nft_parse_u32_check() to make sure we don't get a value over the unsigned 8-bit integer. Moreover, make sure this value doesn't go over the two supported range comparison modes. Fixes: 9286c2eb1fda ("netfilter: nft_range: validate operation netlink attribute") Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_range.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nft_range.c b/net/netfilter/nft_range.c index c6d5358482d12..9bc4586c3006c 100644 --- a/net/netfilter/nft_range.c +++ b/net/netfilter/nft_range.c @@ -59,6 +59,7 @@ static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr struct nft_range_expr *priv = nft_expr_priv(expr); struct nft_data_desc desc_from, desc_to; int err; + u32 op; err = nft_data_init(NULL, &priv->data_from, sizeof(priv->data_from), &desc_from, tb[NFTA_RANGE_FROM_DATA]); @@ -80,7 +81,20 @@ static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr if (err < 0) goto err2; - priv->op = ntohl(nla_get_be32(tb[NFTA_RANGE_OP])); + err = nft_parse_u32_check(tb[NFTA_RANGE_OP], U8_MAX, &op); + if (err < 0) + goto err2; + + switch (op) { + case NFT_RANGE_EQ: + case NFT_RANGE_NEQ: + break; + default: + err = -EINVAL; + goto err2; + } + + priv->op = op; priv->len = desc_from.len; return 0; err2: -- GitLab From fc971a2f2383950ddedb1e4896c5ead5d2357029 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 11:05:40 -0300 Subject: [PATCH 0667/1167] net: nps_enet: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/net/ethernet/ezchip/nps_enet.ko | grep alias $ After this patch: $ modinfo drivers/net/ethernet/ezchip/nps_enet.ko | grep alias alias: of:N*T*Cezchip,nps-mgt-enetC* alias: of:N*T*Cezchip,nps-mgt-enet Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index f928e6f79c895..223f35cc034cf 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -669,6 +669,7 @@ static const struct of_device_id nps_enet_dt_ids[] = { { .compatible = "ezchip,nps-mgt-enet" }, { /* Sentinel */ } }; +MODULE_DEVICE_TABLE(of, nps_enet_dt_ids); static struct platform_driver nps_enet_driver = { .probe = nps_enet_probe, -- GitLab From 2fa3e317e6c89fc89e96a48308f6791f74fcea3c Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 11:05:41 -0300 Subject: [PATCH 0668/1167] net: ethernet: nb8800: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ $ modinfo drivers/net/ethernet/aurora/nb8800.ko | grep alias $ After this patch: $ modinfo drivers/net/ethernet/aurora/nb8800.ko | grep alias alias: of:N*T*Csigma,smp8734-ethernetC* alias: of:N*T*Csigma,smp8734-ethernet alias: of:N*T*Csigma,smp8642-ethernetC* alias: of:N*T*Csigma,smp8642-ethernet alias: of:N*T*Caurora,nb8800C* alias: of:N*T*Caurora,nb8800 Signed-off-by: Javier Martinez Canillas Acked-by: Mans Rullgard Signed-off-by: David S. Miller --- drivers/net/ethernet/aurora/nb8800.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c index b047fd607b83b..00c38bf151e6a 100644 --- a/drivers/net/ethernet/aurora/nb8800.c +++ b/drivers/net/ethernet/aurora/nb8800.c @@ -1358,6 +1358,7 @@ static const struct of_device_id nb8800_dt_ids[] = { }, { } }; +MODULE_DEVICE_TABLE(of, nb8800_dt_ids); static int nb8800_probe(struct platform_device *pdev) { -- GitLab From a7deb924d33b5688b11e34e84c88f2591f933e3a Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 11:05:42 -0300 Subject: [PATCH 0669/1167] net: hns: Fix hns_dsaf module autoload for OF registration If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/net/ethernet/hisilicon/hns/hns_dsaf.ko | grep alias alias: acpi*:HISI00B2:* alias: acpi*:HISI00B1:* After this patch: $ modinfo drivers/net/ethernet/hisilicon/hns/hns_dsaf.ko | grep alias alias: acpi*:HISI00B2:* alias: acpi*:HISI00B1:* alias: of:N*T*Chisilicon,hns-dsaf-v2C* alias: of:N*T*Chisilicon,hns-dsaf-v2 alias: of:N*T*Chisilicon,hns-dsaf-v1C* alias: of:N*T*Chisilicon,hns-dsaf-v1 Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index 8e5b3f51b47b8..66b99d2be3fe7 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -2761,6 +2761,7 @@ static const struct of_device_id g_dsaf_match[] = { {.compatible = "hisilicon,hns-dsaf-v2"}, {} }; +MODULE_DEVICE_TABLE(of, g_dsaf_match); static struct platform_driver g_dsaf_driver = { .probe = hns_dsaf_probe, -- GitLab From 7097268509a7d6756d14ab422af7446f9bf53221 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 11:05:43 -0300 Subject: [PATCH 0670/1167] net: qcom/emac: Fix module autoload for OF registration If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/net/ethernet/qualcomm/emac/qcom-emac.ko | grep alias alias: platform:qcom-emac After this patch: $ modinfo drivers/net/ethernet/qualcomm/emac/qcom-emac.ko | grep alias alias: platform:qcom-emac alias: of:N*T*Cqcom,fsm9900-emacC* alias: of:N*T*Cqcom,fsm9900-emac Signed-off-by: Javier Martinez Canillas Acked-by: Timur Tabi Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/emac/emac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c index 9bf3b2b82e953..4fede4b865386 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac.c @@ -575,6 +575,7 @@ static const struct of_device_id emac_dt_match[] = { }, {} }; +MODULE_DEVICE_TABLE(of, emac_dt_match); #if IS_ENABLED(CONFIG_ACPI) static const struct acpi_device_id emac_acpi_match[] = { -- GitLab From af40097e3eafc97f6f856c085360a0e696e1f319 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 11:05:44 -0300 Subject: [PATCH 0671/1167] net: hisilicon: Fix hns_mdio module autoload for OF registration If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/net/ethernet/hisilicon//hns_mdio.ko | grep alias alias: platform:Hi-HNS_MDIO alias: acpi*:HISI0141:* After this patch: $ modinfo drivers/net/ethernet/hisilicon//hns_mdio.ko | grep alias alias: platform:Hi-HNS_MDIO alias: of:N*T*Chisilicon,hns-mdioC* alias: of:N*T*Chisilicon,hns-mdio alias: of:N*T*Chisilicon,mdioC* alias: of:N*T*Chisilicon,mdio alias: acpi*:HISI0141:* Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns_mdio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c index 33f4c483af0f4..501eb2090ca62 100644 --- a/drivers/net/ethernet/hisilicon/hns_mdio.c +++ b/drivers/net/ethernet/hisilicon/hns_mdio.c @@ -563,6 +563,7 @@ static const struct of_device_id hns_mdio_match[] = { {.compatible = "hisilicon,hns-mdio"}, {} }; +MODULE_DEVICE_TABLE(of, hns_mdio_match); static const struct acpi_device_id hns_mdio_acpi_match[] = { { "HISI0141", 0 }, -- GitLab From 03eaae52537f4bbe2e565535f2aa38d80f92e994 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 11:05:45 -0300 Subject: [PATCH 0672/1167] net: dsa: b53: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/net/dsa/b53/b53_mmap.ko | grep alias $ After this patch: $ modinfo drivers/net/dsa/b53/b53_mmap.ko | grep alias alias: of:N*T*Cbrcm,bcm63xx-switchC* alias: of:N*T*Cbrcm,bcm63xx-switch alias: of:N*T*Cbrcm,bcm6368-switchC* alias: of:N*T*Cbrcm,bcm6368-switch alias: of:N*T*Cbrcm,bcm6328-switchC* alias: of:N*T*Cbrcm,bcm6328-switch alias: of:N*T*Cbrcm,bcm3384-switchC* alias: of:N*T*Cbrcm,bcm3384-switch Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_mmap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c index 76fb8552c9d93..ef63d24fef814 100644 --- a/drivers/net/dsa/b53/b53_mmap.c +++ b/drivers/net/dsa/b53/b53_mmap.c @@ -256,6 +256,7 @@ static const struct of_device_id b53_mmap_of_table[] = { { .compatible = "brcm,bcm63xx-switch" }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, b53_mmap_of_table); static struct platform_driver b53_mmap_driver = { .probe = b53_mmap_probe, -- GitLab From 0822b43e4f08af3619a5dbf59f5036872c3ea323 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 11:05:46 -0300 Subject: [PATCH 0673/1167] net: dsa: bcm_sf2: Fix module autoload for OF registration If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/net/dsa/bcm_sf2.ko | grep alias alias: platform:brcm-sf2 After this patch: $ modinfo drivers/net/dsa/bcm_sf2.ko | grep alias alias: platform:brcm-sf2 alias: of:N*T*Cbrcm,bcm7445-switch-v4.0C* alias: of:N*T*Cbrcm,bcm7445-switch-v4.0 Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index e218887f18b79..0427009bc9246 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -1158,6 +1158,7 @@ static const struct of_device_id bcm_sf2_of_match[] = { { .compatible = "brcm,bcm7445-switch-v4.0" }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, bcm_sf2_of_match); static struct platform_driver bcm_sf2_driver = { .probe = bcm_sf2_sw_probe, -- GitLab From 667f4bab81ea8357d260aa14bb6fb1a4834248d5 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 5 Oct 2016 10:40:54 +1300 Subject: [PATCH 0674/1167] hwmon: (adm9240) handle temperature readings below 0 Unlike the temperature thresholds the temperature data is a 9-bit signed value. This allows and additional 0.5 degrees of precision on the reading but makes handling negative values slightly harder. In order to have sign-extension applied correctly the 9-bit value is stored in the upper bits of a signed 16-bit value. When presenting this in sysfs the value is shifted and scaled appropriately. Signed-off-by: Chris Packham Signed-off-by: Guenter Roeck --- drivers/hwmon/adm9240.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 98114cef1e439..2fe1828bd10b7 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -194,10 +194,10 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) * 0.5'C per two measurement cycles thus ignore possible * but unlikely aliasing error on lsb reading. --Grant */ - data->temp = ((i2c_smbus_read_byte_data(client, + data->temp = (i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP) << 8) | i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_CONF)) / 128; + ADM9240_REG_TEMP_CONF); for (i = 0; i < 2; i++) { /* read fans */ data->fan[i] = i2c_smbus_read_byte_data(client, @@ -263,7 +263,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *dummy, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", data->temp * 500); /* 9-bit value */ + return sprintf(buf, "%d\n", data->temp / 128 * 500); /* 9-bit value */ } static ssize_t show_max(struct device *dev, struct device_attribute *devattr, -- GitLab From 94cdc5608b5561aeda80edda9c9223608a1da6fc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2016 09:24:52 +0300 Subject: [PATCH 0675/1167] hwmon: (max31790) potential ERR_PTR dereference We should only dereference "data" after we check if it is an error pointer. Fixes: 54187ff9d766 ('hwmon: (max31790) Convert to use new hwmon registration API') Signed-off-by: Dan Carpenter Signed-off-by: Guenter Roeck --- drivers/hwmon/max31790.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index bef84e0859730..c1b9275978f9d 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -268,11 +268,13 @@ static int max31790_read_pwm(struct device *dev, u32 attr, int channel, long *val) { struct max31790_data *data = max31790_update_device(dev); - u8 fan_config = data->fan_config[channel]; + u8 fan_config; if (IS_ERR(data)) return PTR_ERR(data); + fan_config = data->fan_config[channel]; + switch (attr) { case hwmon_pwm_input: *val = data->pwm[channel] >> 8; -- GitLab From 4fa507992f0a1063d7326abaf705f9408548349e Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Thu, 13 Oct 2016 12:08:48 +0530 Subject: [PATCH 0676/1167] scsi: libiscsi: Fix locking in __iscsi_conn_send_pdu The code at free_task label in __iscsi_conn_send_pdu can get executed from blk_timeout_work which takes queue_lock using spin_lock_irq. back_lock taken with spin_unlock_bh will cause WARN_ON_ONCE. The code gets executed either with bottom half or IRQ disabled hence using spin_lock/spin_unlock for back_lock is safe. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/libiscsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index c051694bfcb0f..f9b6fba689ffb 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -791,9 +791,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, free_task: /* regular RX path uses back_lock */ - spin_lock_bh(&session->back_lock); + spin_lock(&session->back_lock); __iscsi_put_task(task); - spin_unlock_bh(&session->back_lock); + spin_unlock(&session->back_lock); return NULL; } -- GitLab From 7d2c0d643244311d0ce04fde373cd371ad1f1cad Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Thu, 13 Oct 2016 12:08:49 +0530 Subject: [PATCH 0677/1167] scsi: be2iscsi: Replace _bh with _irqsave/irqrestore [ 3843.132217] WARNING: CPU: 20 PID: 1227 at kernel/softirq.c:150 __local_bh_enable_ip+0x6b/0x90 [ 3843.142815] Modules linked in: ... [ 3843.294328] CPU: 20 PID: 1227 Comm: kworker/20:1H Tainted: G E 4.8.0-rc1+ #3 [ 3843.304944] Hardware name: Dell Inc. PowerEdge R720/0X6H47, BIOS 1.4.8 10/25/2012 [ 3843.314798] Workqueue: kblockd blk_timeout_work [ 3843.321350] 0000000000000086 00000000a32f4533 ffff8802216d7bd8 ffffffff8135c3cf [ 3843.331146] 0000000000000000 0000000000000000 ffff8802216d7c18 ffffffff8108d661 [ 3843.340918] 00000096216d7c50 0000000000000200 ffff8802d07cc828 ffff8801b3632550 [ 3843.350687] Call Trace: [ 3843.354866] [] dump_stack+0x63/0x84 [ 3843.362061] [] __warn+0xd1/0xf0 [ 3843.368851] [] warn_slowpath_null+0x1d/0x20 [ 3843.376791] [] __local_bh_enable_ip+0x6b/0x90 [ 3843.384903] [] _raw_spin_unlock_bh+0x1e/0x20 [ 3843.392940] [] beiscsi_alloc_pdu+0x2f0/0x6e0 [be2iscsi] [ 3843.402076] [] __iscsi_conn_send_pdu+0xf8/0x370 [libiscsi] [ 3843.411549] [] iscsi_send_nopout+0xbe/0x110 [libiscsi] [ 3843.420639] [] iscsi_eh_cmd_timed_out+0x29b/0x2b0 [libiscsi] [ 3843.430339] [] scsi_times_out+0x5e/0x250 [ 3843.438119] [] blk_rq_timed_out+0x1f/0x60 [ 3843.446009] [] blk_timeout_work+0xad/0x150 [ 3843.454010] [] process_one_work+0x152/0x400 [ 3843.462114] [] worker_thread+0x125/0x4b0 [ 3843.469961] [] ? rescuer_thread+0x380/0x380 [ 3843.478116] [] kthread+0xd8/0xf0 [ 3843.485212] [] ret_from_fork+0x1f/0x40 [ 3843.492908] [] ? kthread_park+0x60/0x60 [ 3843.500715] ---[ end trace 57ec0a1d8f0dd3a0 ]--- [ 3852.328667] NMI watchdog: Watchdog detected hard LOCKUP on cpu 1Kernel panic - not syncing: Hard LOCKUP blk_timeout_work takes queue_lock spin_lock with interrupts disabled before invoking iscsi_eh_cmd_timed_out. This causes a WARN_ON_ONCE in spin_unlock_bh for wrb_lock/io_sgl_lock/mgmt_sgl_lock. CPU was kept busy in lot of bottom half work with interrupts disabled thus causing hard lock up. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 37 ++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 6a6906f847dbb..75bfa14ed5bad 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -900,8 +900,9 @@ void hwi_ring_cq_db(struct beiscsi_hba *phba, static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba) { struct sgl_handle *psgl_handle; + unsigned long flags; - spin_lock_bh(&phba->io_sgl_lock); + spin_lock_irqsave(&phba->io_sgl_lock, flags); if (phba->io_sgl_hndl_avbl) { beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO, "BM_%d : In alloc_io_sgl_handle," @@ -919,14 +920,16 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba) phba->io_sgl_alloc_index++; } else psgl_handle = NULL; - spin_unlock_bh(&phba->io_sgl_lock); + spin_unlock_irqrestore(&phba->io_sgl_lock, flags); return psgl_handle; } static void free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) { - spin_lock_bh(&phba->io_sgl_lock); + unsigned long flags; + + spin_lock_irqsave(&phba->io_sgl_lock, flags); beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO, "BM_%d : In free_,io_sgl_free_index=%d\n", phba->io_sgl_free_index); @@ -941,7 +944,7 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) "value there=%p\n", phba->io_sgl_free_index, phba->io_sgl_hndl_base [phba->io_sgl_free_index]); - spin_unlock_bh(&phba->io_sgl_lock); + spin_unlock_irqrestore(&phba->io_sgl_lock, flags); return; } phba->io_sgl_hndl_base[phba->io_sgl_free_index] = psgl_handle; @@ -950,7 +953,7 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) phba->io_sgl_free_index = 0; else phba->io_sgl_free_index++; - spin_unlock_bh(&phba->io_sgl_lock); + spin_unlock_irqrestore(&phba->io_sgl_lock, flags); } static inline struct wrb_handle * @@ -958,15 +961,16 @@ beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context, unsigned int wrbs_per_cxn) { struct wrb_handle *pwrb_handle; + unsigned long flags; - spin_lock_bh(&pwrb_context->wrb_lock); + spin_lock_irqsave(&pwrb_context->wrb_lock, flags); pwrb_handle = pwrb_context->pwrb_handle_base[pwrb_context->alloc_index]; pwrb_context->wrb_handles_available--; if (pwrb_context->alloc_index == (wrbs_per_cxn - 1)) pwrb_context->alloc_index = 0; else pwrb_context->alloc_index++; - spin_unlock_bh(&pwrb_context->wrb_lock); + spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags); if (pwrb_handle) memset(pwrb_handle->pwrb, 0, sizeof(*pwrb_handle->pwrb)); @@ -1001,14 +1005,16 @@ beiscsi_put_wrb_handle(struct hwi_wrb_context *pwrb_context, struct wrb_handle *pwrb_handle, unsigned int wrbs_per_cxn) { - spin_lock_bh(&pwrb_context->wrb_lock); + unsigned long flags; + + spin_lock_irqsave(&pwrb_context->wrb_lock, flags); pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle; pwrb_context->wrb_handles_available++; if (pwrb_context->free_index == (wrbs_per_cxn - 1)) pwrb_context->free_index = 0; else pwrb_context->free_index++; - spin_unlock_bh(&pwrb_context->wrb_lock); + spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags); } /** @@ -1037,8 +1043,9 @@ free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context, static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba) { struct sgl_handle *psgl_handle; + unsigned long flags; - spin_lock_bh(&phba->mgmt_sgl_lock); + spin_lock_irqsave(&phba->mgmt_sgl_lock, flags); if (phba->eh_sgl_hndl_avbl) { psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index]; phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL; @@ -1056,14 +1063,16 @@ static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba) phba->eh_sgl_alloc_index++; } else psgl_handle = NULL; - spin_unlock_bh(&phba->mgmt_sgl_lock); + spin_unlock_irqrestore(&phba->mgmt_sgl_lock, flags); return psgl_handle; } void free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) { - spin_lock_bh(&phba->mgmt_sgl_lock); + unsigned long flags; + + spin_lock_irqsave(&phba->mgmt_sgl_lock, flags); beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, "BM_%d : In free_mgmt_sgl_handle," "eh_sgl_free_index=%d\n", @@ -1078,7 +1087,7 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) "BM_%d : Double Free in eh SGL ," "eh_sgl_free_index=%d\n", phba->eh_sgl_free_index); - spin_unlock_bh(&phba->mgmt_sgl_lock); + spin_unlock_irqrestore(&phba->mgmt_sgl_lock, flags); return; } phba->eh_sgl_hndl_base[phba->eh_sgl_free_index] = psgl_handle; @@ -1088,7 +1097,7 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) phba->eh_sgl_free_index = 0; else phba->eh_sgl_free_index++; - spin_unlock_bh(&phba->mgmt_sgl_lock); + spin_unlock_irqrestore(&phba->mgmt_sgl_lock, flags); } static void -- GitLab From 77f18a87186a87cab2a027335758a7244896084c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 11 Oct 2016 11:23:23 +0200 Subject: [PATCH 0678/1167] scsi: NCR5380: no longer mark irq probing as __init The g_NCR5380 has been converted to more regular probing, which means its probe function can now be invoked after the __init section is discarded, as pointed out by this kbuild warning: WARNING: drivers/scsi/built-in.o(.text+0x3a105): Section mismatch in reference from the function generic_NCR5380_isa_match() to the function .init.text:probe_intr() WARNING: drivers/scsi/built-in.o(.text+0x3a145): Section mismatch in reference from the function generic_NCR5380_isa_match() to the variable .init.data:probe_irq To make sure this works correctly in all cases, let's remove the __init and __initdata annotations. Fixes: a8cfbcaec0c1 ("scsi: g_NCR5380: Stop using scsi_module.c") Signed-off-by: Arnd Bergmann Acked-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index db2739079cbb4..790babc5ef660 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -353,7 +353,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) #endif -static int probe_irq __initdata; +static int probe_irq; /** * probe_intr - helper for IRQ autoprobe @@ -365,7 +365,7 @@ static int probe_irq __initdata; * used by the IRQ probe code. */ -static irqreturn_t __init probe_intr(int irq, void *dev_id) +static irqreturn_t probe_intr(int irq, void *dev_id) { probe_irq = irq; return IRQ_HANDLED; @@ -380,7 +380,7 @@ static irqreturn_t __init probe_intr(int irq, void *dev_id) * and then looking to see what interrupt actually turned up. */ -static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance, +static int __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance, int possible) { struct NCR5380_hostdata *hostdata = shost_priv(instance); -- GitLab From 91cb163e4d141c74e99639fbee7c2a6332c92901 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 17 Oct 2016 13:38:14 +0100 Subject: [PATCH 0679/1167] arm64: sysreg: Fix use of XZR in write_sysreg_s Commit 8a71f0c656e0 ("arm64: sysreg: replace open-coded mrs_s/msr_s with {read,write}_sysreg_s") introduced a write_sysreg_s macro for writing to system registers that are not supported by binutils. Unfortunately, this was implemented with the wrong template (%0 vs %x0), so in the case that we are writing a constant 0, we will generate invalid instruction syntax and bail with a cryptic assembler error: | Error: constant expression required This patch fixes the template. Acked-by: Mark Rutland Signed-off-by: Will Deacon --- arch/arm64/include/asm/sysreg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index e8d46e8e60791..6c80b3699cb8a 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -286,7 +286,7 @@ asm( #define write_sysreg_s(v, r) do { \ u64 __val = (u64)v; \ - asm volatile("msr_s " __stringify(r) ", %0" : : "rZ" (__val)); \ + asm volatile("msr_s " __stringify(r) ", %x0" : : "rZ" (__val)); \ } while (0) static inline void config_sctlr_el1(u32 clear, u32 set) -- GitLab From b052b07c39d593c9954a84d5bbe1563999483f38 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Mon, 17 Oct 2016 21:20:07 +0200 Subject: [PATCH 0680/1167] dm raid: fix activation of existing raid4/10 devices dm-raid 1.9.0 fails to activate existing RAID4/10 devices that have the old superblock format (which does not have takeover/reshaping support that was added via commit 33e53f06850f). Fix validation path for old superblocks by reverting to the old raid4 layout and basing checks on mddev->new_{level,layout,...} members in super_init_validation(). Cc: stable@vger.kernel.org # 4.8 Signed-off-by: Heinz Mauelshagen Signed-off-by: Mike Snitzer --- Documentation/device-mapper/dm-raid.txt | 1 + drivers/md/dm-raid.c | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Documentation/device-mapper/dm-raid.txt b/Documentation/device-mapper/dm-raid.txt index e5b6497116f41..c75b64a85859f 100644 --- a/Documentation/device-mapper/dm-raid.txt +++ b/Documentation/device-mapper/dm-raid.txt @@ -309,3 +309,4 @@ Version History with a reshape in progress. 1.9.0 Add support for RAID level takeover/reshape/region size and set size reduction. +1.9.1 Fix activation of existing RAID 4/10 mapped devices diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 2a39700979910..6d53810963f75 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -266,7 +266,7 @@ static struct raid_type { {"raid10_offset", "raid10 offset (striped mirrors)", 0, 2, 10, ALGORITHM_RAID10_OFFSET}, {"raid10_near", "raid10 near (striped mirrors)", 0, 2, 10, ALGORITHM_RAID10_NEAR}, {"raid10", "raid10 (striped mirrors)", 0, 2, 10, ALGORITHM_RAID10_DEFAULT}, - {"raid4", "raid4 (dedicated last parity disk)", 1, 2, 4, ALGORITHM_PARITY_N}, /* raid4 layout = raid5_n */ + {"raid4", "raid4 (dedicated first parity disk)", 1, 2, 5, ALGORITHM_PARITY_0}, /* raid4 layout = raid5_0 */ {"raid5_n", "raid5 (dedicated last parity disk)", 1, 2, 5, ALGORITHM_PARITY_N}, {"raid5_ls", "raid5 (left symmetric)", 1, 2, 5, ALGORITHM_LEFT_SYMMETRIC}, {"raid5_rs", "raid5 (right symmetric)", 1, 2, 5, ALGORITHM_RIGHT_SYMMETRIC}, @@ -2087,11 +2087,11 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev) /* * No takeover/reshaping, because we don't have the extended v1.9.0 metadata */ - if (le32_to_cpu(sb->level) != mddev->level) { + if (le32_to_cpu(sb->level) != mddev->new_level) { DMERR("Reshaping/takeover raid sets not yet supported. (raid level/stripes/size change)"); return -EINVAL; } - if (le32_to_cpu(sb->layout) != mddev->layout) { + if (le32_to_cpu(sb->layout) != mddev->new_layout) { DMERR("Reshaping raid sets not yet supported. (raid layout change)"); DMERR(" 0x%X vs 0x%X", le32_to_cpu(sb->layout), mddev->layout); DMERR(" Old layout: %s w/ %d copies", @@ -2102,7 +2102,7 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev) raid10_md_layout_to_copies(mddev->layout)); return -EINVAL; } - if (le32_to_cpu(sb->stripe_sectors) != mddev->chunk_sectors) { + if (le32_to_cpu(sb->stripe_sectors) != mddev->new_chunk_sectors) { DMERR("Reshaping raid sets not yet supported. (stripe sectors change)"); return -EINVAL; } @@ -2115,6 +2115,8 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev) return -EINVAL; } + DMINFO("Discovered old metadata format; upgrading to extended metadata format"); + /* Table line is checked vs. authoritative superblock */ rs_set_new(rs); } @@ -3647,7 +3649,7 @@ static void raid_resume(struct dm_target *ti) static struct target_type raid_target = { .name = "raid", - .version = {1, 9, 0}, + .version = {1, 9, 1}, .module = THIS_MODULE, .ctr = raid_ctr, .dtr = raid_dtr, -- GitLab From 1b283eea6228880b765bc40fe4e555416437ce58 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 7 Oct 2016 10:52:17 +0200 Subject: [PATCH 0681/1167] ARM: dts: fix the SD card on the Snowball This fixes a very annoying regression on the Snowball SD card that has been around for a while. It turns out that the device tree does not configure the direction pins properly, nor sets up the pins for the voltage converter properly at boot. Unless all things are correctly set up, the feedback clock will not work, and makes the driver spew messages in the console (but it works, very slowly): root@Ux500:/ mount /dev/mmcblk0p2 /mnt/ [ 9.953460] mmci-pl18x 80126000.sdi0_per1: error during DMA transfer! [ 9.960296] mmcblk0: error -110 sending status command, retrying [ 9.966461] mmcblk0: error -110 sending status command, retrying [ 9.972534] mmcblk0: error -110 sending status command, aborting Fix this by rectifying the device tree to correspond to that of the Ux500 HREF boards plus the DAT31DIR setting that is unique for the Snowball, and things start working smoothly. Add in the SDR12 and SDR25 modes which this host can do without any problems. I don't know if this has ever been correct, sadly. It works after this patch. Cc: stable@vger.kernel.org Reported-by: Daniel Lezcano Cc: Ulf Hansson Signed-off-by: Linus Walleij Signed-off-by: Olof Johansson --- arch/arm/boot/dts/ste-snowball.dts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/ste-snowball.dts b/arch/arm/boot/dts/ste-snowball.dts index b3df1c60d4657..386eee6de2320 100644 --- a/arch/arm/boot/dts/ste-snowball.dts +++ b/arch/arm/boot/dts/ste-snowball.dts @@ -239,14 +239,25 @@ arm,primecell-periphid = <0x10480180>; max-frequency = <100000000>; bus-width = <4>; + cap-sd-highspeed; cap-mmc-highspeed; + sd-uhs-sdr12; + sd-uhs-sdr25; + /* All direction control is used */ + st,sig-dir-cmd; + st,sig-dir-dat0; + st,sig-dir-dat2; + st,sig-dir-dat31; + st,sig-pin-fbclk; + full-pwr-cycle; vmmc-supply = <&ab8500_ldo_aux3_reg>; vqmmc-supply = <&vmmci>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&sdi0_default_mode>; pinctrl-1 = <&sdi0_sleep_mode>; - cd-gpios = <&gpio6 26 GPIO_ACTIVE_LOW>; // 218 + /* GPIO218 MMC_CD */ + cd-gpios = <&gpio6 26 GPIO_ACTIVE_LOW>; status = "okay"; }; @@ -549,7 +560,7 @@ /* VMMCI level-shifter enable */ snowball_cfg3 { pins = "GPIO217_AH12"; - ste,config = <&gpio_out_lo>; + ste,config = <&gpio_out_hi>; }; /* VMMCI level-shifter voltage select */ snowball_cfg4 { -- GitLab From 5fac7e8405a951f536dfcea09c6f6adb904a08a8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 4 Oct 2016 13:56:19 +0200 Subject: [PATCH 0682/1167] bus: qcom-ebi2: depend on ARCH_QCOM or COMPILE_TEST This hides the option for people who do not want their Kconfig vision cluttered (i.e. x86) and enables compile testing apart from the supported main arch. Cc: Stephen Boyd Cc: Arnd Bergmann Signed-off-by: Linus Walleij Signed-off-by: Olof Johansson --- drivers/bus/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 7010dcac93288..78751057164ae 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -111,6 +111,7 @@ config OMAP_OCP2SCP config QCOM_EBI2 bool "Qualcomm External Bus Interface 2 (EBI2)" depends on HAS_IOMEM + depends on ARCH_QCOM || COMPILE_TEST help Say y here to enable support for the Qualcomm External Bus Interface 2, which can be used to connect things like NAND Flash, -- GitLab From eac0ca77e42f0bed4d36c76c8fc056321441c569 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Mon, 17 Oct 2016 13:57:09 -0700 Subject: [PATCH 0683/1167] x86, pkeys: remove cruft from never-merged syscalls pkey_set() and pkey_get() were syscalls present in older versions of the protection keys patches. The syscall number definitions were inadvertently left in place. This patch removes them. I did a git grep and verified that these are the last places in the tree that these appear, save for the protection_keys.c tests and Documentation. Those spots talk about functions called pkey_get/set() which are wrappers for the direct PKRU instructions, not the syscalls. Signed-off-by: Dave Hansen Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: mgorman@techsingularity.net Cc: arnd@arndb.de Cc: linux-api@vger.kernel.org Cc: linux-mm@kvack.org Cc: luto@kernel.org Cc: akpm@linux-foundation.org Fixes: f9afc6197e9bb ("x86: Wire up protection keys system calls") Signed-off-by: Linus Torvalds --- arch/x86/entry/syscalls/syscall_32.tbl | 2 -- arch/x86/entry/syscalls/syscall_64.tbl | 2 -- 2 files changed, 4 deletions(-) diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index ff6ef7b308223..2b36185425441 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -389,5 +389,3 @@ 380 i386 pkey_mprotect sys_pkey_mprotect 381 i386 pkey_alloc sys_pkey_alloc 382 i386 pkey_free sys_pkey_free -#383 i386 pkey_get sys_pkey_get -#384 i386 pkey_set sys_pkey_set diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 2f024d02511da..e93ef0b38db8e 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -338,8 +338,6 @@ 329 common pkey_mprotect sys_pkey_mprotect 330 common pkey_alloc sys_pkey_alloc 331 common pkey_free sys_pkey_free -#332 common pkey_get sys_pkey_get -#333 common pkey_set sys_pkey_set # # x32-specific system call numbers start at 512 to avoid cache impact -- GitLab From 14155cafeadda946376260e2ad5d39a0528a332f Mon Sep 17 00:00:00 2001 From: Junjie Mao Date: Mon, 17 Oct 2016 09:20:25 +0800 Subject: [PATCH 0684/1167] btrfs: assign error values to the correct bio structs Fixes: 4246a0b63bd8 ("block: add a bi_error field to struct bio") Signed-off-by: Junjie Mao Acked-by: David Sterba Cc: stable@vger.kernel.org # 4.3+ Signed-off-by: Linus Torvalds --- fs/btrfs/compression.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index ccc70d96958d8..d4d8b7e36b2ff 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -698,7 +698,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, ret = btrfs_map_bio(root, comp_bio, mirror_num, 0); if (ret) { - bio->bi_error = ret; + comp_bio->bi_error = ret; bio_endio(comp_bio); } @@ -728,7 +728,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, ret = btrfs_map_bio(root, comp_bio, mirror_num, 0); if (ret) { - bio->bi_error = ret; + comp_bio->bi_error = ret; bio_endio(comp_bio); } -- GitLab From 70e1a28fe1e3fe1bddcb09e8eee25d8be1610b49 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 29 Sep 2016 18:51:20 +0800 Subject: [PATCH 0685/1167] MAINTAINERS: add myself as Marvell berlin SoC maintainer I would like to take maintainership for Marvell berlin SoCs. Signed-off-by: Jisheng Zhang Acked-by: Sebastian Hesselbarth Signed-off-by: Olof Johansson --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1cd38a7e0064e..25f543c1814d8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1442,6 +1442,7 @@ F: drivers/cpufreq/mvebu-cpufreq.c F: arch/arm/configs/mvebu_*_defconfig ARM/Marvell Berlin SoC support +M: Jisheng Zhang M: Sebastian Hesselbarth L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -- GitLab From 2723605169d8f58ebc2881d2b8a59e6ee6fe074a Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Sat, 8 Oct 2016 13:41:04 -0700 Subject: [PATCH 0686/1167] ARM: multi_v7_defconfig: Enable Intel e1000e driver Enable support for the Intel e1000e driver Signed-off-by: Ray Jui Signed-off-by: Scott Branden Signed-off-by: Olof Johansson --- arch/arm/configs/multi_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 437d0740dec60..11f37ed1dbfff 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -850,6 +850,7 @@ CONFIG_PWM_SUN4I=y CONFIG_PWM_TEGRA=y CONFIG_PWM_VT8500=y CONFIG_PHY_HIX5HD2_SATA=y +CONFIG_E1000E=y CONFIG_PWM_STI=y CONFIG_PWM_BCM2835=y CONFIG_PWM_BRCMSTB=m -- GitLab From 8236d9ac4cf2e51e4355c411612cfbaec8d31942 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 17 Oct 2016 00:11:14 +0900 Subject: [PATCH 0687/1167] clk: uniphier: add system clock support for sLD3 SoC I do not know why, but I missed to add this compatible string in the initial commit of this driver. Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index 5ffb898d0839d..f4e0f6be5f33a 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -110,6 +110,10 @@ static int uniphier_clk_remove(struct platform_device *pdev) static const struct of_device_id uniphier_clk_match[] = { /* System clock */ + { + .compatible = "socionext,uniphier-sld3-clock", + .data = uniphier_sld3_sys_clk_data, + }, { .compatible = "socionext,uniphier-ld4-clock", .data = uniphier_ld4_sys_clk_data, -- GitLab From c0ce317f0c8863d309e7cfb6f6c0fe86e38c6d86 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 17 Oct 2016 00:25:55 +0900 Subject: [PATCH 0688/1167] clk: uniphier: fix type of variable passed to regmap_read() The 3rd argument of regmap_read() takes a pointer to unsigned int. This driver is saved just because u32 happens to be typedef'ed as unsigned int, but we should not rely on that fact. Change the variable type just in case. Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/uniphier/clk-uniphier-mux.c b/drivers/clk/uniphier/clk-uniphier-mux.c index 15a2f2cbe0d90..2c243a894f3b9 100644 --- a/drivers/clk/uniphier/clk-uniphier-mux.c +++ b/drivers/clk/uniphier/clk-uniphier-mux.c @@ -42,7 +42,7 @@ static u8 uniphier_clk_mux_get_parent(struct clk_hw *hw) struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw); int num_parents = clk_hw_get_num_parents(hw); int ret; - u32 val; + unsigned int val; u8 i; ret = regmap_read(mux->regmap, mux->reg, &val); -- GitLab From 34b89b2967f284937be6759936ef3dc4d3aff2d0 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sun, 16 Oct 2016 10:45:07 -0300 Subject: [PATCH 0689/1167] clk: samsung: clk-exynos-audss: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/clk/samsung/clk-exynos-audss.ko | grep alias alias: platform:exynos-audss-clk After this patch: $ modinfo drivers/clk/samsung/clk-exynos-audss.ko | grep alias alias: platform:exynos-audss-clk alias: of:N*T*Csamsung,exynos5420-audss-clockC* alias: of:N*T*Csamsung,exynos5420-audss-clock alias: of:N*T*Csamsung,exynos5410-audss-clockC* alias: of:N*T*Csamsung,exynos5410-audss-clock alias: of:N*T*Csamsung,exynos5250-audss-clockC* alias: of:N*T*Csamsung,exynos5250-audss-clock alias: of:N*T*Csamsung,exynos4210-audss-clockC* alias: of:N*T*Csamsung,exynos4210-audss-clock Fixes: 4d252fd5719b ("clk: samsung: Allow modular build of the Audio Subsystem CLKCON driver") Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk-exynos-audss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 51d152f735cc5..17e68a7249456 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -106,6 +106,7 @@ static const struct of_device_id exynos_audss_clk_of_match[] = { }, { }, }; +MODULE_DEVICE_TABLE(of, exynos_audss_clk_of_match); static void exynos_audss_clk_teardown(void) { -- GitLab From 234d511d8c158d62f73f1a818eb4dd494a13a6e3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 14 Oct 2016 14:44:13 +0200 Subject: [PATCH 0690/1167] clk: mediatek: Add hardware dependency Only propose the mediatek clock drivers on this platform, unless build-testing. Signed-off-by: Jean Delvare Cc: Shunli Wang Cc: James Liao Cc: Erin Lo Cc: Matthias Brugger Cc: Michael Turquette Reviewed-by: Matthias Brugger Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 380c372d528ec..f042bd2a6a998 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -8,6 +8,7 @@ config COMMON_CLK_MEDIATEK config COMMON_CLK_MT8135 bool "Clock driver for Mediatek MT8135" + depends on ARCH_MEDIATEK || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK ---help--- @@ -15,6 +16,7 @@ config COMMON_CLK_MT8135 config COMMON_CLK_MT8173 bool "Clock driver for Mediatek MT8173" + depends on ARCH_MEDIATEK || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK ---help--- -- GitLab From 339e1e54891c339b30023c9cc8a005cbf65a3c0c Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 8 Oct 2016 16:59:38 +0800 Subject: [PATCH 0691/1167] clk: core: add __init decoration for CLK_OF_DECLARE_DRIVER function The new introduced macro CLK_OF_DECLARE_DRIVER is usually used to declare clock driver init functions, which are mostly decorated with __init. Add __init decoration for CLK_OF_DECLARE_DRIVER function to avoid causing section mismatch warnings on client clock drivers. Signed-off-by: Shawn Guo Fixes: c7296c51ce5d ("clk: core: New macro CLK_OF_DECLARE_DRIVER") Signed-off-by: Stephen Boyd --- include/linux/clk-provider.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index af596381fa0fa..a428aec36acee 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -785,7 +785,7 @@ extern struct of_device_id __clk_of_table; * routines, one at of_clk_init(), and one at platform device probe */ #define CLK_OF_DECLARE_DRIVER(name, compat, fn) \ - static void name##_of_clk_init_driver(struct device_node *np) \ + static void __init name##_of_clk_init_driver(struct device_node *np) \ { \ of_node_clear_flag(np, OF_POPULATED); \ fn(np); \ -- GitLab From 981e1bea55e56abdb16505502e4a69ff868e87d3 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 29 Sep 2016 16:28:55 +0200 Subject: [PATCH 0692/1167] clk: mvebu: armada-37xx-periph: Fix the clock provider registration While trying using a peripheral clock on a driver, I saw that the clock pointer returned by the provider was NULL. The problem was a missing indirection. It was the pointer stored in the hws array which needed to be updated not the value it contains. Signed-off-by: Gregory CLEMENT Fixes: 8ca4746a78ab ("clk: mvebu: Add the peripheral clock driver for Armada 3700") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-37xx-periph.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index 45905fc0d75b3..d5dfbad4ceabd 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -305,7 +305,7 @@ static const struct of_device_id armada_3700_periph_clock_of_match[] = { }; static int armada_3700_add_composite_clk(const struct clk_periph_data *data, void __iomem *reg, spinlock_t *lock, - struct device *dev, struct clk_hw *hw) + struct device *dev, struct clk_hw **hw) { const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *rate_ops = NULL; @@ -353,13 +353,13 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data, } } - hw = clk_hw_register_composite(dev, data->name, data->parent_names, + *hw = clk_hw_register_composite(dev, data->name, data->parent_names, data->num_parents, mux_hw, mux_ops, rate_hw, rate_ops, gate_hw, gate_ops, CLK_IGNORE_UNUSED); - if (IS_ERR(hw)) - return PTR_ERR(hw); + if (IS_ERR(*hw)) + return PTR_ERR(*hw); return 0; } @@ -400,7 +400,7 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) spin_lock_init(&driver_data->lock); for (i = 0; i < num_periph; i++) { - struct clk_hw *hw = driver_data->hw_data->hws[i]; + struct clk_hw **hw = &driver_data->hw_data->hws[i]; if (armada_3700_add_composite_clk(&data[i], reg, &driver_data->lock, dev, hw)) -- GitLab From 1c7032258d568f9a7aeb4c541786699d9a219a2a Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 6 Oct 2016 11:59:59 -0300 Subject: [PATCH 0693/1167] clk: max77686: fix number of clocks setup for clk_hw based registration The commit 9b4cac33adc7 ("clk: max77686: Migrate to clk_hw based OF and registration APIs") converted the driver to use the new provider API to register clocks using clk_hw. But unfortunately, in the conversion it missed to set the num_clks value which lead to the following error when trying to register a clk provider: [ 1.963782] of_clk_max77686_get: invalid index 0 [ 1.967460] ERROR: could not get clock /rtc@10070000:rtc_src(1) [ 1.973638] s3c-rtc 10070000.rtc: failed to find rtc source clock Fix it by correctly set the max77686_clk_driver_data num_clks member. Fixes: 9b4cac33adc7 ("clk: max77686: Migrate to clk_hw based OF and registration APIs") Reported-by: Markus Reichl Suggested-by: Tobias Jakobi Signed-off-by: Javier Martinez Canillas Tested-by: Markus Reichl Reviewed-by: Chanwoo Choi Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- drivers/clk/clk-max77686.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index b637f5979023f..eb953d3b0b69b 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c @@ -216,6 +216,7 @@ static int max77686_clk_probe(struct platform_device *pdev) return -EINVAL; } + drv_data->num_clks = num_clks; drv_data->max_clk_data = devm_kcalloc(dev, num_clks, sizeof(*drv_data->max_clk_data), GFP_KERNEL); -- GitLab From c4e634ce412d97f0e61223b2a5b3f8f9600cd4dc Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 30 Sep 2016 10:07:27 -0700 Subject: [PATCH 0694/1167] clk: bcm2835: Clamp the PLL's requested rate to the hardware limits. Fixes setting low-resolution video modes on HDMI. Now the PLLH_PIX divider adjusts itself until the PLLH is within bounds. Signed-off-by: Eric Anholt Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-bcm2835.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index b68bf573dcfb7..8c7763fd9efc5 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -502,8 +502,12 @@ static long bcm2835_pll_rate_from_divisors(unsigned long parent_rate, static long bcm2835_pll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { + struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); + const struct bcm2835_pll_data *data = pll->data; u32 ndiv, fdiv; + rate = clamp(rate, data->min_rate, data->max_rate); + bcm2835_pll_choose_ndiv_and_fdiv(rate, *parent_rate, &ndiv, &fdiv); return bcm2835_pll_rate_from_divisors(*parent_rate, ndiv, fdiv, 1); @@ -608,13 +612,6 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw, u32 ana[4]; int i; - if (rate < data->min_rate || rate > data->max_rate) { - dev_err(cprman->dev, "%s: rate out of spec: %lu vs (%lu, %lu)\n", - clk_hw_get_name(hw), rate, - data->min_rate, data->max_rate); - return -EINVAL; - } - if (rate > data->max_fb_rate) { use_fb_prediv = true; rate /= 2; -- GitLab From 4aa6c99d31c0cc471b7f243f5d314391a1abcaf3 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 30 Sep 2016 10:33:59 +0200 Subject: [PATCH 0695/1167] clk: mvebu: armada-37xx-periph: Fix the clock gate flag For the gate part of the peripheral clock setting the bit disables the clock and clearing it enables the clock. This is not the default behavior of clk_gate component, so we need to use the CLK_GATE_SET_TO_DISABLE flag. Signed-off-by: Gregory CLEMENT Fixes: 8ca4746a78ab ("clk: mvebu: Add the peripheral clock driver for Armada 3700") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-37xx-periph.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index d5dfbad4ceabd..cecb0fdfaef6c 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -329,6 +329,7 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data, gate->lock = lock; gate_ops = gate_hw->init->ops; gate->reg = reg + (u64)gate->reg; + gate->flags = CLK_GATE_SET_TO_DISABLE; } if (data->rate_hw) { -- GitLab From d3397484bb5b8534289a630c1a78500ff4f2fbf4 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 8 Oct 2016 21:38:12 +0800 Subject: [PATCH 0696/1167] clk: hi6220: use CLK_OF_DECLARE_DRIVER for sysctrl and mediactrl clock init The hi6220-sysctrl and hi6220-mediactrl are not only clock provider but also reset controller. It worked fine that single sysctrl/mediactrl device node in DT can be used to initialize clock driver and populate platform device for reset controller. But it stops working after commit 989eafd0b609 ("clk: core: Avoid double initialization of clocks") gets merged. The commit sets flag OF_POPULATED during clock initialization to skip the platform device populating for the same device node. On hi6220, it effectively makes hi6220-sysctrl reset driver not probe any more. The patch changes hi6220 sysctrl and mediactrl clock init macro from CLK_OF_DECLARE to CLK_OF_DECLARE_DRIVER, so that the reset driver using the same hardware block can continue working. Signed-off-by: Shawn Guo Tested-by: John Stultz Signed-off-by: Stephen Boyd --- drivers/clk/hisilicon/clk-hi6220.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c index fe364e63f8de8..c0e8e1f196aae 100644 --- a/drivers/clk/hisilicon/clk-hi6220.c +++ b/drivers/clk/hisilicon/clk-hi6220.c @@ -195,7 +195,7 @@ static void __init hi6220_clk_sys_init(struct device_node *np) hi6220_clk_register_divider(hi6220_div_clks_sys, ARRAY_SIZE(hi6220_div_clks_sys), clk_data); } -CLK_OF_DECLARE(hi6220_clk_sys, "hisilicon,hi6220-sysctrl", hi6220_clk_sys_init); +CLK_OF_DECLARE_DRIVER(hi6220_clk_sys, "hisilicon,hi6220-sysctrl", hi6220_clk_sys_init); /* clocks in media controller */ @@ -252,7 +252,7 @@ static void __init hi6220_clk_media_init(struct device_node *np) hi6220_clk_register_divider(hi6220_div_clks_media, ARRAY_SIZE(hi6220_div_clks_media), clk_data); } -CLK_OF_DECLARE(hi6220_clk_media, "hisilicon,hi6220-mediactrl", hi6220_clk_media_init); +CLK_OF_DECLARE_DRIVER(hi6220_clk_media, "hisilicon,hi6220-mediactrl", hi6220_clk_media_init); /* clocks in pmctrl */ -- GitLab From 3ab7511eafdd5c4f40d2832f09554478dfbea170 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 17 Oct 2016 17:23:59 +0100 Subject: [PATCH 0697/1167] ALSA: hda - allow 40 bit DMA mask for NVidia devices Commit 49d9e77e72cf ("ALSA: hda - Fix system panic when DMA > 40 bits for Nvidia audio controllers") simply disabled any DMA exceeding 32 bits for NVidia devices, even though they are capable of performing DMA up to 40 bits. On some architectures (such as arm64), system memory is not guaranteed to be 32-bit addressable by PCI devices, and so this change prevents NVidia devices from working on platforms such as AMD Seattle. Since the original commit already mentioned that up to 40 bits of DMA is supported, and given that the code has been updated in the meantime to support a 40 bit DMA mask on other devices, revert commit 49d9e77e72cf and explicitly set the DMA mask to 40 bits for NVidia devices. Fixes: 49d9e77e72cf ('ALSA: hda - Fix system panic when DMA > 40 bits...') Signed-off-by: Ard Biesheuvel Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c3469f756ec25..c64d986009a9e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -341,8 +341,7 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ - (AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \ - AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\ + (AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\ AZX_DCAPS_SNOOP_TYPE(NVIDIA)) #define AZX_DCAPS_PRESET_CTHDA \ @@ -1716,6 +1715,10 @@ static int azx_first_init(struct azx *chip) } } + /* NVidia hardware normally only supports up to 40 bits of DMA */ + if (chip->pci->vendor == PCI_VENDOR_ID_NVIDIA) + dma_bits = 40; + /* disable 64bit DMA address on some devices */ if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { dev_dbg(card->dev, "Disabling 64bit DMA\n"); -- GitLab From a2ed0b391dd9c3ef1d64c7c3e370f4a5ffcd324a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 4 Oct 2016 13:44:06 +0200 Subject: [PATCH 0698/1167] isofs: Do not return EACCES for unknown filesystems When isofs_mount() is called to mount a device read-write, it returns EACCES even before it checks that the device actually contains an isofs filesystem. This may confuse mount(8) which then tries to mount all subsequent filesystem types in read-only mode. Fix the problem by returning EACCES only once we verify that the device indeed contains an iso9660 filesystem. CC: stable@vger.kernel.org Fixes: 17b7f7cf58926844e1dd40f5eb5348d481deca6a Reported-by: Kent Overstreet Reported-by: Karel Zak Signed-off-by: Jan Kara --- fs/isofs/inode.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index ad0c745ebad72..871c8b3920991 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -687,6 +687,11 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) pri_bh = NULL; root_found: + /* We don't support read-write mounts */ + if (!(s->s_flags & MS_RDONLY)) { + error = -EACCES; + goto out_freebh; + } if (joliet_level && (pri == NULL || !opt.rock)) { /* This is the case of Joliet with the norock mount flag. @@ -1501,9 +1506,6 @@ struct inode *__isofs_iget(struct super_block *sb, static struct dentry *isofs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - /* We don't support read-write mounts */ - if (!(flags & MS_RDONLY)) - return ERR_PTR(-EACCES); return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super); } -- GitLab From e952813e210b3addaea063da64ef68c3f30c0aa2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Oct 2016 00:05:34 +0200 Subject: [PATCH 0699/1167] ext2: avoid bogus -Wmaybe-uninitialized warning On ARM, we get this false-positive warning since the rework of the ext2_get_blocks interface: fs/ext2/inode.c: In function 'ext2_get_block': include/linux/buffer_head.h:340:16: error: 'bno' may be used uninitialized in this function [-Werror=maybe-uninitialized] The calling conventions for this function are rather complex, and it's not surprising that the compiler gets this wrong, I spent a long time trying to understand how it all fits together myself. This change to avoid the warning makes sure the compiler sees that we always set 'bno' pointer whenever we have a positive return code. The transformation is correct because we always arrive at the 'got_it' label with a positive count that gets used as the return value, while any branch to the 'cleanup' label has a negative or zero 'err'. Fixes: 6750ad71986d ("ext2: stop passing buffer_head to ext2_get_blocks") Signed-off-by: Arnd Bergmann Reviewed-by: Christoph Hellwig Cc: Dave Chinner Signed-off-by: Jan Kara --- fs/ext2/inode.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index d831e24dc8853..41b8b44a391cb 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -622,7 +622,7 @@ static int ext2_get_blocks(struct inode *inode, u32 *bno, bool *new, bool *boundary, int create) { - int err = -EIO; + int err; int offsets[4]; Indirect chain[4]; Indirect *partial; @@ -639,7 +639,7 @@ static int ext2_get_blocks(struct inode *inode, depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); if (depth == 0) - return (err); + return -EIO; partial = ext2_get_branch(inode, depth, offsets, chain, &err); /* Simplest case - block found, no allocation needed */ @@ -761,7 +761,6 @@ static int ext2_get_blocks(struct inode *inode, ext2_splice_branch(inode, iblock, partial, indirect_blks, count); mutex_unlock(&ei->truncate_mutex); got_it: - *bno = le32_to_cpu(chain[depth-1].key); if (count > blocks_to_boundary) *boundary = true; err = count; @@ -772,6 +771,8 @@ static int ext2_get_blocks(struct inode *inode, brelse(partial->bh); partial--; } + if (err > 0) + *bno = le32_to_cpu(chain[depth-1].key); return err; } -- GitLab From f771d5bb71d4df9573d12386400540516672208b Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Tue, 18 Oct 2016 10:59:09 +0800 Subject: [PATCH 0700/1167] ALSA: hda - Adding a new group of pin cfg into ALC295 pin quirk table We have a new Dell laptop model which uses ALC295, the pin definition is different from the existing ones in the pin quirk table, to fix the headset mic detection and mic mute led's problem, we need to add the new pin defintion into the pin quirk table. Cc: stable@vger.kernel.org Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b58e8c76346ac..8483fc20f6350 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5811,8 +5811,6 @@ static const struct hda_model_fixup alc269_fixup_models[] = { #define ALC295_STANDARD_PINS \ {0x12, 0xb7a60130}, \ {0x14, 0x90170110}, \ - {0x17, 0x21014020}, \ - {0x18, 0x21a19030}, \ {0x21, 0x04211020} #define ALC298_STANDARD_PINS \ @@ -6039,7 +6037,13 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { ALC292_STANDARD_PINS, {0x13, 0x90a60140}), SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC295_STANDARD_PINS), + ALC295_STANDARD_PINS, + {0x17, 0x21014020}, + {0x18, 0x21a19030}), + SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC295_STANDARD_PINS, + {0x17, 0x21014040}, + {0x18, 0x21a19050}), SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, ALC298_STANDARD_PINS, {0x17, 0x90170110}), -- GitLab From f72f94555aa32b2c4374dde5ad9b960cc4ff32e2 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 12 Oct 2016 14:48:28 +0800 Subject: [PATCH 0701/1167] ceph: fix readdir vs fragmentation race following sequence of events tigger the race - client readdir frag 0* -> got item 'A' - MDS merges frag 0* and frag 1* - client send readdir request (frag 1*, offset 2, readdir_start 'A') - MDS reply items (that are after item 'A') in frag * Link: http://tracker.ceph.com/issues/17286 Signed-off-by: Yan, Zheng --- fs/ceph/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index bca1b49c1c4b1..ef4d046473256 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1511,7 +1511,8 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, ceph_fill_dirfrag(d_inode(parent), rinfo->dir_dir); } - if (ceph_frag_is_leftmost(frag) && req->r_readdir_offset == 2) { + if (ceph_frag_is_leftmost(frag) && req->r_readdir_offset == 2 && + !(rinfo->hash_order && req->r_path2)) { /* note dir version at start of readdir so we can tell * if any dentries get dropped */ req->r_dir_release_cnt = atomic64_read(&ci->i_release_count); -- GitLab From 31ca58781019de191c7f520f0626ca76a88c1f6e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 13 Oct 2016 17:15:37 +0200 Subject: [PATCH 0702/1167] ceph: fix uninitialized dentry pointer in ceph_real_mount() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fs/ceph/super.c: In function ‘ceph_real_mount’: fs/ceph/super.c:818: warning: ‘root’ may be used uninitialized in this function If s_root is already valid, dentry pointer root is never initialized, and returned by ceph_real_mount(). This will cause a crash later when the caller dereferences the pointer. Fixes: ce2728aaa82bbeba ("ceph: avoid accessing / when mounting a subpath") Signed-off-by: Geert Uytterhoeven Signed-off-by: Yan, Zheng --- fs/ceph/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ceph/super.c b/fs/ceph/super.c index a29ffce981879..b382e5910eea8 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -845,6 +845,8 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) err = ceph_fs_debugfs_init(fsc); if (err < 0) goto fail; + } else { + root = dget(fsc->sb->s_root); } fsc->mount_state = CEPH_MOUNT_MOUNTED; -- GitLab From 55a76b59b5fef408442e16121faa9eb00a65fd50 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 13 Oct 2016 16:26:15 -0500 Subject: [PATCH 0703/1167] locking/rwsem/x86: Add stack frame dependency for ____down_write() Arnd reported the following objtool warning: kernel/locking/rwsem.o: warning: objtool: down_write_killable()+0x16: call without frame pointer save/setup The warning means gcc placed the ____down_write() inline asm (and its call instruction) before the frame pointer setup in down_write_killable(), which breaks frame pointer convention and can result in incorrect stack traces. Force the stack frame to be created before the call instruction by listing the stack pointer as an output operand in the inline asm statement. Reported-by: Arnd Bergmann Signed-off-by: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1188b7015f04baf361e59de499ee2d7272c59dce.1476393828.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar --- arch/x86/include/asm/rwsem.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index 3d33a719f5c1d..a34e0d4b957d6 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h @@ -103,8 +103,10 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem) ({ \ long tmp; \ struct rw_semaphore* ret; \ + register void *__sp asm(_ASM_SP); \ + \ asm volatile("# beginning down_write\n\t" \ - LOCK_PREFIX " xadd %1,(%3)\n\t" \ + LOCK_PREFIX " xadd %1,(%4)\n\t" \ /* adds 0xffff0001, returns the old value */ \ " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \ /* was the active mask 0 before? */\ @@ -112,7 +114,7 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem) " call " slow_path "\n" \ "1:\n" \ "# ending down_write" \ - : "+m" (sem->count), "=d" (tmp), "=a" (ret) \ + : "+m" (sem->count), "=d" (tmp), "=a" (ret), "+r" (__sp) \ : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \ : "memory", "cc"); \ ret; \ -- GitLab From 5f43086bb9224987010460dcf3dee68fbd4f574d Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 8 Oct 2016 10:12:28 +0200 Subject: [PATCH 0704/1167] locking, fs/locks: Add missing file_sem locks I overlooked a few code-paths that can lead to locks_delete_global_locks(). Reported-by: Dmitry Vyukov Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Jeff Layton Cc: Al Viro Cc: Bruce Fields Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-fsdevel@vger.kernel.org Cc: syzkaller Link: http://lkml.kernel.org/r/20161008081228.GF3142@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar --- fs/locks.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/locks.c b/fs/locks.c index ce93b416b490f..22c5b4aa49611 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1609,6 +1609,7 @@ int fcntl_getlease(struct file *filp) ctx = smp_load_acquire(&inode->i_flctx); if (ctx && !list_empty_careful(&ctx->flc_lease)) { + percpu_down_read_preempt_disable(&file_rwsem); spin_lock(&ctx->flc_lock); time_out_leases(inode, &dispose); list_for_each_entry(fl, &ctx->flc_lease, fl_list) { @@ -1618,6 +1619,8 @@ int fcntl_getlease(struct file *filp) break; } spin_unlock(&ctx->flc_lock); + percpu_up_read_preempt_enable(&file_rwsem); + locks_dispose_list(&dispose); } return type; @@ -2529,11 +2532,14 @@ locks_remove_lease(struct file *filp, struct file_lock_context *ctx) if (list_empty(&ctx->flc_lease)) return; + percpu_down_read_preempt_disable(&file_rwsem); spin_lock(&ctx->flc_lock); list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) if (filp == fl->fl_file) lease_modify(fl, F_UNLCK, &dispose); spin_unlock(&ctx->flc_lock); + percpu_up_read_preempt_enable(&file_rwsem); + locks_dispose_list(&dispose); } -- GitLab From 5130ccea7cf4646a24c005be1309b7f86f1e91c9 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 15:11:29 +0000 Subject: [PATCH 0705/1167] ceph: fix non static symbol warning Fixes the following sparse warning: fs/ceph/xattr.c:19:28: warning: symbol 'ceph_other_xattr_handler' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Ilya Dryomov --- fs/ceph/xattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 40b703217977d..febc28f9e2c27 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -16,7 +16,7 @@ static int __remove_xattr(struct ceph_inode_info *ci, struct ceph_inode_xattr *xattr); -const struct xattr_handler ceph_other_xattr_handler; +static const struct xattr_handler ceph_other_xattr_handler; /* * List of handlers for synthetic system.* attributes. Other @@ -1086,7 +1086,7 @@ static int ceph_set_xattr_handler(const struct xattr_handler *handler, return __ceph_setxattr(inode, name, value, size, flags); } -const struct xattr_handler ceph_other_xattr_handler = { +static const struct xattr_handler ceph_other_xattr_handler = { .prefix = "", /* match any name => handlers called with full name */ .get = ceph_get_xattr_handler, .set = ceph_set_xattr_handler, -- GitLab From 2317eacd9cf9dc1beee74ddb453bdd7552a64a27 Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 17 Oct 2016 17:36:23 -0700 Subject: [PATCH 0706/1167] Revert "usb: dwc2: gadget: change variable name to more meaningful" This reverts commit ba48eab8866c ("usb: dwc2: gadget: change variable name to more meaningful"). This is needed to cleanly revert commit aa381a7259c3 ("usb: dwc2: gadget: fix TX FIFO size and address initialization") which may cause regressions on some platforms. Signed-off-by: John Youn Cc: Robert Baldyga Cc: Stefan Wahren Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 4cd6403a75668..aac4af3ea68fa 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -186,7 +186,7 @@ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, */ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) { - unsigned int fifo; + unsigned int ep; unsigned int addr; int timeout; u32 dptxfsizn; @@ -217,8 +217,8 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) * them to endpoints dynamically according to maxpacket size value of * given endpoint. */ - for (fifo = 1; fifo < MAX_EPS_CHANNELS; fifo++) { - dptxfsizn = dwc2_readl(hsotg->regs + DPTXFSIZN(fifo)); + for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { + dptxfsizn = dwc2_readl(hsotg->regs + DPTXFSIZN(ep)); val = (dptxfsizn & FIFOSIZE_DEPTH_MASK) | addr; addr += dptxfsizn >> FIFOSIZE_DEPTH_SHIFT; @@ -226,7 +226,7 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) if (addr > hsotg->fifo_mem) break; - dwc2_writel(val, hsotg->regs + DPTXFSIZN(fifo)); + dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep)); } /* -- GitLab From 3fa9538539ac737096c81f3315a14670b1609092 Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 17 Oct 2016 17:36:25 -0700 Subject: [PATCH 0707/1167] Revert "usb: dwc2: gadget: fix TX FIFO size and address initialization" This reverts commit aa381a7259c3 ("usb: dwc2: gadget: fix TX FIFO size and address initialization"). The original commit removed the FIFO size programming per endpoint. The DPTXFSIZn register is also used for DIEPTXFn and the SIZE field is r/w in dedicated fifo mode. So it isn't appropriate to simply remove this initialization as it might break existing behavior. Also, some cores might not have enough fifo space to handle the programming method used in the reverted patch, resulting in fifo initialization failure. Signed-off-by: John Youn Cc: Robert Baldyga Cc: Stefan Wahren Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.h | 7 ++++++ drivers/usb/dwc2/gadget.c | 47 ++++++++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index aad4107ef927e..2a21a0414b1d3 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -259,6 +259,13 @@ enum dwc2_lx_state { DWC2_L3, /* Off state */ }; +/* + * Gadget periodic tx fifo sizes as used by legacy driver + * EP0 is not included + */ +#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \ + 768, 0, 0, 0, 0, 0, 0, 0} + /* Gadget ep0 states */ enum dwc2_ep0_state { DWC2_EP0_SETUP, diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index aac4af3ea68fa..24fbebc9b4090 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -189,7 +189,6 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) unsigned int ep; unsigned int addr; int timeout; - u32 dptxfsizn; u32 val; /* Reset fifo map if not correctly cleared during previous session */ @@ -218,13 +217,13 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) * given endpoint. */ for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { - dptxfsizn = dwc2_readl(hsotg->regs + DPTXFSIZN(ep)); - - val = (dptxfsizn & FIFOSIZE_DEPTH_MASK) | addr; - addr += dptxfsizn >> FIFOSIZE_DEPTH_SHIFT; - - if (addr > hsotg->fifo_mem) - break; + if (!hsotg->g_tx_fifo_sz[ep]) + continue; + val = addr; + val |= hsotg->g_tx_fifo_sz[ep] << FIFOSIZE_DEPTH_SHIFT; + WARN_ONCE(addr + hsotg->g_tx_fifo_sz[ep] > hsotg->fifo_mem, + "insufficient fifo memory"); + addr += hsotg->g_tx_fifo_sz[ep]; dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep)); } @@ -3807,10 +3806,36 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) static void dwc2_hsotg_of_probe(struct dwc2_hsotg *hsotg) { struct device_node *np = hsotg->dev->of_node; + u32 len = 0; + u32 i = 0; /* Enable dma if requested in device tree */ hsotg->g_using_dma = of_property_read_bool(np, "g-use-dma"); + /* + * Register TX periodic fifo size per endpoint. + * EP0 is excluded since it has no fifo configuration. + */ + if (!of_find_property(np, "g-tx-fifo-size", &len)) + goto rx_fifo; + + len /= sizeof(u32); + + /* Read tx fifo sizes other than ep0 */ + if (of_property_read_u32_array(np, "g-tx-fifo-size", + &hsotg->g_tx_fifo_sz[1], len)) + goto rx_fifo; + + /* Add ep0 */ + len++; + + /* Make remaining TX fifos unavailable */ + if (len < MAX_EPS_CHANNELS) { + for (i = len; i < MAX_EPS_CHANNELS; i++) + hsotg->g_tx_fifo_sz[i] = 0; + } + +rx_fifo: /* Register RX fifo size */ of_property_read_u32(np, "g-rx-fifo-size", &hsotg->g_rx_fifo_sz); @@ -3832,10 +3857,13 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) struct device *dev = hsotg->dev; int epnum; int ret; + int i; + u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE; /* Initialize to legacy fifo configuration values */ hsotg->g_rx_fifo_sz = 2048; hsotg->g_np_g_tx_fifo_sz = 1024; + memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo)); /* Device tree specific probe */ dwc2_hsotg_of_probe(hsotg); @@ -3853,6 +3881,9 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", hsotg->g_np_g_tx_fifo_sz); dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz); + for (i = 0; i < MAX_EPS_CHANNELS; i++) + dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i, + hsotg->g_tx_fifo_sz[i]); hsotg->gadget.max_speed = USB_SPEED_HIGH; hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; -- GitLab From a1aa8cf6471b17c0fa7132ea5eeef0ae07ca07cd Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 17 Oct 2016 17:36:28 -0700 Subject: [PATCH 0708/1167] Revert "Documentation: devicetree: dwc2: Deprecate g-tx-fifo-size" This binding was deprecated due to commit aa381a7259c3 ("usb: dwc2: gadget: fix TX FIFO size and address initialization"). However that commit is now reverted, so also revert this commit. The binding is valid and shouldn't be deprecated. This reverts commit 65e1ff7f4b5b ("Documentation: devicetree: dwc2: Deprecate g-tx-fifo-size"). Signed-off-by: John Youn Acked-by: Rob Herring Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc2.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt index 455f2c310a1b9..2c30a5479069b 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.txt +++ b/Documentation/devicetree/bindings/usb/dwc2.txt @@ -28,10 +28,7 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties - g-use-dma: enable dma usage in gadget driver. - g-rx-fifo-size: size of rx fifo size in gadget mode. - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode. - -Deprecated properties: -- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) - in gadget mode. +- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode. Example: -- GitLab From d69bb92e402ff948bdcd39f19c9067874fb86873 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich Date: Thu, 13 Oct 2016 14:36:41 +0200 Subject: [PATCH 0709/1167] ALSA: asihpi: fix kernel memory disclosure Some elements in hr are not cleared before being copied to user space, leaking kernel heap memory to user space. For example, this happens in the error handling code for the HPI_ADAPTER_DELETE case. Zero the memory before it's copied. Signed-off-by: Vlad Tsyrklevich Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index d17937b92331e..7e3aa50b21f9d 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -111,7 +111,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -EINVAL; hm = kmalloc(sizeof(*hm), GFP_KERNEL); - hr = kmalloc(sizeof(*hr), GFP_KERNEL); + hr = kzalloc(sizeof(*hr), GFP_KERNEL); if (!hm || !hr) { err = -ENOMEM; goto out; -- GitLab From 5366f1460c447f8ecb7d13e99e5ccb4bcfc21927 Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Wed, 28 Sep 2016 00:20:13 +0930 Subject: [PATCH 0710/1167] pinctrl: aspeed: "Not enabled" is a significant mux state Consider a scenario with one pin P that has two signals A and B, where A is defined to be higher priority than B: That is, if the mux IP is in a state that would consider both A and B to be active on P, then A will be the active signal. To instead configure B as the active signal we must configure the mux so that A is inactive. The mux state for signals can be described by logical operations on one or more bits from one or more registers (a "signal expression"), which in some cases leads to aliased mux states for a particular signal. Further, signals described by multi-bit bitfields often do not only need to record the states that would make them active (the "enable" expressions), but also the states that makes them inactive (the "disable" expressions). All of this combined leads to four possible states for a signal: 1. A signal is active with respect to an "enable" expression 2. A signal is not active with respect to an "enable" expression 3. A signal is inactive with respect to a "disable" expression 4. A signal is not inactive with respect to a "disable" expression In the case of P, if we are looking to activate B without explicitly having configured A it's enough to consider A inactive if all of A's "enable" signal expressions evaluate to "not active". If any evaluate to "active" then the corresponding "disable" states must be applied so it becomes inactive. For example, on the AST2400 the pins composing GPIO bank H provide signals ROMD8 through ROMD15 (high priority) and those for UART6 (low priority). The mux states for ROMD8 through ROMD15 are aliased, i.e. there are two mux states that result in the respective signals being configured: A. SCU90[6]=1 B. Strap[4,1:0]=100 Further, the second mux state is a 3-bit bitfield that explicitly defines the enabled state but the disabled state is implicit, i.e. if Strap[4,1:0] is not exactly "100" then ROMD8 through ROMD15 are not considered active. This requires the mux function evaluation logic to use approach 2. above, however the existing code was using approach 3. The problem was brought to light on the Palmetto machines where the strap register value is 0x120ce416, and prevented GPIO requests in bank H from succeeding despite the hardware being in a position to allow them. Fixes: 318398c09a8d ("pinctrl: Add core pinctrl support for Aspeed SoCs") Signed-off-by: Andrew Jeffery Reviewed-by: Joel Stanley Signed-off-by: Linus Walleij --- drivers/pinctrl/aspeed/pinctrl-aspeed.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c index 0391f9f13f3e6..49aeba9125319 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c @@ -166,13 +166,9 @@ static bool aspeed_sig_expr_set(const struct aspeed_sig_expr *expr, bool enable, struct regmap *map) { int i; - bool ret; - - ret = aspeed_sig_expr_eval(expr, enable, map); - if (ret) - return ret; for (i = 0; i < expr->ndescs; i++) { + bool ret; const struct aspeed_sig_desc *desc = &expr->descs[i]; u32 pattern = enable ? desc->enable : desc->disable; @@ -199,12 +195,18 @@ static bool aspeed_sig_expr_set(const struct aspeed_sig_expr *expr, static bool aspeed_sig_expr_enable(const struct aspeed_sig_expr *expr, struct regmap *map) { + if (aspeed_sig_expr_eval(expr, true, map)) + return true; + return aspeed_sig_expr_set(expr, true, map); } static bool aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr, struct regmap *map) { + if (!aspeed_sig_expr_eval(expr, true, map)) + return true; + return aspeed_sig_expr_set(expr, false, map); } -- GitLab From 97e8c3f5e76582d63026585c79d39c1d1fb960e5 Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Wed, 28 Sep 2016 00:20:14 +0930 Subject: [PATCH 0711/1167] pinctrl: aspeed-g5: Fix names of GPID2 pins Fixes simple typos in the initial commit. There is no behavioural change. Fixes: 56e57cb6c07f (pinctrl: Add pinctrl-aspeed-g5 driver) Reported-by: Xo Wang Signed-off-by: Andrew Jeffery Reviewed-by: Joel Stanley Signed-off-by: Linus Walleij --- drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c index e1ab864e1a7f0..14639834a5eba 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c @@ -151,21 +151,21 @@ FUNC_GROUP_DECL(GPID0, F19, E21); #define GPID2_DESC SIG_DESC_SET(SCU8C, 9) -#define D20 26 +#define F20 26 SIG_EXPR_LIST_DECL_SINGLE(SD2DAT0, SD2, SD2_DESC); SIG_EXPR_DECL(GPID2IN, GPID2, GPID2_DESC); SIG_EXPR_DECL(GPID2IN, GPID, GPID_DESC); SIG_EXPR_LIST_DECL_DUAL(GPID2IN, GPID2, GPID); -MS_PIN_DECL(D20, GPIOD2, SD2DAT0, GPID2IN); +MS_PIN_DECL(F20, GPIOD2, SD2DAT0, GPID2IN); -#define D21 27 +#define D20 27 SIG_EXPR_LIST_DECL_SINGLE(SD2DAT1, SD2, SD2_DESC); SIG_EXPR_DECL(GPID2OUT, GPID2, GPID2_DESC); SIG_EXPR_DECL(GPID2OUT, GPID, GPID_DESC); SIG_EXPR_LIST_DECL_DUAL(GPID2OUT, GPID2, GPID); -MS_PIN_DECL(D21, GPIOD3, SD2DAT1, GPID2OUT); +MS_PIN_DECL(D20, GPIOD3, SD2DAT1, GPID2OUT); -FUNC_GROUP_DECL(GPID2, D20, D21); +FUNC_GROUP_DECL(GPID2, F20, D20); #define GPIE_DESC SIG_DESC_SET(HW_STRAP1, 21) #define GPIE0_DESC SIG_DESC_SET(SCU8C, 12) @@ -614,7 +614,6 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = { ASPEED_PINCTRL_PIN(D10), ASPEED_PINCTRL_PIN(D2), ASPEED_PINCTRL_PIN(D20), - ASPEED_PINCTRL_PIN(D21), ASPEED_PINCTRL_PIN(D4), ASPEED_PINCTRL_PIN(D5), ASPEED_PINCTRL_PIN(D6), @@ -630,6 +629,7 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = { ASPEED_PINCTRL_PIN(E7), ASPEED_PINCTRL_PIN(E9), ASPEED_PINCTRL_PIN(F19), + ASPEED_PINCTRL_PIN(F20), ASPEED_PINCTRL_PIN(F9), ASPEED_PINCTRL_PIN(H20), ASPEED_PINCTRL_PIN(L1), -- GitLab From d3dbabe9848092d26d14076cdf4d52734f998580 Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Wed, 28 Sep 2016 00:20:15 +0930 Subject: [PATCH 0712/1167] pinctrl: aspeed-g5: Fix GPIOE1 typo This prevented C20 from successfully being muxed as GPIO. Fixes: 56e57cb6c07f (pinctrl: Add pinctrl-aspeed-g5 driver) Signed-off-by: Andrew Jeffery Reviewed-by: Joel Stanley Signed-off-by: Linus Walleij --- drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c index 14639834a5eba..235d929e74fd3 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c @@ -182,7 +182,7 @@ SIG_EXPR_LIST_DECL_SINGLE(NDCD3, NDCD3, SIG_DESC_SET(SCU80, 17)); SIG_EXPR_DECL(GPIE0OUT, GPIE0, GPIE0_DESC); SIG_EXPR_DECL(GPIE0OUT, GPIE, GPIE_DESC); SIG_EXPR_LIST_DECL_DUAL(GPIE0OUT, GPIE0, GPIE); -MS_PIN_DECL(C20, GPIE0, NDCD3, GPIE0OUT); +MS_PIN_DECL(C20, GPIOE1, NDCD3, GPIE0OUT); FUNC_GROUP_DECL(GPIE0, B20, C20); -- GitLab From 8eb37aff76f4d97db39e62a838cd37c4d341d673 Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Wed, 28 Sep 2016 00:20:16 +0930 Subject: [PATCH 0713/1167] pinctrl: aspeed-g5: Fix pin association of SPI1 function The SPI1 function was associated with the wrong pins: The functions that those pins provide is either an SPI debug or passthrough function coupled to SPI1. Make the SPI1 mux function configure the relevant pins and associate new SPI1DEBUG and SPI1PASSTHRU functions with the pins that were already defined. The notation used in the datasheet's multi-function pin table for the SoC is often creative: in this case the SYS* signals are enabled by a single bit, which is nothing unusual on its own, but in this case the bit was also participating in a multi-bit bitfield and therefore represented multiple functions. This fact was overlooked in the original patch. Fixes: 56e57cb6c07f (pinctrl: Add pinctrl-aspeed-g5 driver) Signed-off-by: Andrew Jeffery Reviewed-by: Joel Stanley Acked-by: Rob Herring Signed-off-by: Linus Walleij --- .../bindings/pinctrl/pinctrl-aspeed.txt | 4 +- drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 86 +++++++++++++++++-- 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt index 5e60ad18f147c..2ad18c4ea55c5 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt @@ -43,7 +43,9 @@ aspeed,ast2500-pinctrl, aspeed,g5-pinctrl: GPID0 GPID2 GPIE0 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 I2C5 I2C6 I2C7 I2C8 I2C9 MAC1LINK MDIO1 MDIO2 OSCCLK PEWAKE PWM0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7 -RGMII1 RGMII2 RMII1 RMII2 SD1 SPI1 TIMER4 TIMER5 TIMER6 TIMER7 TIMER8 +RGMII1 RGMII2 RMII1 RMII2 SD1 SPI1 SPI1DEBUG SPI1PASSTHRU TIMER4 TIMER5 TIMER6 +TIMER7 TIMER8 VGABIOSROM + Examples: diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c index 235d929e74fd3..c8c72e8259d38 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c @@ -186,24 +186,84 @@ MS_PIN_DECL(C20, GPIOE1, NDCD3, GPIE0OUT); FUNC_GROUP_DECL(GPIE0, B20, C20); -#define SPI1_DESC SIG_DESC_SET(HW_STRAP1, 13) +#define SPI1_DESC { HW_STRAP1, GENMASK(13, 12), 1, 0 } +#define SPI1DEBUG_DESC { HW_STRAP1, GENMASK(13, 12), 2, 0 } +#define SPI1PASSTHRU_DESC { HW_STRAP1, GENMASK(13, 12), 3, 0 } + #define C18 64 -SIG_EXPR_LIST_DECL_SINGLE(SYSCS, SPI1, COND1, SPI1_DESC); +SIG_EXPR_DECL(SYSCS, SPI1DEBUG, COND1, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SYSCS, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL_DUAL(SYSCS, SPI1DEBUG, SPI1PASSTHRU); SS_PIN_DECL(C18, GPIOI0, SYSCS); #define E15 65 -SIG_EXPR_LIST_DECL_SINGLE(SYSCK, SPI1, COND1, SPI1_DESC); +SIG_EXPR_DECL(SYSCK, SPI1DEBUG, COND1, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SYSCK, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL_DUAL(SYSCK, SPI1DEBUG, SPI1PASSTHRU); SS_PIN_DECL(E15, GPIOI1, SYSCK); -#define A14 66 -SIG_EXPR_LIST_DECL_SINGLE(SYSMOSI, SPI1, COND1, SPI1_DESC); -SS_PIN_DECL(A14, GPIOI2, SYSMOSI); +#define B16 66 +SIG_EXPR_DECL(SYSMOSI, SPI1DEBUG, COND1, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SYSMOSI, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL_DUAL(SYSMOSI, SPI1DEBUG, SPI1PASSTHRU); +SS_PIN_DECL(B16, GPIOI2, SYSMOSI); #define C16 67 -SIG_EXPR_LIST_DECL_SINGLE(SYSMISO, SPI1, COND1, SPI1_DESC); +SIG_EXPR_DECL(SYSMISO, SPI1DEBUG, COND1, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SYSMISO, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL_DUAL(SYSMISO, SPI1DEBUG, SPI1PASSTHRU); SS_PIN_DECL(C16, GPIOI3, SYSMISO); -FUNC_GROUP_DECL(SPI1, C18, E15, A14, C16); +#define VB_DESC SIG_DESC_SET(HW_STRAP1, 5) + +#define B15 68 +SIG_EXPR_DECL(SPI1CS0, SPI1, COND1, SPI1_DESC); +SIG_EXPR_DECL(SPI1CS0, SPI1DEBUG, COND1, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SPI1CS0, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL(SPI1CS0, SIG_EXPR_PTR(SPI1CS0, SPI1), + SIG_EXPR_PTR(SPI1CS0, SPI1DEBUG), + SIG_EXPR_PTR(SPI1CS0, SPI1PASSTHRU)); +SIG_EXPR_LIST_DECL_SINGLE(VBCS, VGABIOSROM, COND1, VB_DESC); +MS_PIN_DECL(B15, GPIOI4, SPI1CS0, VBCS); + +#define C15 69 +SIG_EXPR_DECL(SPI1CK, SPI1, COND1, SPI1_DESC); +SIG_EXPR_DECL(SPI1CK, SPI1DEBUG, COND1, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SPI1CK, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL(SPI1CK, SIG_EXPR_PTR(SPI1CK, SPI1), + SIG_EXPR_PTR(SPI1CK, SPI1DEBUG), + SIG_EXPR_PTR(SPI1CK, SPI1PASSTHRU)); +SIG_EXPR_LIST_DECL_SINGLE(VBCK, VGABIOSROM, COND1, VB_DESC); +MS_PIN_DECL(C15, GPIOI5, SPI1CK, VBCK); + +#define A14 70 +SIG_EXPR_DECL(SPI1MOSI, SPI1, COND1, SPI1_DESC); +SIG_EXPR_DECL(SPI1MOSI, SPI1DEBUG, COND1, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SPI1MOSI, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL(SPI1MOSI, SIG_EXPR_PTR(SPI1MOSI, SPI1), + SIG_EXPR_PTR(SPI1MOSI, SPI1DEBUG), + SIG_EXPR_PTR(SPI1MOSI, SPI1PASSTHRU)); +SIG_EXPR_LIST_DECL_SINGLE(VBMOSI, VGABIOSROM, COND1, VB_DESC); +MS_PIN_DECL(A14, GPIOI6, SPI1MOSI, VBMOSI); + +#define A15 71 +SIG_EXPR_DECL(SPI1MISO, SPI1, COND1, SPI1_DESC); +SIG_EXPR_DECL(SPI1MISO, SPI1DEBUG, COND1, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SPI1MISO, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL(SPI1MISO, SIG_EXPR_PTR(SPI1MISO, SPI1), + SIG_EXPR_PTR(SPI1MISO, SPI1DEBUG), + SIG_EXPR_PTR(SPI1MISO, SPI1PASSTHRU)); +SIG_EXPR_LIST_DECL_SINGLE(VBMISO, VGABIOSROM, COND1, VB_DESC); +MS_PIN_DECL(A15, GPIOI7, SPI1MISO, VBMISO); + +FUNC_GROUP_DECL(SPI1, B15, C15, A14, A15); +FUNC_GROUP_DECL(SPI1DEBUG, C18, E15, B16, C16, B15, C15, A14, A15); +FUNC_GROUP_DECL(SPI1PASSTHRU, C18, E15, B16, C16, B15, C15, A14, A15); +FUNC_GROUP_DECL(VGABIOSROM, B15, C15, A14, A15); + +#define R2 72 +SIG_EXPR_LIST_DECL_SINGLE(SGPMCK, SGPM, SIG_DESC_SET(SCU84, 8)); +SS_PIN_DECL(R2, GPIOJ0, SGPMCK); #define L2 73 SIG_EXPR_LIST_DECL_SINGLE(SGPMLD, SGPM, SIG_DESC_SET(SCU84, 9)); @@ -580,6 +640,7 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = { ASPEED_PINCTRL_PIN(A12), ASPEED_PINCTRL_PIN(A13), ASPEED_PINCTRL_PIN(A14), + ASPEED_PINCTRL_PIN(A15), ASPEED_PINCTRL_PIN(A2), ASPEED_PINCTRL_PIN(A3), ASPEED_PINCTRL_PIN(A4), @@ -592,6 +653,8 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = { ASPEED_PINCTRL_PIN(B12), ASPEED_PINCTRL_PIN(B13), ASPEED_PINCTRL_PIN(B14), + ASPEED_PINCTRL_PIN(B15), + ASPEED_PINCTRL_PIN(B16), ASPEED_PINCTRL_PIN(B2), ASPEED_PINCTRL_PIN(B20), ASPEED_PINCTRL_PIN(B3), @@ -603,6 +666,7 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = { ASPEED_PINCTRL_PIN(C12), ASPEED_PINCTRL_PIN(C13), ASPEED_PINCTRL_PIN(C14), + ASPEED_PINCTRL_PIN(C15), ASPEED_PINCTRL_PIN(C16), ASPEED_PINCTRL_PIN(C18), ASPEED_PINCTRL_PIN(C2), @@ -691,11 +755,14 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = { ASPEED_PINCTRL_GROUP(RMII2), ASPEED_PINCTRL_GROUP(SD1), ASPEED_PINCTRL_GROUP(SPI1), + ASPEED_PINCTRL_GROUP(SPI1DEBUG), + ASPEED_PINCTRL_GROUP(SPI1PASSTHRU), ASPEED_PINCTRL_GROUP(TIMER4), ASPEED_PINCTRL_GROUP(TIMER5), ASPEED_PINCTRL_GROUP(TIMER6), ASPEED_PINCTRL_GROUP(TIMER7), ASPEED_PINCTRL_GROUP(TIMER8), + ASPEED_PINCTRL_GROUP(VGABIOSROM), }; static const struct aspeed_pin_function aspeed_g5_functions[] = { @@ -733,11 +800,14 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = { ASPEED_PINCTRL_FUNC(RMII2), ASPEED_PINCTRL_FUNC(SD1), ASPEED_PINCTRL_FUNC(SPI1), + ASPEED_PINCTRL_FUNC(SPI1DEBUG), + ASPEED_PINCTRL_FUNC(SPI1PASSTHRU), ASPEED_PINCTRL_FUNC(TIMER4), ASPEED_PINCTRL_FUNC(TIMER5), ASPEED_PINCTRL_FUNC(TIMER6), ASPEED_PINCTRL_FUNC(TIMER7), ASPEED_PINCTRL_FUNC(TIMER8), + ASPEED_PINCTRL_FUNC(VGABIOSROM), }; static struct aspeed_pinctrl_data aspeed_g5_pinctrl_data = { -- GitLab From a171bc51fa697021e1b2082d7e95c12a363bc0a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 3 Oct 2016 17:56:55 +0300 Subject: [PATCH 0714/1167] pinctrl: baytrail: Fix lockdep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize the spinlock before using it. INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 2 PID: 1 Comm: swapper/0 Not tainted 4.8.0-dwc-bisect #4 Hardware name: Intel Corp. VALLEYVIEW C0 PLATFORM/BYT-T FFD8, BIOS BLAKFF81.X64.0088.R10.1403240443 FFD8_X64_R_2014_13_1_00 03/24/2014 0000000000000000 ffff8800788ff770 ffffffff8133d597 0000000000000000 0000000000000000 ffff8800788ff7e0 ffffffff810cfb9e 0000000000000002 ffff8800788ff7d0 ffffffff8205b600 0000000000000002 ffff8800788ff7f0 Call Trace: [] dump_stack+0x67/0x90 [] register_lock_class+0x52e/0x540 [] __lock_acquire+0x81/0x16b0 [] ? save_trace+0x41/0xd0 [] ? __lock_acquire+0x13b2/0x16b0 [] ? __lock_is_held+0x4a/0x70 [] lock_acquire+0xba/0x220 [] ? byt_gpio_get_direction+0x3e/0x80 [] _raw_spin_lock_irqsave+0x47/0x60 [] ? byt_gpio_get_direction+0x3e/0x80 [] byt_gpio_get_direction+0x3e/0x80 [] gpiochip_add_data+0x319/0x7d0 [] ? _raw_spin_unlock_irqrestore+0x43/0x70 [] byt_pinctrl_probe+0x2fb/0x620 [] platform_drv_probe+0x3c/0xa0 ... Based on the diff it looks like the problem was introduced in commit 71e6ca61e826 ("pinctrl: baytrail: Register pin control handling") but I wasn't able to verify that empirically as the parent commit just oopsed when I tried to boot it. Cc: Cristina Ciocan Cc: stable@vger.kernel.org Fixes: 71e6ca61e826 ("pinctrl: baytrail: Register pin control handling") Signed-off-by: Ville Syrjälä Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-baytrail.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index d22a9fe2e6dfc..71bbeb9321bad 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -1808,6 +1808,8 @@ static int byt_pinctrl_probe(struct platform_device *pdev) return PTR_ERR(vg->pctl_dev); } + raw_spin_lock_init(&vg->lock); + ret = byt_gpio_probe(vg); if (ret) { pinctrl_unregister(vg->pctl_dev); @@ -1815,7 +1817,6 @@ static int byt_pinctrl_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, vg); - raw_spin_lock_init(&vg->lock); pm_runtime_enable(&pdev->dev); return 0; -- GitLab From c538b9436751a0be2e1246b48353bc23156bdbcc Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 10 Oct 2016 16:39:31 +0300 Subject: [PATCH 0715/1167] pinctrl: intel: Only restore pins that are used by the driver Dell XPS 13 (and maybe some others) uses a GPIO (CPU_GP_1) during suspend to explicitly disable USB touchscreen interrupt. This is done to prevent situation where the lid is closed the touchscreen is left functional. The pinctrl driver (wrongly) assumes it owns all pins which are owned by host and not locked down. It is perfectly fine for BIOS to use those pins as it is also considered as host in this context. What happens is that when the lid of Dell XPS 13 is closed, the BIOS configures CPU_GP_1 low disabling the touchscreen interrupt. During resume we restore all host owned pins to the known state which includes CPU_GP_1 and this overwrites what the BIOS has programmed there causing the touchscreen to fail as no interrupts are reaching the CPU anymore. Fix this by restoring only those pins we know are explicitly requested by the kernel one way or other. Cc: stable@vger.kernel.org Link: https://bugzilla.kernel.org/show_bug.cgi?id=176361 Reported-by: AceLan Kao Tested-by: AceLan Kao Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-intel.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 63387a40b973a..01443762e5705 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -19,6 +19,7 @@ #include #include +#include "../core.h" #include "pinctrl-intel.h" /* Offset from regs */ @@ -1056,6 +1057,26 @@ int intel_pinctrl_remove(struct platform_device *pdev) EXPORT_SYMBOL_GPL(intel_pinctrl_remove); #ifdef CONFIG_PM_SLEEP +static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned pin) +{ + const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin); + + if (!pd || !intel_pad_usable(pctrl, pin)) + return false; + + /* + * Only restore the pin if it is actually in use by the kernel (or + * by userspace). It is possible that some pins are used by the + * BIOS during resume and those are not always locked down so leave + * them alone. + */ + if (pd->mux_owner || pd->gpio_owner || + gpiochip_line_is_irq(&pctrl->chip, pin)) + return true; + + return false; +} + int intel_pinctrl_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -1069,7 +1090,7 @@ int intel_pinctrl_suspend(struct device *dev) const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; u32 val; - if (!intel_pad_usable(pctrl, desc->number)) + if (!intel_pinctrl_should_save(pctrl, desc->number)) continue; val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG0)); @@ -1130,7 +1151,7 @@ int intel_pinctrl_resume(struct device *dev) void __iomem *padcfg; u32 val; - if (!intel_pad_usable(pctrl, desc->number)) + if (!intel_pinctrl_should_save(pctrl, desc->number)) continue; padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG0); -- GitLab From 6bc80629eefc3731f5881092bed610d994e05763 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Tue, 18 Oct 2016 08:16:03 +0200 Subject: [PATCH 0716/1167] bnx2: fix locking when netconsole is used Functions bnx2_reg_rd_ind(), bnx2_reg_wr_ind() and bnx2_ctx_wr() can be called with IRQs disabled when netconsole is enabled. So they should use spin_{,un}lock_irq{save,restore} instead of _bh variants. Example call flow: bnx2_poll() ->bnx2_poll_link() ->bnx2_phy_int() ->bnx2_set_remote_link() ->bnx2_shmem_rd() ->bnx2_reg_rd_ind() -> spin_lock_bh(&bp->indirect_lock); spin_unlock_bh(&bp->indirect_lock); ... -> __local_bh_enable_ip static inline void __local_bh_enable_ip(unsigned long ip) WARN_ON_ONCE(in_irq() || irqs_disabled()); <<<<<< WARN Cc: Sony Chacko Cc: Dept-HSGLinuxNICDev@qlogic.com Signed-off-by: Ivan Vecera Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 27f11a5d5fe27..b3791b394715d 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -271,22 +271,25 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr) static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset) { + unsigned long flags; u32 val; - spin_lock_bh(&bp->indirect_lock); + spin_lock_irqsave(&bp->indirect_lock, flags); BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset); val = BNX2_RD(bp, BNX2_PCICFG_REG_WINDOW); - spin_unlock_bh(&bp->indirect_lock); + spin_unlock_irqrestore(&bp->indirect_lock, flags); return val; } static void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val) { - spin_lock_bh(&bp->indirect_lock); + unsigned long flags; + + spin_lock_irqsave(&bp->indirect_lock, flags); BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset); BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, val); - spin_unlock_bh(&bp->indirect_lock); + spin_unlock_irqrestore(&bp->indirect_lock, flags); } static void @@ -304,8 +307,10 @@ bnx2_shmem_rd(struct bnx2 *bp, u32 offset) static void bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) { + unsigned long flags; + offset += cid_addr; - spin_lock_bh(&bp->indirect_lock); + spin_lock_irqsave(&bp->indirect_lock, flags); if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { int i; @@ -322,7 +327,7 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) BNX2_WR(bp, BNX2_CTX_DATA_ADR, offset); BNX2_WR(bp, BNX2_CTX_DATA, val); } - spin_unlock_bh(&bp->indirect_lock); + spin_unlock_irqrestore(&bp->indirect_lock, flags); } #ifdef BCM_CNIC -- GitLab From 8d324fd9e1bee59274d67a0a08eac5f7b1573db7 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 18 Oct 2016 09:07:29 +0200 Subject: [PATCH 0717/1167] net/hsr: Remove unused but set variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the unused but set variable master_dev in check_local_dest to fix the following GCC warning when building with 'W=1': net/hsr/hsr_forward.c: In function ‘check_local_dest’: net/hsr/hsr_forward.c:303:21: warning: variable ‘master_dev’ set but not used [-Wunused-but-set-variable] Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- net/hsr/hsr_forward.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c index 5ee1d43f13100..4ebe2aa3e7d3e 100644 --- a/net/hsr/hsr_forward.c +++ b/net/hsr/hsr_forward.c @@ -300,10 +300,6 @@ static void hsr_forward_do(struct hsr_frame_info *frame) static void check_local_dest(struct hsr_priv *hsr, struct sk_buff *skb, struct hsr_frame_info *frame) { - struct net_device *master_dev; - - master_dev = hsr_port_get_hsr(hsr, HSR_PT_MASTER)->dev; - if (hsr_addr_is_self(hsr, eth_hdr(skb)->h_dest)) { frame->is_local_exclusive = true; skb->pkt_type = PACKET_HOST; -- GitLab From 902943c0d759a090490b2bf6c91a49395b353653 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 18 Oct 2016 09:20:33 +0200 Subject: [PATCH 0718/1167] dwc_eth_qos: do not clear pause flags from phy_device->supported phy_device->supported is originally set by the PHY driver. The ethernet driver should filter phy_device->supported to only contain flags supported by the IP. The IP supports setting rx and tx flow control independently, therefore SUPPORTED_Pause and SUPPORTED_Asym_Pause should not be cleared. If the flags are cleared, pause frames cannot be enabled (even if they are supported by the PHY). Signed-off-by: Niklas Cassel Signed-off-by: Jesper Nilsson Acked-by: Lars Persson Signed-off-by: David S. Miller --- drivers/net/ethernet/synopsys/dwc_eth_qos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c index 0d00531285425..d775729648eff 100644 --- a/drivers/net/ethernet/synopsys/dwc_eth_qos.c +++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c @@ -982,7 +982,8 @@ static int dwceqos_mii_probe(struct net_device *ndev) if (netif_msg_probe(lp)) phy_attached_info(phydev); - phydev->supported &= PHY_GBIT_FEATURES; + phydev->supported &= PHY_GBIT_FEATURES | SUPPORTED_Pause | + SUPPORTED_Asym_Pause; lp->link = 0; lp->speed = 0; -- GitLab From 1826277802d83b47d77e6a3e876aec07777aa271 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 18 Oct 2016 09:20:55 +0200 Subject: [PATCH 0719/1167] dwc_eth_qos: enable flow control by default Allow autoneg to enable flow control by default. The behavior when autoneg is off has not changed. Signed-off-by: Niklas Cassel Signed-off-by: Jesper Nilsson Acked-by: Lars Persson Signed-off-by: David S. Miller --- drivers/net/ethernet/synopsys/dwc_eth_qos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c index d775729648eff..5eedac4950778 100644 --- a/drivers/net/ethernet/synopsys/dwc_eth_qos.c +++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c @@ -988,6 +988,7 @@ static int dwceqos_mii_probe(struct net_device *ndev) lp->link = 0; lp->speed = 0; lp->duplex = DUPLEX_UNKNOWN; + lp->flowcontrol.autoneg = AUTONEG_ENABLE; return 0; } -- GitLab From 7e1670c15c9b18d614b43a674e086eb3e239c8f7 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 18 Oct 2016 09:40:20 +0200 Subject: [PATCH 0720/1167] ipv4: Remove unused but set variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the unused but set variable dev in ip_do_fragment to fix the following GCC warning when building with 'W=1': net/ipv4/ip_output.c: In function ‘ip_do_fragment’: net/ipv4/ip_output.c:541:21: warning: variable ‘dev’ set but not used [-Wunused-but-set-variable] Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 05d105832bdbb..03e7f7310423f 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -538,7 +538,6 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, { struct iphdr *iph; int ptr; - struct net_device *dev; struct sk_buff *skb2; unsigned int mtu, hlen, left, len, ll_rs; int offset; @@ -546,8 +545,6 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, struct rtable *rt = skb_rtable(skb); int err = 0; - dev = rt->dst.dev; - /* for offloaded checksums cleanup checksum before fragmentation */ if (skb->ip_summed == CHECKSUM_PARTIAL && (err = skb_checksum_help(skb))) -- GitLab From a56177e18f2e44499a8bf5bc03dbe896dbec657d Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Tue, 18 Oct 2016 14:21:25 +0530 Subject: [PATCH 0721/1167] cxgb4: Fix number of queue sets corssing the limit Do not let number of offload queue sets to go more than MAX_OFLD_QSETS, which would otherwise crash the driver on machines with cores more than MAX_OFLD_QSETS. Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index f320497368f40..57eb4e1345cb0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4057,7 +4057,7 @@ static void cfg_queues(struct adapter *adap) * capped by the number of available cores. */ if (n10g) { - i = num_online_cpus(); + i = min_t(int, MAX_OFLD_QSETS, num_online_cpus()); s->ofldqsets = roundup(i, adap->params.nports); } else { s->ofldqsets = adap->params.nports; -- GitLab From 7ab488951aa536d52feb3690d204a693edf4f433 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 18 Oct 2016 11:22:54 +0200 Subject: [PATCH 0722/1167] tcp: Remove unused but set variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the unused but set variable icsk in listening_get_next to fix the following GCC warning when building with 'W=1': net/ipv4/tcp_ipv4.c: In function ‘listening_get_next’: net/ipv4/tcp_ipv4.c:1890:31: warning: variable ‘icsk’ set but not used [-Wunused-but-set-variable] Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index bd5e8d10893fb..79d55eb3ec3f1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1887,7 +1887,6 @@ static void *listening_get_next(struct seq_file *seq, void *cur) struct tcp_iter_state *st = seq->private; struct net *net = seq_file_net(seq); struct inet_listen_hashbucket *ilb; - struct inet_connection_sock *icsk; struct sock *sk = cur; if (!sk) { @@ -1909,7 +1908,6 @@ static void *listening_get_next(struct seq_file *seq, void *cur) continue; if (sk->sk_family == st->family) return sk; - icsk = inet_csk(sk); } spin_unlock_bh(&ilb->lock); st->offset = 0; -- GitLab From 6026ed2fe258b61ea5aadd91a95c4f36a6dbe167 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 18 Oct 2016 15:33:11 +0100 Subject: [PATCH 0723/1167] MAINTAINERS: Add myself as EFI maintainer At the request of Matt, I am taking up co-maintainership of the EFI subsystem. So add my name to the EFI section in MAINTAINERS, and change the SCM tree reference to point to the new shared Git repo. Signed-off-by: Ard Biesheuvel Acked-by: Will Deacon Acked-by: Matt Fleming Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/20161018143318.15673-2-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1cd38a7e0064e..6847ba844ef93 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4620,8 +4620,9 @@ F: sound/usb/misc/ua101.c EXTENSIBLE FIRMWARE INTERFACE (EFI) M: Matt Fleming +M: Ard Biesheuvel L: linux-efi@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git S: Maintained F: Documentation/efi-stub.txt F: arch/ia64/kernel/efi.c -- GitLab From d2e4d593516e877f1f6fb40031eb495f36606e16 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Oct 2016 00:05:30 +0200 Subject: [PATCH 0724/1167] netfilter: nf_tables: avoid uninitialized variable warning The newly added nft_range_eval() function handles the two possible nft range operations, but as the compiler warning points out, any unexpected value would lead to the 'mismatch' variable being used without being initialized: net/netfilter/nft_range.c: In function 'nft_range_eval': net/netfilter/nft_range.c:45:5: error: 'mismatch' may be used uninitialized in this function [-Werror=maybe-uninitialized] This removes the variable in question and instead moves the condition into the switch itself, which is potentially more efficient than adding a bogus 'default' clause as in my first approach, and is nicer than using the 'uninitialized_var' macro. Fixes: 0f3cd9b36977 ("netfilter: nf_tables: add range expression") Link: http://patchwork.ozlabs.org/patch/677114/ Signed-off-by: Arnd Bergmann Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_range.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/net/netfilter/nft_range.c b/net/netfilter/nft_range.c index 9bc4586c3006c..fbc88009ca2ef 100644 --- a/net/netfilter/nft_range.c +++ b/net/netfilter/nft_range.c @@ -28,22 +28,20 @@ static void nft_range_eval(const struct nft_expr *expr, const struct nft_pktinfo *pkt) { const struct nft_range_expr *priv = nft_expr_priv(expr); - bool mismatch; int d1, d2; d1 = memcmp(®s->data[priv->sreg], &priv->data_from, priv->len); d2 = memcmp(®s->data[priv->sreg], &priv->data_to, priv->len); switch (priv->op) { case NFT_RANGE_EQ: - mismatch = (d1 < 0 || d2 > 0); + if (d1 < 0 || d2 > 0) + regs->verdict.code = NFT_BREAK; break; case NFT_RANGE_NEQ: - mismatch = (d1 >= 0 && d2 <= 0); + if (d1 >= 0 && d2 <= 0) + regs->verdict.code = NFT_BREAK; break; } - - if (mismatch) - regs->verdict.code = NFT_BREAK; } static const struct nla_policy nft_range_policy[NFTA_RANGE_MAX + 1] = { -- GitLab From d09960b0032174eb493c4c13be5b9c9ef36dc9a7 Mon Sep 17 00:00:00 2001 From: Tahsin Erdogan Date: Mon, 10 Oct 2016 05:35:19 -0700 Subject: [PATCH 0725/1167] dm: free io_barrier after blk_cleanup_queue call dm_old_request_fn() has paths that access md->io_barrier. The party destroying io_barrier should ensure that no future execution of dm_old_request_fn() is possible. Move io_barrier destruction to below blk_cleanup_queue() to ensure this and avoid a NULL pointer crash during request-based DM device shutdown. Cc: stable@vger.kernel.org # 4.3+ Signed-off-by: Tahsin Erdogan Signed-off-by: Mike Snitzer --- drivers/md/dm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index be35258324c11..ec513ee864f26 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1423,8 +1423,6 @@ static void cleanup_mapped_device(struct mapped_device *md) if (md->bs) bioset_free(md->bs); - cleanup_srcu_struct(&md->io_barrier); - if (md->disk) { spin_lock(&_minor_lock); md->disk->private_data = NULL; @@ -1436,6 +1434,8 @@ static void cleanup_mapped_device(struct mapped_device *md) if (md->queue) blk_cleanup_queue(md->queue); + cleanup_srcu_struct(&md->io_barrier); + if (md->bdev) { bdput(md->bdev); md->bdev = NULL; -- GitLab From 7cb3f9214dfa443c1ccc2be637dcc6344cc203f0 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 18 Oct 2016 18:09:48 +0200 Subject: [PATCH 0726/1167] bridge: multicast: restore perm router ports on multicast enable Satish reported a problem with the perm multicast router ports not getting reenabled after some series of events, in particular if it happens that the multicast snooping has been disabled and the port goes to disabled state then it will be deleted from the router port list, but if it moves into non-disabled state it will not be re-added because the mcast snooping is still disabled, and enabling snooping later does nothing. Here are the steps to reproduce, setup br0 with snooping enabled and eth1 added as a perm router (multicast_router = 2): 1. $ echo 0 > /sys/class/net/br0/bridge/multicast_snooping 2. $ ip l set eth1 down ^ This step deletes the interface from the router list 3. $ ip l set eth1 up ^ This step does not add it again because mcast snooping is disabled 4. $ echo 1 > /sys/class/net/br0/bridge/multicast_snooping 5. $ bridge -d -s mdb show At this point we have mcast enabled and eth1 as a perm router (value = 2) but it is not in the router list which is incorrect. After this change: 1. $ echo 0 > /sys/class/net/br0/bridge/multicast_snooping 2. $ ip l set eth1 down ^ This step deletes the interface from the router list 3. $ ip l set eth1 up ^ This step does not add it again because mcast snooping is disabled 4. $ echo 1 > /sys/class/net/br0/bridge/multicast_snooping 5. $ bridge -d -s mdb show router ports on br0: eth1 Note: we can directly do br_multicast_enable_port for all because the querier timer already has checks for the port state and will simply expire if it's in blocking/disabled. See the comment added by commit 9aa66382163e7 ("bridge: multicast: add a comment to br_port_state_selection about blocking state") Fixes: 561f1103a2b7 ("bridge: Add multicast_snooping sysfs toggle") Reported-by: Satish Ashok Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_multicast.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index c5fea9393946f..2136e45f52777 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -972,13 +972,12 @@ static void br_multicast_enable(struct bridge_mcast_own_query *query) mod_timer(&query->timer, jiffies); } -void br_multicast_enable_port(struct net_bridge_port *port) +static void __br_multicast_enable_port(struct net_bridge_port *port) { struct net_bridge *br = port->br; - spin_lock(&br->multicast_lock); if (br->multicast_disabled || !netif_running(br->dev)) - goto out; + return; br_multicast_enable(&port->ip4_own_query); #if IS_ENABLED(CONFIG_IPV6) @@ -987,8 +986,14 @@ void br_multicast_enable_port(struct net_bridge_port *port) if (port->multicast_router == MDB_RTR_TYPE_PERM && hlist_unhashed(&port->rlist)) br_multicast_add_router(br, port); +} -out: +void br_multicast_enable_port(struct net_bridge_port *port) +{ + struct net_bridge *br = port->br; + + spin_lock(&br->multicast_lock); + __br_multicast_enable_port(port); spin_unlock(&br->multicast_lock); } @@ -1994,8 +1999,9 @@ static void br_multicast_start_querier(struct net_bridge *br, int br_multicast_toggle(struct net_bridge *br, unsigned long val) { - int err = 0; struct net_bridge_mdb_htable *mdb; + struct net_bridge_port *port; + int err = 0; spin_lock_bh(&br->multicast_lock); if (br->multicast_disabled == !val) @@ -2023,10 +2029,9 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) goto rollback; } - br_multicast_start_querier(br, &br->ip4_own_query); -#if IS_ENABLED(CONFIG_IPV6) - br_multicast_start_querier(br, &br->ip6_own_query); -#endif + br_multicast_open(br); + list_for_each_entry(port, &br->port_list, list) + __br_multicast_enable_port(port); unlock: spin_unlock_bh(&br->multicast_lock); -- GitLab From 937fa62e8a00d0b4bc2c0a40567d7c88ab2b2e8d Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Tue, 18 Oct 2016 14:02:04 -0400 Subject: [PATCH 0727/1167] dm rq: clear kworker_task if kthread_run() returned an error cleanup_mapped_device() calls kthread_stop() if kworker_task is non-NULL. Currently the assigned value could be a valid task struct or an error code (e.g -ENOMEM). Reset md->kworker_task to NULL if kthread_run() returned an erorr. Fixes: 7193a9defc ("dm rq: check kthread_run return for .request_fn request-based DM") Cc: stable@vger.kernel.org # 4.8 Reported-by: Tahsin Erdogan Signed-off-by: Mike Snitzer --- drivers/md/dm-rq.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index 5eacce1ef88b6..63e43f261cce4 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c @@ -856,8 +856,11 @@ int dm_old_init_request_queue(struct mapped_device *md) init_kthread_worker(&md->kworker); md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker, "kdmwork-%s", dm_device_name(md)); - if (IS_ERR(md->kworker_task)) - return PTR_ERR(md->kworker_task); + if (IS_ERR(md->kworker_task)) { + int error = PTR_ERR(md->kworker_task); + md->kworker_task = NULL; + return error; + } elv_register_queue(md->queue); -- GitLab From 7c6273194445fe1316084d3096f9311c3dfa4da6 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 18 Oct 2016 20:52:28 +0800 Subject: [PATCH 0728/1167] arm64: dts: rockchip: remove the abuse of keep-power-in-suspend It was invented for sdio only, and should not be used for sdmmc or emmc. Remove it. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts | 1 - arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts | 2 -- 2 files changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts index 353314ca74269..e5eeca2c24565 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts @@ -116,7 +116,6 @@ cap-mmc-highspeed; clock-frequency = <150000000>; disable-wp; - keep-power-in-suspend; non-removable; num-slots = <1>; vmmc-supply = <&vcc_io>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts index 13b7f1edad104..ea0a8eceefd46 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts @@ -199,7 +199,6 @@ bus-width = <8>; cap-mmc-highspeed; disable-wp; - keep-power-in-suspend; mmc-pwrseq = <&emmc_pwrseq>; mmc-hs200-1_2v; mmc-hs200-1_8v; @@ -348,7 +347,6 @@ clock-freq-min-max = <400000 50000000>; cap-sd-highspeed; card-detect-delay = <200>; - keep-power-in-suspend; num-slots = <1>; pinctrl-names = "default"; pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; -- GitLab From 9fa2f2cca21b14d17b1c1a37babb639a48a5a29f Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 17 Oct 2016 15:56:29 -0500 Subject: [PATCH 0729/1167] ibmvnic: Driver Version 1.0.1 Increment driver version to reflect features that have been added since release. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index bfc84c7d0e114..878e2c059f5c8 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -27,7 +27,7 @@ /**************************************************************************/ #define IBMVNIC_NAME "ibmvnic" -#define IBMVNIC_DRIVER_VERSION "1.0" +#define IBMVNIC_DRIVER_VERSION "1.0.1" #define IBMVNIC_INVALID_MAP -1 #define IBMVNIC_STATS_TIMEOUT 1 /* basic structures plus 100 2k buffers */ -- GitLab From 12608c260d2fe36746508cb4fa20b6e9a5f9c241 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 17 Oct 2016 15:28:09 -0500 Subject: [PATCH 0730/1167] ibmvnic: Fix GFP_KERNEL allocation in interrupt context Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index bfe17d9c022df..928bf8a5a5676 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1190,7 +1190,7 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter if (!scrq) return NULL; - scrq->msgs = (union sub_crq *)__get_free_pages(GFP_KERNEL, 2); + scrq->msgs = (union sub_crq *)__get_free_pages(GFP_ATOMIC, 2); memset(scrq->msgs, 0, 4 * PAGE_SIZE); if (!scrq->msgs) { dev_warn(dev, "Couldn't allocate crq queue messages page\n"); -- GitLab From 87737f8810db445db171ca81ca4cc43bd5b067ce Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 17 Oct 2016 15:28:10 -0500 Subject: [PATCH 0731/1167] ibmvnic: Update MTU after device initialization It is possible for the MTU to be changed during the initialization process with the VNIC Server. Ensure that the net device is updated to reflect the new MTU. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 928bf8a5a5676..213162df1a9bf 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3654,6 +3654,7 @@ static void handle_crq_init_rsp(struct work_struct *work) goto task_failed; netdev->real_num_tx_queues = adapter->req_tx_queues; + netdev->mtu = adapter->req_mtu; if (adapter->failover) { adapter->failover = false; @@ -3792,6 +3793,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) } netdev->real_num_tx_queues = adapter->req_tx_queues; + netdev->mtu = adapter->req_mtu; rc = register_netdev(netdev); if (rc) { -- GitLab From 41ee9c557ef5de992843b6dac35a199e651525cf Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 17 Oct 2016 14:22:48 -0700 Subject: [PATCH 0732/1167] soreuseport: do not export reuseport_add_sock() reuseport_add_sock() is not used from a module, no need to export it. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock_reuseport.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c index e92b759d906c1..9a1a352fd1ebe 100644 --- a/net/core/sock_reuseport.c +++ b/net/core/sock_reuseport.c @@ -129,7 +129,6 @@ int reuseport_add_sock(struct sock *sk, struct sock *sk2) return 0; } -EXPORT_SYMBOL(reuseport_add_sock); static void reuseport_free_rcu(struct rcu_head *head) { -- GitLab From 4b75ca5a7a9e01dda3ea70bc17b1826fd679af61 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Oct 2016 00:16:08 +0200 Subject: [PATCH 0733/1167] net: bcm63xx: avoid referencing uninitialized variable gcc found a reference to an uninitialized variable in the error handling of bcm_enet_open, introduced by a recent cleanup: drivers/net/ethernet/broadcom/bcm63xx_enet.c: In function 'bcm_enet_open' drivers/net/ethernet/broadcom/bcm63xx_enet.c:1129:2: warning: 'phydev' may be used uninitialized in this function [-Wmaybe-uninitialized] This makes the use of that variable conditional, so we only reference it here after it has been used before. Unlike my normal patches, I have not build-tested this one, as I don't currently have mips test in my randconfig setup. Fixes: 625eb8667d6f ("net: ethernet: broadcom: bcm63xx: use phydev from struct net_device") Cc: Philippe Reynes Reported-by: kbuild test robot Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index ae364c74baf3f..537090952c454 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -1126,7 +1126,8 @@ static int bcm_enet_open(struct net_device *dev) free_irq(dev->irq, dev); out_phy_disconnect: - phy_disconnect(phydev); + if (priv->has_phy) + phy_disconnect(phydev); return ret; } -- GitLab From 52ccd6318481a467d8ad54ea40f60c61e957d58f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Oct 2016 00:16:09 +0200 Subject: [PATCH 0734/1167] net/hyperv: avoid uninitialized variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hdr_offset variable is only if we deal with a TCP or UDP packet, but as the check surrounding its usage tests for skb_is_gso() instead, the compiler has no idea if the variable is initialized or not at that point: drivers/net/hyperv/netvsc_drv.c: In function ‘netvsc_start_xmit’: drivers/net/hyperv/netvsc_drv.c:494:42: error: ‘hdr_offset’ may be used uninitialized in this function [-Werror=maybe-uninitialized] This adds an additional check for the transport type, which tells the compiler that this path cannot happen. Since the get_net_transport_info() function should always be inlined here, I don't expect this to result in additional runtime checks. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index f0919bd3a5632..5d6e75a40d383 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -447,7 +447,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) * Setup the sendside checksum offload only if this is not a * GSO packet. */ - if (skb_is_gso(skb)) { + if ((net_trans_info & (INFO_TCP | INFO_UDP)) && skb_is_gso(skb)) { struct ndis_tcp_lso_info *lso_info; rndis_msg_size += NDIS_LSO_PPI_SIZE; -- GitLab From ecf244f753e09486707843f2b7b1874f33027038 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Oct 2016 00:16:15 +0200 Subject: [PATCH 0735/1167] rocker: fix maybe-uninitialized warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In some rare configurations, we get a warning about the 'index' variable being used without an initialization: drivers/net/ethernet/rocker/rocker_ofdpa.c: In function ‘ofdpa_port_fib_ipv4.isra.16.constprop’: drivers/net/ethernet/rocker/rocker_ofdpa.c:2425:92: warning: ‘index’ may be used uninitialized in this function [-Wmaybe-uninitialized] This is a false positive, the logic is just a bit too complex for gcc to follow here. Moving the intialization of 'index' a little further down makes it clear to gcc that the function always returns an error if it is not initialized. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker_ofdpa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 431a608042727..4ca461322d608 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -1493,8 +1493,6 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, spin_lock_irqsave(&ofdpa->neigh_tbl_lock, lock_flags); found = ofdpa_neigh_tbl_find(ofdpa, ip_addr); - if (found) - *index = found->index; updating = found && adding; removing = found && !adding; @@ -1508,9 +1506,11 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, resolved = false; } else if (removing) { ofdpa_neigh_del(trans, found); + *index = found->index; } else if (updating) { ofdpa_neigh_update(found, trans, NULL, false); resolved = !is_zero_ether_addr(found->eth_dst); + *index = found->index; } else { err = -ENOENT; } -- GitLab From b4f0fd4baa90ecce798e0d26d1cce8f4457f2028 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 15:17:51 +0000 Subject: [PATCH 0736/1167] qed: Use list_move_tail instead of list_del/list_add_tail Using list_move_tail() instead of list_del() + list_add_tail(). Signed-off-by: Wei Yongjun Acked-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index ce171a80bdafa..63e1a1b0ef8ef 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -538,8 +538,7 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) if (!p_pkt) break; - list_del(&p_pkt->list_entry); - list_add_tail(&p_pkt->list_entry, &p_rx->free_descq); + list_move_tail(&p_pkt->list_entry, &p_rx->free_descq); rx_buf_addr = p_pkt->rx_buf_addr; cookie = p_pkt->cookie; @@ -993,9 +992,8 @@ static void qed_ll2_post_rx_buffer_notify_fw(struct qed_hwfn *p_hwfn, p_posting_packet = list_first_entry(&p_rx->posting_descq, struct qed_ll2_rx_packet, list_entry); - list_del(&p_posting_packet->list_entry); - list_add_tail(&p_posting_packet->list_entry, - &p_rx->active_descq); + list_move_tail(&p_posting_packet->list_entry, + &p_rx->active_descq); b_notify_fw = true; } @@ -1186,8 +1184,7 @@ static void qed_ll2_tx_packet_notify(struct qed_hwfn *p_hwfn, if (!p_pkt) break; - list_del(&p_pkt->list_entry); - list_add_tail(&p_pkt->list_entry, &p_tx->active_descq); + list_move_tail(&p_pkt->list_entry, &p_tx->active_descq); } SET_FIELD(db_msg.params, CORE_DB_DATA_DEST, DB_DEST_XCM); -- GitLab From 19be0eaffa3ac7d8eb6784ad9bdbc7d67ed8e619 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 13 Oct 2016 13:07:36 -0700 Subject: [PATCH 0737/1167] mm: remove gup_flags FOLL_WRITE games from __get_user_pages() This is an ancient bug that was actually attempted to be fixed once (badly) by me eleven years ago in commit 4ceb5db9757a ("Fix get_user_pages() race for write access") but that was then undone due to problems on s390 by commit f33ea7f404e5 ("fix get_user_pages bug"). In the meantime, the s390 situation has long been fixed, and we can now fix it by checking the pte_dirty() bit properly (and do it better). The s390 dirty bit was implemented in abf09bed3cce ("s390/mm: implement software dirty bits") which made it into v3.9. Earlier kernels will have to look at the page state itself. Also, the VM has become more scalable, and what used a purely theoretical race back then has become easier to trigger. To fix it, we introduce a new internal FOLL_COW flag to mark the "yes, we already did a COW" rather than play racy games with FOLL_WRITE that is very fundamental, and then use the pte dirty flag to validate that the FOLL_COW flag is still valid. Reported-and-tested-by: Phil "not Paul" Oester Acked-by: Hugh Dickins Reviewed-by: Michal Hocko Cc: Andy Lutomirski Cc: Kees Cook Cc: Oleg Nesterov Cc: Willy Tarreau Cc: Nick Piggin Cc: Greg Thelen Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds --- include/linux/mm.h | 1 + mm/gup.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index e9caec6a51e97..ed85879f47f5f 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2232,6 +2232,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma, #define FOLL_TRIED 0x800 /* a retry, previous pass started an IO */ #define FOLL_MLOCK 0x1000 /* lock present pages */ #define FOLL_REMOTE 0x2000 /* we are working on non-current tsk/mm */ +#define FOLL_COW 0x4000 /* internal GUP flag */ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, void *data); diff --git a/mm/gup.c b/mm/gup.c index 96b2b2fd0fbd1..22cc22e7432f6 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -60,6 +60,16 @@ static int follow_pfn_pte(struct vm_area_struct *vma, unsigned long address, return -EEXIST; } +/* + * FOLL_FORCE can write to even unwritable pte's, but only + * after we've gone through a COW cycle and they are dirty. + */ +static inline bool can_follow_write_pte(pte_t pte, unsigned int flags) +{ + return pte_write(pte) || + ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte)); +} + static struct page *follow_page_pte(struct vm_area_struct *vma, unsigned long address, pmd_t *pmd, unsigned int flags) { @@ -95,7 +105,7 @@ static struct page *follow_page_pte(struct vm_area_struct *vma, } if ((flags & FOLL_NUMA) && pte_protnone(pte)) goto no_page; - if ((flags & FOLL_WRITE) && !pte_write(pte)) { + if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) { pte_unmap_unlock(ptep, ptl); return NULL; } @@ -412,7 +422,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma, * reCOWed by userspace write). */ if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE)) - *flags &= ~FOLL_WRITE; + *flags |= FOLL_COW; return 0; } -- GitLab From 859110d7497cdd0e6b21010d6f777049d676382c Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Thu, 13 Oct 2016 01:20:11 +0100 Subject: [PATCH 0738/1167] mm: remove write/force parameters from __get_user_pages_locked() This removes the redundant 'write' and 'force' parameters from __get_user_pages_locked() to make the use of FOLL_FORCE explicit in callers as use of this flag can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes Reviewed-by: Jan Kara Acked-by: Michal Hocko Signed-off-by: Linus Torvalds --- mm/gup.c | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index 22cc22e7432f6..720eb93852043 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -739,7 +739,6 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, struct vm_area_struct **vmas, int *locked, bool notify_drop, @@ -757,10 +756,6 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk, if (pages) flags |= FOLL_GET; - if (write) - flags |= FOLL_WRITE; - if (force) - flags |= FOLL_FORCE; pages_done = 0; lock_dropped = false; @@ -856,9 +851,15 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages, int *locked) { + unsigned int flags = FOLL_TOUCH; + + if (write) + flags |= FOLL_WRITE; + if (force) + flags |= FOLL_FORCE; + return __get_user_pages_locked(current, current->mm, start, nr_pages, - write, force, pages, NULL, locked, true, - FOLL_TOUCH); + pages, NULL, locked, true, flags); } EXPORT_SYMBOL(get_user_pages_locked); @@ -879,9 +880,15 @@ __always_inline long __get_user_pages_unlocked(struct task_struct *tsk, struct m { long ret; int locked = 1; + + if (write) + gup_flags |= FOLL_WRITE; + if (force) + gup_flags |= FOLL_FORCE; + down_read(&mm->mmap_sem); - ret = __get_user_pages_locked(tsk, mm, start, nr_pages, write, force, - pages, NULL, &locked, false, gup_flags); + ret = __get_user_pages_locked(tsk, mm, start, nr_pages, pages, NULL, + &locked, false, gup_flags); if (locked) up_read(&mm->mmap_sem); return ret; @@ -973,9 +980,15 @@ long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, int write, int force, struct page **pages, struct vm_area_struct **vmas) { - return __get_user_pages_locked(tsk, mm, start, nr_pages, write, force, - pages, vmas, NULL, false, - FOLL_TOUCH | FOLL_REMOTE); + unsigned int flags = FOLL_TOUCH | FOLL_REMOTE; + + if (write) + flags |= FOLL_WRITE; + if (force) + flags |= FOLL_FORCE; + + return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas, + NULL, false, flags); } EXPORT_SYMBOL(get_user_pages_remote); @@ -989,9 +1002,15 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages, struct vm_area_struct **vmas) { + unsigned int flags = FOLL_TOUCH; + + if (write) + flags |= FOLL_WRITE; + if (force) + flags |= FOLL_FORCE; + return __get_user_pages_locked(current, current->mm, start, nr_pages, - write, force, pages, vmas, NULL, false, - FOLL_TOUCH); + pages, vmas, NULL, false, flags); } EXPORT_SYMBOL(get_user_pages); -- GitLab From d4944b0ecec0af882483fe44b66729316e575208 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Thu, 13 Oct 2016 01:20:12 +0100 Subject: [PATCH 0739/1167] mm: remove write/force parameters from __get_user_pages_unlocked() This removes the redundant 'write' and 'force' parameters from __get_user_pages_unlocked() to make the use of FOLL_FORCE explicit in callers as use of this flag can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes Acked-by: Paolo Bonzini Reviewed-by: Jan Kara Acked-by: Michal Hocko Signed-off-by: Linus Torvalds --- include/linux/mm.h | 3 +-- mm/gup.c | 17 +++++++++-------- mm/nommu.c | 12 +++++++++--- mm/process_vm_access.c | 7 +++++-- virt/kvm/async_pf.c | 3 ++- virt/kvm/kvm_main.c | 11 ++++++++--- 6 files changed, 34 insertions(+), 19 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index ed85879f47f5f..bcdea1f4e98ce 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1285,8 +1285,7 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages, int *locked); long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, - unsigned int gup_flags); + struct page **pages, unsigned int gup_flags); long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages); int get_user_pages_fast(unsigned long start, int nr_pages, int write, diff --git a/mm/gup.c b/mm/gup.c index 720eb93852043..e997f545b059e 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -875,17 +875,11 @@ EXPORT_SYMBOL(get_user_pages_locked); */ __always_inline long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, - unsigned int gup_flags) + struct page **pages, unsigned int gup_flags) { long ret; int locked = 1; - if (write) - gup_flags |= FOLL_WRITE; - if (force) - gup_flags |= FOLL_FORCE; - down_read(&mm->mmap_sem); ret = __get_user_pages_locked(tsk, mm, start, nr_pages, pages, NULL, &locked, false, gup_flags); @@ -915,8 +909,15 @@ EXPORT_SYMBOL(__get_user_pages_unlocked); long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages) { + unsigned int flags = FOLL_TOUCH; + + if (write) + flags |= FOLL_WRITE; + if (force) + flags |= FOLL_FORCE; + return __get_user_pages_unlocked(current, current->mm, start, nr_pages, - write, force, pages, FOLL_TOUCH); + pages, flags); } EXPORT_SYMBOL(get_user_pages_unlocked); diff --git a/mm/nommu.c b/mm/nommu.c index 95daf81a4855d..925dcc1fa2f3e 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -185,8 +185,7 @@ EXPORT_SYMBOL(get_user_pages_locked); long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, - unsigned int gup_flags) + struct page **pages, unsigned int gup_flags) { long ret; down_read(&mm->mmap_sem); @@ -200,8 +199,15 @@ EXPORT_SYMBOL(__get_user_pages_unlocked); long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages) { + unsigned int flags = 0; + + if (write) + flags |= FOLL_WRITE; + if (force) + flags |= FOLL_FORCE; + return __get_user_pages_unlocked(current, current->mm, start, nr_pages, - write, force, pages, 0); + pages, flags); } EXPORT_SYMBOL(get_user_pages_unlocked); diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c index 07514d41ebcc1..be8dc8d1edb95 100644 --- a/mm/process_vm_access.c +++ b/mm/process_vm_access.c @@ -88,12 +88,16 @@ static int process_vm_rw_single_vec(unsigned long addr, ssize_t rc = 0; unsigned long max_pages_per_loop = PVM_MAX_KMALLOC_PAGES / sizeof(struct pages *); + unsigned int flags = FOLL_REMOTE; /* Work out address and page range required */ if (len == 0) return 0; nr_pages = (addr + len - 1) / PAGE_SIZE - addr / PAGE_SIZE + 1; + if (vm_write) + flags |= FOLL_WRITE; + while (!rc && nr_pages && iov_iter_count(iter)) { int pages = min(nr_pages, max_pages_per_loop); size_t bytes; @@ -104,8 +108,7 @@ static int process_vm_rw_single_vec(unsigned long addr, * current/current->mm */ pages = __get_user_pages_unlocked(task, mm, pa, pages, - vm_write, 0, process_pages, - FOLL_REMOTE); + process_pages, flags); if (pages <= 0) return -EFAULT; diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index db9668869f6ff..8035cc1eb9551 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -84,7 +84,8 @@ static void async_pf_execute(struct work_struct *work) * mm and might be done in another context, so we must * use FOLL_REMOTE. */ - __get_user_pages_unlocked(NULL, mm, addr, 1, 1, 0, NULL, FOLL_REMOTE); + __get_user_pages_unlocked(NULL, mm, addr, 1, NULL, + FOLL_WRITE | FOLL_REMOTE); kvm_async_page_present_sync(vcpu, apf); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 81dfc73d3df39..28510e72618a0 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1416,10 +1416,15 @@ static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault, down_read(¤t->mm->mmap_sem); npages = get_user_page_nowait(addr, write_fault, page); up_read(¤t->mm->mmap_sem); - } else + } else { + unsigned int flags = FOLL_TOUCH | FOLL_HWPOISON; + + if (write_fault) + flags |= FOLL_WRITE; + npages = __get_user_pages_unlocked(current, current->mm, addr, 1, - write_fault, 0, page, - FOLL_TOUCH|FOLL_HWPOISON); + page, flags); + } if (npages != 1) return npages; -- GitLab From c164154f66f0c9b02673f07aa4f044f1d9c70274 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Thu, 13 Oct 2016 01:20:13 +0100 Subject: [PATCH 0740/1167] mm: replace get_user_pages_unlocked() write/force parameters with gup_flags This removes the 'write' and 'force' use from get_user_pages_unlocked() and replaces them with 'gup_flags' to make the use of FOLL_FORCE explicit in callers as use of this flag can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes Reviewed-by: Jan Kara Acked-by: Michal Hocko Signed-off-by: Linus Torvalds --- arch/mips/mm/gup.c | 2 +- arch/s390/mm/gup.c | 3 ++- arch/sh/mm/gup.c | 3 ++- arch/sparc/mm/gup.c | 3 ++- arch/x86/mm/gup.c | 2 +- drivers/media/pci/ivtv/ivtv-udma.c | 4 ++-- drivers/media/pci/ivtv/ivtv-yuv.c | 5 +++-- drivers/scsi/st.c | 5 ++--- drivers/video/fbdev/pvr2fb.c | 4 ++-- include/linux/mm.h | 2 +- mm/gup.c | 14 ++++---------- mm/nommu.c | 11 ++--------- mm/util.c | 3 ++- net/ceph/pagevec.c | 2 +- 14 files changed, 27 insertions(+), 36 deletions(-) diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c index 42d124fb64744..d8c3c159289a2 100644 --- a/arch/mips/mm/gup.c +++ b/arch/mips/mm/gup.c @@ -287,7 +287,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, pages += nr; ret = get_user_pages_unlocked(start, (end - start) >> PAGE_SHIFT, - write, 0, pages); + pages, write ? FOLL_WRITE : 0); /* Have to be a bit careful with return values */ if (nr > 0) { diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index adb0c34bf431e..18d4107e10eef 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c @@ -266,7 +266,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, /* Try to get the remaining pages with get_user_pages */ start += nr << PAGE_SHIFT; pages += nr; - ret = get_user_pages_unlocked(start, nr_pages - nr, write, 0, pages); + ret = get_user_pages_unlocked(start, nr_pages - nr, pages, + write ? FOLL_WRITE : 0); /* Have to be a bit careful with return values */ if (nr > 0) ret = (ret < 0) ? nr : ret + nr; diff --git a/arch/sh/mm/gup.c b/arch/sh/mm/gup.c index 40fa6c8adc43a..063c298ba56cc 100644 --- a/arch/sh/mm/gup.c +++ b/arch/sh/mm/gup.c @@ -258,7 +258,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, pages += nr; ret = get_user_pages_unlocked(start, - (end - start) >> PAGE_SHIFT, write, 0, pages); + (end - start) >> PAGE_SHIFT, pages, + write ? FOLL_WRITE : 0); /* Have to be a bit careful with return values */ if (nr > 0) { diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c index 4e06750a5d295..cd0e32bbcb1de 100644 --- a/arch/sparc/mm/gup.c +++ b/arch/sparc/mm/gup.c @@ -238,7 +238,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, pages += nr; ret = get_user_pages_unlocked(start, - (end - start) >> PAGE_SHIFT, write, 0, pages); + (end - start) >> PAGE_SHIFT, pages, + write ? FOLL_WRITE : 0); /* Have to be a bit careful with return values */ if (nr > 0) { diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index b8b6a60b32cf4..0d4fb3ebbbac9 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c @@ -435,7 +435,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, ret = get_user_pages_unlocked(start, (end - start) >> PAGE_SHIFT, - write, 0, pages); + pages, write ? FOLL_WRITE : 0); /* Have to be a bit careful with return values */ if (nr > 0) { diff --git a/drivers/media/pci/ivtv/ivtv-udma.c b/drivers/media/pci/ivtv/ivtv-udma.c index 4769469fe8429..2c9232ef7baa4 100644 --- a/drivers/media/pci/ivtv/ivtv-udma.c +++ b/drivers/media/pci/ivtv/ivtv-udma.c @@ -124,8 +124,8 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, } /* Get user pages for DMA Xfer */ - err = get_user_pages_unlocked(user_dma.uaddr, user_dma.page_count, 0, - 1, dma->map); + err = get_user_pages_unlocked(user_dma.uaddr, user_dma.page_count, + dma->map, FOLL_FORCE); if (user_dma.page_count != err) { IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c index b094054cda6e5..f7299d3d82449 100644 --- a/drivers/media/pci/ivtv/ivtv-yuv.c +++ b/drivers/media/pci/ivtv/ivtv-yuv.c @@ -76,11 +76,12 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, /* Get user pages for DMA Xfer */ y_pages = get_user_pages_unlocked(y_dma.uaddr, - y_dma.page_count, 0, 1, &dma->map[0]); + y_dma.page_count, &dma->map[0], FOLL_FORCE); uv_pages = 0; /* silence gcc. value is set and consumed only if: */ if (y_pages == y_dma.page_count) { uv_pages = get_user_pages_unlocked(uv_dma.uaddr, - uv_dma.page_count, 0, 1, &dma->map[y_pages]); + uv_dma.page_count, &dma->map[y_pages], + FOLL_FORCE); } if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) { diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 7af5226aa55ba..618422ea3a412 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4922,9 +4922,8 @@ static int sgl_map_user_pages(struct st_buffer *STbp, res = get_user_pages_unlocked( uaddr, nr_pages, - rw == READ, - 0, /* don't force */ - pages); + pages, + rw == READ ? FOLL_WRITE : 0); /* don't force */ /* Errors and no page mapped should return here */ if (res < nr_pages) diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c index 3b1ca44110737..a2564ab91e62d 100644 --- a/drivers/video/fbdev/pvr2fb.c +++ b/drivers/video/fbdev/pvr2fb.c @@ -686,8 +686,8 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, if (!pages) return -ENOMEM; - ret = get_user_pages_unlocked((unsigned long)buf, nr_pages, WRITE, - 0, pages); + ret = get_user_pages_unlocked((unsigned long)buf, nr_pages, pages, + FOLL_WRITE); if (ret < nr_pages) { nr_pages = ret; diff --git a/include/linux/mm.h b/include/linux/mm.h index bcdea1f4e98ce..abd53f2eb74ea 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1287,7 +1287,7 @@ long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, struct page **pages, unsigned int gup_flags); long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages); + struct page **pages, unsigned int gup_flags); int get_user_pages_fast(unsigned long start, int nr_pages, int write, struct page **pages); diff --git a/mm/gup.c b/mm/gup.c index e997f545b059e..373d1ec006e4f 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -907,17 +907,10 @@ EXPORT_SYMBOL(__get_user_pages_unlocked); * "force" parameter). */ long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages) + struct page **pages, unsigned int gup_flags) { - unsigned int flags = FOLL_TOUCH; - - if (write) - flags |= FOLL_WRITE; - if (force) - flags |= FOLL_FORCE; - return __get_user_pages_unlocked(current, current->mm, start, nr_pages, - pages, flags); + pages, gup_flags | FOLL_TOUCH); } EXPORT_SYMBOL(get_user_pages_unlocked); @@ -1535,7 +1528,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, start += nr << PAGE_SHIFT; pages += nr; - ret = get_user_pages_unlocked(start, nr_pages - nr, write, 0, pages); + ret = get_user_pages_unlocked(start, nr_pages - nr, pages, + write ? FOLL_WRITE : 0); /* Have to be a bit careful with return values */ if (nr > 0) { diff --git a/mm/nommu.c b/mm/nommu.c index 925dcc1fa2f3e..7e27add39f7ef 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -197,17 +197,10 @@ long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, EXPORT_SYMBOL(__get_user_pages_unlocked); long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages) + struct page **pages, unsigned int gup_flags) { - unsigned int flags = 0; - - if (write) - flags |= FOLL_WRITE; - if (force) - flags |= FOLL_FORCE; - return __get_user_pages_unlocked(current, current->mm, start, nr_pages, - pages, flags); + pages, gup_flags); } EXPORT_SYMBOL(get_user_pages_unlocked); diff --git a/mm/util.c b/mm/util.c index 662cddf914af2..4c685bde5ebc0 100644 --- a/mm/util.c +++ b/mm/util.c @@ -283,7 +283,8 @@ EXPORT_SYMBOL_GPL(__get_user_pages_fast); int __weak get_user_pages_fast(unsigned long start, int nr_pages, int write, struct page **pages) { - return get_user_pages_unlocked(start, nr_pages, write, 0, pages); + return get_user_pages_unlocked(start, nr_pages, pages, + write ? FOLL_WRITE : 0); } EXPORT_SYMBOL_GPL(get_user_pages_fast); diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c index 00d2601407c5d..1a7c9a79a53c2 100644 --- a/net/ceph/pagevec.c +++ b/net/ceph/pagevec.c @@ -26,7 +26,7 @@ struct page **ceph_get_direct_page_vector(const void __user *data, while (got < num_pages) { rc = get_user_pages_unlocked( (unsigned long)data + ((unsigned long)got * PAGE_SIZE), - num_pages - got, write_page, 0, pages + got); + num_pages - got, pages + got, write_page ? FOLL_WRITE : 0); if (rc < 0) break; BUG_ON(rc == 0); -- GitLab From db766b0a25c9520b7c585bcdb2725dcc0e490f4a Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 13 Oct 2016 15:51:47 -0400 Subject: [PATCH 0741/1167] sh: add Kconfig option for J-Core SoC core drivers Signed-off-by: Rich Felker --- arch/sh/boards/Kconfig | 10 ++++++++++ arch/sh/configs/j2_defconfig | 1 + 2 files changed, 11 insertions(+) diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index e9c2c42031fee..4e21949593cf5 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig @@ -22,6 +22,16 @@ config SH_DEVICE_TREE have sufficient driver coverage to use this option; do not select it if you are using original SuperH hardware. +config SH_JCORE_SOC + bool "J-Core SoC" + depends on SH_DEVICE_TREE && (CPU_SH2 || CPU_J2) + select CLKSRC_JCORE_PIT + select JCORE_AIC + default y if CPU_J2 + help + Select this option to include drivers core components of the + J-Core SoC, including interrupt controllers and timers. + config SH_SOLUTION_ENGINE bool "SolutionEngine" select SOLUTION_ENGINE diff --git a/arch/sh/configs/j2_defconfig b/arch/sh/configs/j2_defconfig index 94d1eca52f723..530e66e163aaa 100644 --- a/arch/sh/configs/j2_defconfig +++ b/arch/sh/configs/j2_defconfig @@ -8,6 +8,7 @@ CONFIG_MEMORY_START=0x10000000 CONFIG_MEMORY_SIZE=0x04000000 CONFIG_CPU_BIG_ENDIAN=y CONFIG_SH_DEVICE_TREE=y +CONFIG_SH_JCORE_SOC=y CONFIG_HZ_100=y CONFIG_CMDLINE_OVERWRITE=y CONFIG_CMDLINE="console=ttyUL0 earlycon" -- GitLab From 99f453f875a5e207f38e92ced6ce3427433d5be2 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Tue, 18 Oct 2016 18:54:56 -0400 Subject: [PATCH 0742/1167] sh: add earlycon support to j2_defconfig Signed-off-by: Rich Felker --- arch/sh/configs/j2_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/sh/configs/j2_defconfig b/arch/sh/configs/j2_defconfig index 530e66e163aaa..2eb81ebe3888b 100644 --- a/arch/sh/configs/j2_defconfig +++ b/arch/sh/configs/j2_defconfig @@ -21,6 +21,7 @@ CONFIG_INET=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_NETDEVICES=y +CONFIG_SERIAL_EARLYCON=y CONFIG_SERIAL_UARTLITE=y CONFIG_SERIAL_UARTLITE_CONSOLE=y CONFIG_I2C=y -- GitLab From d852b5f35e84e60c930589eeb14a6df21ea9b1cb Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 19 Oct 2016 00:24:27 +0100 Subject: [PATCH 0743/1167] KVM: MIPS: Add missing uaccess.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MIPS KVM uses user memory accessors but mips.c doesn't directly include uaccess.h, so include it now. This wasn't too much of a problem before v4.9-rc1 as asm/module.h included asm/uaccess.h, however since commit 29abfbd9cbba ("mips: separate extable.h, switch module.h to it") this is no longer the case. This resulted in build failures when trace points were disabled, as trace/define_trace.h includes trace/trace_events.h only ifdef TRACEPOINTS_ENABLED, which goes on to include asm/uaccess.h via a couple of other headers. Fixes: 29abfbd9cbba ("mips: separate extable.h, switch module.h to it") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim Krčmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org --- arch/mips/kvm/mips.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index ce961495b5e12..622037d851a35 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include -- GitLab From 6d4952d9d9d4dc2bb9c0255d95a09405a1e958f7 Mon Sep 17 00:00:00 2001 From: Andrew Lutomirski Date: Mon, 17 Oct 2016 10:06:27 -0700 Subject: [PATCH 0744/1167] hwrng: core - Don't use a stack buffer in add_early_randomness() hw_random carefully avoids using a stack buffer except in add_early_randomness(). This causes a crash in virtio_rng if CONFIG_VMAP_STACK=y. Reported-by: Matt Mullins Tested-by: Matt Mullins Fixes: d3cc7996473a ("hwrng: fetch randomness only after device init") Signed-off-by: Andy Lutomirski Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 482794526e8cd..d2d2c89de5b44 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -84,14 +84,14 @@ static size_t rng_buffer_size(void) static void add_early_randomness(struct hwrng *rng) { - unsigned char bytes[16]; int bytes_read; + size_t size = min_t(size_t, 16, rng_buffer_size()); mutex_lock(&reading_mutex); - bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1); + bytes_read = rng_get_data(rng, rng_buffer, size, 1); mutex_unlock(&reading_mutex); if (bytes_read > 0) - add_device_randomness(bytes, bytes_read); + add_device_randomness(rng_buffer, bytes_read); } static inline void cleanup_rng(struct kref *kref) -- GitLab From d2cf909cda5f8c5609cb7ed6cda816c3e15528c7 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Fri, 17 Jun 2016 18:53:28 +0200 Subject: [PATCH 0745/1167] powerpc/mm: Prevent unlikely crash in copro_calculate_slb() If a cxl adapter faults on an invalid address for a kernel context, we may enter copro_calculate_slb() with a NULL mm pointer (kernel context) and an effective address which looks like a user address. Which will cause a crash when dereferencing mm. It is clearly an AFU bug, but there's no reason to crash either. So return an error, so that cxl can ack the interrupt with an address error. Fixes: 73d16a6e0e51 ("powerpc/cell: Move data segment faulting code out of cell platform") Cc: stable@vger.kernel.org # v3.18+ Signed-off-by: Frederic Barrat Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- arch/powerpc/mm/copro_fault.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/mm/copro_fault.c b/arch/powerpc/mm/copro_fault.c index bb0354222b115..362954f98029b 100644 --- a/arch/powerpc/mm/copro_fault.c +++ b/arch/powerpc/mm/copro_fault.c @@ -106,6 +106,8 @@ int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb) switch (REGION_ID(ea)) { case USER_REGION_ID: pr_devel("%s: 0x%llx -- USER_REGION_ID\n", __func__, ea); + if (mm == NULL) + return 1; psize = get_slice_psize(mm, ea); ssize = user_segment_size(ea); vsid = get_vsid(mm->context.id, ea, ssize); -- GitLab From 65bc3ece84ef6340cbd80eec10ab9be3426e1149 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 12 Oct 2016 21:00:43 +0200 Subject: [PATCH 0746/1167] powerpc/boot: Fix boot on systems with uncompressed kernel image This commit broke boot on systems with an uncompressed kernel image, namely systems using a cuImage. On such systems the compressed boot image (boot wrapper, uncompressed kernel image, ..) is decompressed by u-boot already, therefore the boot wrapper code sees an uncompressed kernel image. The old decompression code silently assumed an uncompressed kernel image if it found no valid gzip signature, whilst the new code bailed out in this case. Fix this by re-introducing such a fallback if no valid compressed image is found. Fixes: 1b7898ee276b ("Use the pre-boot decompression API") Signed-off-by: Heiner Kallweit Signed-off-by: Michael Ellerman --- arch/powerpc/boot/main.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c index f7a184b6c35b4..57d42d1290335 100644 --- a/arch/powerpc/boot/main.c +++ b/arch/powerpc/boot/main.c @@ -32,9 +32,16 @@ static struct addr_range prep_kernel(void) void *addr = 0; struct elf_info ei; long len; + int uncompressed_image = 0; - partial_decompress(vmlinuz_addr, vmlinuz_size, + len = partial_decompress(vmlinuz_addr, vmlinuz_size, elfheader, sizeof(elfheader), 0); + /* assume uncompressed data if -1 is returned */ + if (len == -1) { + uncompressed_image = 1; + memcpy(elfheader, vmlinuz_addr, sizeof(elfheader)); + printf("No valid compressed data found, assume uncompressed data\n\r"); + } if (!parse_elf64(elfheader, &ei) && !parse_elf32(elfheader, &ei)) fatal("Error: not a valid PPC32 or PPC64 ELF file!\n\r"); @@ -67,6 +74,13 @@ static struct addr_range prep_kernel(void) "device tree\n\r"); } + if (uncompressed_image) { + memcpy(addr, vmlinuz_addr + ei.elfoffset, ei.loadsize); + printf("0x%lx bytes of uncompressed data copied\n\r", + ei.loadsize); + goto out; + } + /* Finally, decompress the kernel */ printf("Decompressing (0x%p <- 0x%p:0x%p)...\n\r", addr, vmlinuz_addr, vmlinuz_addr+vmlinuz_size); @@ -82,7 +96,7 @@ static struct addr_range prep_kernel(void) len, ei.loadsize); printf("Done! Decompressed 0x%lx bytes\n\r", len); - +out: flush_cache(addr, ei.loadsize); return (struct addr_range){addr, ei.memsize}; -- GitLab From 70b565bbdb911023373e035225ab10077e4ab937 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Fri, 14 Oct 2016 15:08:36 +0530 Subject: [PATCH 0747/1167] cxl: Prevent adapter reset if an active context exists This patch prevents resetting the cxl adapter via sysfs in presence of one or more active cxl_context on it. This protects against an unrecoverable error caused by PSL owning a dirty cache line even after reset and host tries to touch the same cache line. In case a force reset of the card is required irrespective of any active contexts, the int value -1 can be stored in the 'reset' sysfs attribute of the card. The patch introduces a new atomic_t member named contexts_num inside struct cxl that holds the number of active context attached to the card , which is checked against '0' before proceeding with the reset. To prevent against a race condition where a context is activated just after reset check is performed, the contexts_num is atomically set to '-1' after reset-check to indicate that no more contexts can be activated on the card anymore. Before activating a context we atomically test if contexts_num is non-negative and if so, increment its value by one. In case the value of contexts_num is negative then it indicates that the card is about to be reset and context activation is error-ed out at that point. Fixes: 62fa19d4b4fd ("cxl: Add ability to reset the card") Cc: stable@vger.kernel.org # v4.0+ Acked-by: Frederic Barrat Reviewed-by: Andrew Donnellan Signed-off-by: Vaibhav Jain Signed-off-by: Michael Ellerman --- Documentation/ABI/testing/sysfs-class-cxl | 7 ++-- drivers/misc/cxl/api.c | 9 +++++ drivers/misc/cxl/context.c | 3 ++ drivers/misc/cxl/cxl.h | 24 +++++++++++++ drivers/misc/cxl/file.c | 11 ++++++ drivers/misc/cxl/guest.c | 3 ++ drivers/misc/cxl/main.c | 42 ++++++++++++++++++++++- drivers/misc/cxl/pci.c | 2 ++ drivers/misc/cxl/sysfs.c | 27 ++++++++++++--- 9 files changed, 121 insertions(+), 7 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-cxl b/Documentation/ABI/testing/sysfs-class-cxl index 4ba0a2a619262..640f65e79ef1c 100644 --- a/Documentation/ABI/testing/sysfs-class-cxl +++ b/Documentation/ABI/testing/sysfs-class-cxl @@ -220,8 +220,11 @@ What: /sys/class/cxl//reset Date: October 2014 Contact: linuxppc-dev@lists.ozlabs.org Description: write only - Writing 1 will issue a PERST to card which may cause the card - to reload the FPGA depending on load_image_on_perst. + Writing 1 will issue a PERST to card provided there are no + contexts active on any one of the card AFUs. This may cause + the card to reload the FPGA depending on load_image_on_perst. + Writing -1 will do a force PERST irrespective of any active + contexts on the card AFUs. Users: https://github.com/ibm-capi/libcxl What: /sys/class/cxl//perst_reloads_same_image (not in a guest) diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index f3d34b941f859..af23d7dfe7520 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -229,6 +229,14 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed, if (ctx->status == STARTED) goto out; /* already started */ + /* + * Increment the mapped context count for adapter. This also checks + * if adapter_context_lock is taken. + */ + rc = cxl_adapter_context_get(ctx->afu->adapter); + if (rc) + goto out; + if (task) { ctx->pid = get_task_pid(task, PIDTYPE_PID); ctx->glpid = get_task_pid(task->group_leader, PIDTYPE_PID); @@ -240,6 +248,7 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed, if ((rc = cxl_ops->attach_process(ctx, kernel, wed, 0))) { put_pid(ctx->pid); + cxl_adapter_context_put(ctx->afu->adapter); cxl_ctx_put(); goto out; } diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index c466ee2b0c973..5e506c19108ad 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -238,6 +238,9 @@ int __detach_context(struct cxl_context *ctx) put_pid(ctx->glpid); cxl_ctx_put(); + + /* Decrease the attached context count on the adapter */ + cxl_adapter_context_put(ctx->afu->adapter); return 0; } diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 01d372aba1314..a144073593fa1 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -618,6 +618,14 @@ struct cxl { bool perst_select_user; bool perst_same_image; bool psl_timebase_synced; + + /* + * number of contexts mapped on to this card. Possible values are: + * >0: Number of contexts mapped and new one can be mapped. + * 0: No active contexts and new ones can be mapped. + * -1: No contexts mapped and new ones cannot be mapped. + */ + atomic_t contexts_num; }; int cxl_pci_alloc_one_irq(struct cxl *adapter); @@ -944,4 +952,20 @@ bool cxl_pci_is_vphb_device(struct pci_dev *dev); /* decode AFU error bits in the PSL register PSL_SERR_An */ void cxl_afu_decode_psl_serr(struct cxl_afu *afu, u64 serr); + +/* + * Increments the number of attached contexts on an adapter. + * In case an adapter_context_lock is taken the return -EBUSY. + */ +int cxl_adapter_context_get(struct cxl *adapter); + +/* Decrements the number of attached contexts on an adapter */ +void cxl_adapter_context_put(struct cxl *adapter); + +/* If no active contexts then prevents contexts from being attached */ +int cxl_adapter_context_lock(struct cxl *adapter); + +/* Unlock the contexts-lock if taken. Warn and force unlock otherwise */ +void cxl_adapter_context_unlock(struct cxl *adapter); + #endif diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index 5fb9894b157fa..d0b421f49b397 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -205,11 +205,22 @@ static long afu_ioctl_start_work(struct cxl_context *ctx, ctx->pid = get_task_pid(current, PIDTYPE_PID); ctx->glpid = get_task_pid(current->group_leader, PIDTYPE_PID); + /* + * Increment the mapped context count for adapter. This also checks + * if adapter_context_lock is taken. + */ + rc = cxl_adapter_context_get(ctx->afu->adapter); + if (rc) { + afu_release_irqs(ctx, ctx); + goto out; + } + trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr); if ((rc = cxl_ops->attach_process(ctx, false, work.work_element_descriptor, amr))) { afu_release_irqs(ctx, ctx); + cxl_adapter_context_put(ctx->afu->adapter); goto out; } diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c index 9aa58a77a24d1..3e102cd6ed914 100644 --- a/drivers/misc/cxl/guest.c +++ b/drivers/misc/cxl/guest.c @@ -1152,6 +1152,9 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic if ((rc = cxl_sysfs_adapter_add(adapter))) goto err_put1; + /* release the context lock as the adapter is configured */ + cxl_adapter_context_unlock(adapter); + return adapter; err_put1: diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index d9be23b24aa3b..62e0dfb5f15b6 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -243,8 +243,10 @@ struct cxl *cxl_alloc_adapter(void) if (dev_set_name(&adapter->dev, "card%i", adapter->adapter_num)) goto err2; - return adapter; + /* start with context lock taken */ + atomic_set(&adapter->contexts_num, -1); + return adapter; err2: cxl_remove_adapter_nr(adapter); err1: @@ -286,6 +288,44 @@ int cxl_afu_select_best_mode(struct cxl_afu *afu) return 0; } +int cxl_adapter_context_get(struct cxl *adapter) +{ + int rc; + + rc = atomic_inc_unless_negative(&adapter->contexts_num); + return rc >= 0 ? 0 : -EBUSY; +} + +void cxl_adapter_context_put(struct cxl *adapter) +{ + atomic_dec_if_positive(&adapter->contexts_num); +} + +int cxl_adapter_context_lock(struct cxl *adapter) +{ + int rc; + /* no active contexts -> contexts_num == 0 */ + rc = atomic_cmpxchg(&adapter->contexts_num, 0, -1); + return rc ? -EBUSY : 0; +} + +void cxl_adapter_context_unlock(struct cxl *adapter) +{ + int val = atomic_cmpxchg(&adapter->contexts_num, -1, 0); + + /* + * contexts lock taken -> contexts_num == -1 + * If not true then show a warning and force reset the lock. + * This will happen when context_unlock was requested without + * doing a context_lock. + */ + if (val != -1) { + atomic_set(&adapter->contexts_num, 0); + WARN(1, "Adapter context unlocked with %d active contexts", + val); + } +} + static int __init init_cxl(void) { int rc = 0; diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 7afad8477ad55..e96be9ca4e604 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -1487,6 +1487,8 @@ static int cxl_configure_adapter(struct cxl *adapter, struct pci_dev *dev) if ((rc = cxl_native_register_psl_err_irq(adapter))) goto err; + /* Release the context lock as adapter is configured */ + cxl_adapter_context_unlock(adapter); return 0; err: diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c index b043c20f158f1..a8b6d6a635e96 100644 --- a/drivers/misc/cxl/sysfs.c +++ b/drivers/misc/cxl/sysfs.c @@ -75,12 +75,31 @@ static ssize_t reset_adapter_store(struct device *device, int val; rc = sscanf(buf, "%i", &val); - if ((rc != 1) || (val != 1)) + if ((rc != 1) || (val != 1 && val != -1)) return -EINVAL; - if ((rc = cxl_ops->adapter_reset(adapter))) - return rc; - return count; + /* + * See if we can lock the context mapping that's only allowed + * when there are no contexts attached to the adapter. Once + * taken this will also prevent any context from getting activated. + */ + if (val == 1) { + rc = cxl_adapter_context_lock(adapter); + if (rc) + goto out; + + rc = cxl_ops->adapter_reset(adapter); + /* In case reset failed release context lock */ + if (rc) + cxl_adapter_context_unlock(adapter); + + } else if (val == -1) { + /* Perform a forced adapter reset */ + rc = cxl_ops->adapter_reset(adapter); + } + +out: + return rc ? rc : count; } static ssize_t load_image_on_perst_show(struct device *device, -- GitLab From 08b5e79ebdb58868cbb6976ba0e3898029394e6d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 13 Oct 2016 16:27:30 +1100 Subject: [PATCH 0748/1167] powerpc/mm: Drop dump_numa_memory_topology() At boot we dump the NUMA memory topology in dump_numa_memory_topology(), at KERN_DEBUG level, resulting in output like: Node 0 Memory: 0x0-0x100000000 Node 1 Memory: 0x100000000-0x200000000 Which is nice enough, but immediately after that we iterate over each node and call setup_node_data(), which also prints out the node ranges, at KERN_INFO, giving eg: numa: Initmem setup node 0 [mem 0x00000000-0xffffffff] numa: Initmem setup node 1 [mem 0x100000000-0x1ffffffff] Additionally dump_numa_memory_topology() does not use KERN_CONT correctly, resulting in split output lines on recent kernels. So drop dump_numa_memory_topology() as superfluous chatter. Signed-off-by: Michael Ellerman Acked-by: Balbir Singh Signed-off-by: Michael Ellerman --- arch/powerpc/mm/numa.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 75b9cd6150cc8..db5fc2b54c5a1 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -871,40 +871,6 @@ void __init dump_numa_cpu_topology(void) } } -static void __init dump_numa_memory_topology(void) -{ - unsigned int node; - unsigned int count; - - if (min_common_depth == -1 || !numa_enabled) - return; - - for_each_online_node(node) { - unsigned long i; - - printk(KERN_DEBUG "Node %d Memory:", node); - - count = 0; - - for (i = 0; i < memblock_end_of_DRAM(); - i += (1 << SECTION_SIZE_BITS)) { - if (early_pfn_to_nid(i >> PAGE_SHIFT) == node) { - if (count == 0) - printk(" 0x%lx", i); - ++count; - } else { - if (count > 0) - printk("-0x%lx", i); - count = 0; - } - } - - if (count > 0) - printk("-0x%lx", i); - printk("\n"); - } -} - /* Initialize NODE_DATA for a node on the local memory */ static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn) { @@ -947,8 +913,6 @@ void __init initmem_init(void) if (parse_numa_properties()) setup_nonnuma(); - else - dump_numa_memory_topology(); memblock_dump_all(); -- GitLab From 8467801cc8744511bd2664fae7d72ab704816844 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 18 Oct 2016 14:22:14 +0530 Subject: [PATCH 0749/1167] powerpc: Fix numa topology console print With recent update to printk, we get console output like below: [ 0.550639] Brought up 160 CPUs [ 0.550718] Node 0 CPUs: [ 0.550721] 0 [ 0.550754] -39 [ 0.550794] Node 1 CPUs: [ 0.550798] 40 [ 0.550817] -79 [ 0.550856] Node 16 CPUs: [ 0.550860] 80 [ 0.550880] -119 [ 0.550917] Node 17 CPUs: [ 0.550923] 120 [ 0.550942] -159 Fix this by properly using pr_cont(), ie. KERN_CONT. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/mm/numa.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index db5fc2b54c5a1..a51c188b81f31 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -845,7 +845,7 @@ void __init dump_numa_cpu_topology(void) return; for_each_online_node(node) { - printk(KERN_DEBUG "Node %d CPUs:", node); + pr_info("Node %d CPUs:", node); count = 0; /* @@ -856,18 +856,18 @@ void __init dump_numa_cpu_topology(void) if (cpumask_test_cpu(cpu, node_to_cpumask_map[node])) { if (count == 0) - printk(" %u", cpu); + pr_cont(" %u", cpu); ++count; } else { if (count > 1) - printk("-%u", cpu - 1); + pr_cont("-%u", cpu - 1); count = 0; } } if (count > 1) - printk("-%u", nr_cpu_ids - 1); - printk("\n"); + pr_cont("-%u", nr_cpu_ids - 1); + pr_cont("\n"); } } -- GitLab From 78914ff0843623ee6dbeae92fa0bb8761828684e Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 18 Oct 2016 09:33:44 +1100 Subject: [PATCH 0750/1167] powerpc: Ignore the pkey system calls for now Eliminates warning messages: :1316:2: warning: #warning syscall pkey_mprotect not implemented [-Wcpp] :1319:2: warning: #warning syscall pkey_alloc not implemented [-Wcpp] :1322:2: warning: #warning syscall pkey_free not implemented [-Wcpp] Hopefully we will remember to revert this commit if we ever implement them. Signed-off-by: Stephen Rothwell Acked-by: Balbir Singh Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/unistd.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index cf12c580f6b28..e8cdfec8d5125 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -16,6 +16,10 @@ #define __NR__exit __NR_exit +#define __IGNORE_pkey_mprotect +#define __IGNORE_pkey_alloc +#define __IGNORE_pkey_free + #ifndef __ASSEMBLY__ #include -- GitLab From dd1dafcdf071d94cb53917612c66a169ce741461 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 14:26:57 +0000 Subject: [PATCH 0751/1167] irqchip/eznps: Drop pointless static qualifier in nps400_of_init() There is no need to have the 'struct irq_domain *nps400_root_domain' variable static since new value is always assigned before use. Fixes: 44df427c894a ("irqchip: add nps Internal and external irqchips") Signed-off-by: Wei Yongjun Cc: Marc Zyngier Cc: Vineet Gupta Cc: Jason Cooper Link: http://lkml.kernel.org/r/1476714417-12095-1-git-send-email-weiyj.lk@gmail.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-eznps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-eznps.c b/drivers/irqchip/irq-eznps.c index ebc2b0b15f677..2a7a38830a8df 100644 --- a/drivers/irqchip/irq-eznps.c +++ b/drivers/irqchip/irq-eznps.c @@ -135,7 +135,7 @@ static const struct irq_domain_ops nps400_irq_ops = { static int __init nps400_of_init(struct device_node *node, struct device_node *parent) { - static struct irq_domain *nps400_root_domain; + struct irq_domain *nps400_root_domain; if (parent) { pr_err("DeviceTree incore ic not a root irq controller\n"); -- GitLab From b0dddf6c147e6fe61374d625c4bb2b7c52018639 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 18 Oct 2016 16:53:11 +0100 Subject: [PATCH 0752/1167] efi/arm: Fix absolute relocation detection for older toolchains When building the ARM kernel with CONFIG_EFI=y, the following build error may occur when using a less recent version of binutils (2.23 or older): STUBCPY drivers/firmware/efi/libstub/lib-sort.stub.o 00000000 R_ARM_ABS32 sort 00000004 R_ARM_ABS32 __ksymtab_strings drivers/firmware/efi/libstub/lib-sort.stub.o: absolute symbol references not allowed in the EFI stub (and when building with debug symbols, the list above is much longer, and contains all the internal references between the .debug sections and the actual code) This issue is caused by the fact that objcopy v2.23 or earlier does not support wildcards in its -R and -j options, which means the following line from the Makefile: STUBCOPY_FLAGS-y := -R .debug* -R *ksymtab* -R *kcrctab* fails to take effect, leaving harmless absolute relocations in the binary that are indistinguishable from relocations that may cause crashes at runtime due to the fact that these relocations are resolved at link time using the virtual address of the kernel, which is always different from the address at which the EFI firmware loads and invokes the stub. So, as a workaround, disable debug symbols explicitly when building the stub for ARM, and strip the ksymtab and kcrctab symbols for the only exported symbol we currently reuse in the stub, which is 'sort'. Tested-by: Jon Hunter Signed-off-by: Ard Biesheuvel Reviewed-by: Matt Fleming Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1476805991-7160-2-git-send-email-ard.biesheuvel@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index c06945160a415..5e23e2d305e71 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -11,7 +11,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \ -mno-mmx -mno-sse cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) -cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \ +cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) -g0 \ -fno-builtin -fpic -mno-single-pic-base cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt @@ -79,5 +79,6 @@ quiet_cmd_stubcopy = STUBCPY $@ # decompressor. So move our .data to .data.efistub, which is preserved # explicitly by the decompressor linker script. # -STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub +STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub \ + -R ___ksymtab+sort -R ___kcrctab+sort STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS -- GitLab From b5a9b340789b2b24c6896bcf7a065c31a4db671c Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Wed, 19 Oct 2016 14:45:23 +0200 Subject: [PATCH 0753/1167] sched/fair: Fix incorrect task group ->load_avg A scheduler performance regression has been reported by Joseph Salisbury, which he bisected back to: 3d30544f0212 ("sched/fair: Apply more PELT fixes) The regression triggers when several levels of task groups are involved (read: SystemD) and cpu_possible_mask != cpu_present_mask. The root cause is that group entity's load (tg_child->se[i]->avg.load_avg) is initialized to scale_load_down(se->load.weight). During the creation of a child task group, its group entities on possible CPUs are attached to parent's cfs_rq (tg_parent) and their loads are added to the parent's load (tg_parent->load_avg) with update_tg_load_avg(). But only the load on online CPUs will then be updated to reflect real load, whereas load on other CPUs will stay at the initial value. The result is a tg_parent->load_avg that is higher than the real load, the weight of group entities (tg_parent->se[i]->load.weight) on online CPUs is smaller than it should be, and the task group gets a less running time than what it could expect. ( This situation can be detected with /proc/sched_debug. The ".tg_load_avg" of the task group will be much higher than sum of ".tg_load_avg_contrib" of online cfs_rqs of the task group. ) The load of group entities don't have to be intialized to something else than 0 because their load will increase when an entity is attached. Reported-by: Joseph Salisbury Tested-by: Dietmar Eggemann Signed-off-by: Vincent Guittot Acked-by: Peter Zijlstra Cc: # 4.8.x Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: joonwoop@codeaurora.org Fixes: 3d30544f0212 ("sched/fair: Apply more PELT fixes) Link: http://lkml.kernel.org/r/1476881123-10159-1-git-send-email-vincent.guittot@linaro.org Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 76ee7de1859de..d941c97dfbc32 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -690,7 +690,14 @@ void init_entity_runnable_average(struct sched_entity *se) * will definitely be update (after enqueue). */ sa->period_contrib = 1023; - sa->load_avg = scale_load_down(se->load.weight); + /* + * Tasks are intialized with full load to be seen as heavy tasks until + * they get a chance to stabilize to their real load level. + * Group entities are intialized with zero load to reflect the fact that + * nothing has been attached to the task group yet. + */ + if (entity_is_task(se)) + sa->load_avg = scale_load_down(se->load.weight); sa->load_sum = sa->load_avg * LOAD_AVG_MAX; /* * At this point, util_avg won't be used in select_task_rq_fair anyway -- GitLab From 1ee1710cd6bbf49853688e97d6e1d98b48f28586 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 19 Oct 2016 13:19:02 +0000 Subject: [PATCH 0754/1167] wusb: fix error return code in wusb_prf() Fix to return error code -ENOMEM from the kmalloc() error handling case instead of 0, as done elsewhere in this function. Fixes: a19b882c07a6 ("wusb: Stop using the stack for sg crypto scratch space") Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/crypto.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c index de089f3a82f3d..79451f7ef1b76 100644 --- a/drivers/usb/wusbcore/crypto.c +++ b/drivers/usb/wusbcore/crypto.c @@ -339,8 +339,10 @@ ssize_t wusb_prf(void *out, size_t out_size, goto error_setkey_aes; } scratch = kmalloc(sizeof(*scratch), GFP_KERNEL); - if (!scratch) + if (!scratch) { + result = -ENOMEM; goto error_alloc_scratch; + } for (bitr = 0; bitr < (len + 63) / 64; bitr++) { sfn_le = cpu_to_le64(sfn++); -- GitLab From 889882bce2a5f69242c1f3acd840983f467499b9 Mon Sep 17 00:00:00 2001 From: Lukasz Odzioba Date: Tue, 4 Oct 2016 18:26:26 +0200 Subject: [PATCH 0755/1167] perf/x86/intel/cstate: Add C-state residency events for Knights Landing Although KNL does support C1,C6,PC2,PC3,PC6 states, the patch only supports C6,PC2,PC3,PC6, because there is no counter for C1. C6 residency counter MSR on KNL has a different address than other platforms which is handled as a new quirk flag. Signed-off-by: Lukasz Odzioba Acked-by: Peter Zijlstra Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Rafael J. Wysocki Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: bp@suse.de Cc: dave.hansen@linux.intel.com Cc: kan.liang@intel.com Link: http://lkml.kernel.org/r/1475598386-19597-1-git-send-email-lukasz.odzioba@intel.com Signed-off-by: Ingo Molnar --- arch/x86/events/intel/cstate.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index 3ca87b5a86776..4f5ac726335f8 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -48,7 +48,8 @@ * Scope: Core * MSR_CORE_C6_RESIDENCY: CORE C6 Residency Counter * perf code: 0x02 - * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW + * SKL,KNL * Scope: Core * MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter * perf code: 0x03 @@ -56,15 +57,16 @@ * Scope: Core * MSR_PKG_C2_RESIDENCY: Package C2 Residency Counter. * perf code: 0x00 - * Available model: SNB,IVB,HSW,BDW,SKL + * Available model: SNB,IVB,HSW,BDW,SKL,KNL * Scope: Package (physical package) * MSR_PKG_C3_RESIDENCY: Package C3 Residency Counter. * perf code: 0x01 - * Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,KNL * Scope: Package (physical package) * MSR_PKG_C6_RESIDENCY: Package C6 Residency Counter. * perf code: 0x02 - * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW + * SKL,KNL * Scope: Package (physical package) * MSR_PKG_C7_RESIDENCY: Package C7 Residency Counter. * perf code: 0x03 @@ -118,6 +120,7 @@ struct cstate_model { /* Quirk flags */ #define SLM_PKG_C6_USE_C7_MSR (1UL << 0) +#define KNL_CORE_C6_MSR (1UL << 1) struct perf_cstate_msr { u64 msr; @@ -488,6 +491,18 @@ static const struct cstate_model slm_cstates __initconst = { .quirks = SLM_PKG_C6_USE_C7_MSR, }; + +static const struct cstate_model knl_cstates __initconst = { + .core_events = BIT(PERF_CSTATE_CORE_C6_RES), + + .pkg_events = BIT(PERF_CSTATE_PKG_C2_RES) | + BIT(PERF_CSTATE_PKG_C3_RES) | + BIT(PERF_CSTATE_PKG_C6_RES), + .quirks = KNL_CORE_C6_MSR, +}; + + + #define X86_CSTATES_MODEL(model, states) \ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long) &(states) } @@ -523,6 +538,8 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = { X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_MOBILE, snb_cstates), X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_DESKTOP, snb_cstates), + + X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNL, knl_cstates), { }, }; MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match); @@ -558,6 +575,11 @@ static int __init cstate_probe(const struct cstate_model *cm) if (cm->quirks & SLM_PKG_C6_USE_C7_MSR) pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY; + /* KNL has different MSR for CORE C6 */ + if (cm->quirks & KNL_CORE_C6_MSR) + pkg_msr[PERF_CSTATE_CORE_C6_RES].msr = MSR_KNL_CORE_C6_RESIDENCY; + + has_cstate_core = cstate_probe_msr(cm->core_events, PERF_CSTATE_CORE_EVENT_MAX, core_msr, core_events_attrs); -- GitLab From 3805a938a6c24284863732fd45cec5a04609a224 Mon Sep 17 00:00:00 2001 From: Eric Garver Date: Mon, 17 Oct 2016 16:30:12 -0400 Subject: [PATCH 0756/1167] flow_dissector: Check skb for VLAN only if skb specified. Fixes a panic when calling eth_get_headlen(). Noticed on i40e driver. Fixes: d5709f7ab776 ("flow_dissector: For stripped vlan, get vlan info from skb->vlan_tci") Signed-off-by: Eric Garver Reviewed-by: Jakub Sitnicki Acked-by: Amir Vadai Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 1a7b80f733764..44e6ba9d3a6b2 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -247,12 +247,10 @@ bool __skb_flow_dissect(const struct sk_buff *skb, case htons(ETH_P_8021Q): { const struct vlan_hdr *vlan; - if (skb_vlan_tag_present(skb)) + if (skb && skb_vlan_tag_present(skb)) proto = skb->protocol; - if (!skb_vlan_tag_present(skb) || - proto == cpu_to_be16(ETH_P_8021Q) || - proto == cpu_to_be16(ETH_P_8021AD)) { + if (eth_type_vlan(proto)) { struct vlan_hdr _vlan; vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), -- GitLab From 1c5b51dfb7b4564008e0cadec5381a69e88b0d21 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 4 Jul 2016 16:59:43 +0100 Subject: [PATCH 0757/1167] arm64: swp emulation: bound LL/SC retries before rescheduling If a CPU does not implement a global monitor for certain memory types, then userspace can attempt a kernel DoS by issuing SWP instructions targetting the problematic memory (for example, a framebuffer mapped with non-cacheable attributes). The SWP emulation code protects against these sorts of attacks by checking for pending signals and potentially rescheduling when the STXR instruction fails during the emulation. Whilst this is good for avoiding livelock, it harms emulation of legitimate SWP instructions on CPUs where forward progress is not guaranteed if there are memory accesses to the same reservation granule (up to 2k) between the failing STXR and the retry of the LDXR. This patch solves the problem by retrying the STXR a bounded number of times (4) before breaking out of the LL/SC loop and looking for something else to do. Cc: Fixes: bd35a4adc413 ("arm64: Port SWP/SWPB emulation support from arm") Reviewed-by: Mark Rutland Signed-off-by: Will Deacon --- arch/arm64/kernel/armv8_deprecated.c | 36 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 42ffdb54e162d..b0988bb1bf648 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -280,35 +280,43 @@ static void __init register_insn_emulation_sysctl(struct ctl_table *table) /* * Error-checking SWP macros implemented using ldxr{b}/stxr{b} */ -#define __user_swpX_asm(data, addr, res, temp, B) \ + +/* Arbitrary constant to ensure forward-progress of the LL/SC loop */ +#define __SWP_LL_SC_LOOPS 4 + +#define __user_swpX_asm(data, addr, res, temp, temp2, B) \ __asm__ __volatile__( \ + " mov %w3, %w7\n" \ ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) \ - "0: ldxr"B" %w2, [%3]\n" \ - "1: stxr"B" %w0, %w1, [%3]\n" \ + "0: ldxr"B" %w2, [%4]\n" \ + "1: stxr"B" %w0, %w1, [%4]\n" \ " cbz %w0, 2f\n" \ - " mov %w0, %w4\n" \ + " sub %w3, %w3, #1\n" \ + " cbnz %w3, 0b\n" \ + " mov %w0, %w5\n" \ " b 3f\n" \ "2:\n" \ " mov %w1, %w2\n" \ "3:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ - "4: mov %w0, %w5\n" \ + "4: mov %w0, %w6\n" \ " b 3b\n" \ " .popsection" \ _ASM_EXTABLE(0b, 4b) \ _ASM_EXTABLE(1b, 4b) \ ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) \ - : "=&r" (res), "+r" (data), "=&r" (temp) \ - : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ + : "=&r" (res), "+r" (data), "=&r" (temp), "=&r" (temp2) \ + : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT), \ + "i" (__SWP_LL_SC_LOOPS) \ : "memory") -#define __user_swp_asm(data, addr, res, temp) \ - __user_swpX_asm(data, addr, res, temp, "") -#define __user_swpb_asm(data, addr, res, temp) \ - __user_swpX_asm(data, addr, res, temp, "b") +#define __user_swp_asm(data, addr, res, temp, temp2) \ + __user_swpX_asm(data, addr, res, temp, temp2, "") +#define __user_swpb_asm(data, addr, res, temp, temp2) \ + __user_swpX_asm(data, addr, res, temp, temp2, "b") /* * Bit 22 of the instruction encoding distinguishes between @@ -328,12 +336,12 @@ static int emulate_swpX(unsigned int address, unsigned int *data, } while (1) { - unsigned long temp; + unsigned long temp, temp2; if (type == TYPE_SWPB) - __user_swpb_asm(*data, address, res, temp); + __user_swpb_asm(*data, address, res, temp, temp2); else - __user_swp_asm(*data, address, res, temp); + __user_swp_asm(*data, address, res, temp, temp2); if (likely(res != -EAGAIN) || signal_pending(current)) break; -- GitLab From 1e6e57d9b34a9075d5f9e2048ea7b09756590d11 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 4 Jul 2016 17:44:48 +0100 Subject: [PATCH 0758/1167] arm64: percpu: rewrite ll/sc loops in assembly Writing the outer loop of an LL/SC sequence using do {...} while constructs potentially allows the compiler to hoist memory accesses between the STXR and the branch back to the LDXR. On CPUs that do not guarantee forward progress of LL/SC loops when faced with memory accesses to the same ERG (up to 2k) between the failed STXR and the branch back, we may end up livelocking. This patch avoids this issue in our percpu atomics by rewriting the outer loop as part of the LL/SC inline assembly block. Cc: Fixes: f97fc810798c ("arm64: percpu: Implement this_cpu operations") Reviewed-by: Mark Rutland Tested-by: Mark Rutland Signed-off-by: Will Deacon --- arch/arm64/include/asm/percpu.h | 120 +++++++++++++++----------------- 1 file changed, 56 insertions(+), 64 deletions(-) diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 2fee2f59288c9..5394c8405e660 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -44,48 +44,44 @@ static inline unsigned long __percpu_##op(void *ptr, \ \ switch (size) { \ case 1: \ - do { \ - asm ("//__per_cpu_" #op "_1\n" \ - "ldxrb %w[ret], %[ptr]\n" \ + asm ("//__per_cpu_" #op "_1\n" \ + "1: ldxrb %w[ret], %[ptr]\n" \ #asm_op " %w[ret], %w[ret], %w[val]\n" \ - "stxrb %w[loop], %w[ret], %[ptr]\n" \ - : [loop] "=&r" (loop), [ret] "=&r" (ret), \ - [ptr] "+Q"(*(u8 *)ptr) \ - : [val] "Ir" (val)); \ - } while (loop); \ + " stxrb %w[loop], %w[ret], %[ptr]\n" \ + " cbnz %w[loop], 1b" \ + : [loop] "=&r" (loop), [ret] "=&r" (ret), \ + [ptr] "+Q"(*(u8 *)ptr) \ + : [val] "Ir" (val)); \ break; \ case 2: \ - do { \ - asm ("//__per_cpu_" #op "_2\n" \ - "ldxrh %w[ret], %[ptr]\n" \ + asm ("//__per_cpu_" #op "_2\n" \ + "1: ldxrh %w[ret], %[ptr]\n" \ #asm_op " %w[ret], %w[ret], %w[val]\n" \ - "stxrh %w[loop], %w[ret], %[ptr]\n" \ - : [loop] "=&r" (loop), [ret] "=&r" (ret), \ - [ptr] "+Q"(*(u16 *)ptr) \ - : [val] "Ir" (val)); \ - } while (loop); \ + " stxrh %w[loop], %w[ret], %[ptr]\n" \ + " cbnz %w[loop], 1b" \ + : [loop] "=&r" (loop), [ret] "=&r" (ret), \ + [ptr] "+Q"(*(u16 *)ptr) \ + : [val] "Ir" (val)); \ break; \ case 4: \ - do { \ - asm ("//__per_cpu_" #op "_4\n" \ - "ldxr %w[ret], %[ptr]\n" \ + asm ("//__per_cpu_" #op "_4\n" \ + "1: ldxr %w[ret], %[ptr]\n" \ #asm_op " %w[ret], %w[ret], %w[val]\n" \ - "stxr %w[loop], %w[ret], %[ptr]\n" \ - : [loop] "=&r" (loop), [ret] "=&r" (ret), \ - [ptr] "+Q"(*(u32 *)ptr) \ - : [val] "Ir" (val)); \ - } while (loop); \ + " stxr %w[loop], %w[ret], %[ptr]\n" \ + " cbnz %w[loop], 1b" \ + : [loop] "=&r" (loop), [ret] "=&r" (ret), \ + [ptr] "+Q"(*(u32 *)ptr) \ + : [val] "Ir" (val)); \ break; \ case 8: \ - do { \ - asm ("//__per_cpu_" #op "_8\n" \ - "ldxr %[ret], %[ptr]\n" \ + asm ("//__per_cpu_" #op "_8\n" \ + "1: ldxr %[ret], %[ptr]\n" \ #asm_op " %[ret], %[ret], %[val]\n" \ - "stxr %w[loop], %[ret], %[ptr]\n" \ - : [loop] "=&r" (loop), [ret] "=&r" (ret), \ - [ptr] "+Q"(*(u64 *)ptr) \ - : [val] "Ir" (val)); \ - } while (loop); \ + " stxr %w[loop], %[ret], %[ptr]\n" \ + " cbnz %w[loop], 1b" \ + : [loop] "=&r" (loop), [ret] "=&r" (ret), \ + [ptr] "+Q"(*(u64 *)ptr) \ + : [val] "Ir" (val)); \ break; \ default: \ BUILD_BUG(); \ @@ -150,44 +146,40 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val, switch (size) { case 1: - do { - asm ("//__percpu_xchg_1\n" - "ldxrb %w[ret], %[ptr]\n" - "stxrb %w[loop], %w[val], %[ptr]\n" - : [loop] "=&r"(loop), [ret] "=&r"(ret), - [ptr] "+Q"(*(u8 *)ptr) - : [val] "r" (val)); - } while (loop); + asm ("//__percpu_xchg_1\n" + "1: ldxrb %w[ret], %[ptr]\n" + " stxrb %w[loop], %w[val], %[ptr]\n" + " cbnz %w[loop], 1b" + : [loop] "=&r"(loop), [ret] "=&r"(ret), + [ptr] "+Q"(*(u8 *)ptr) + : [val] "r" (val)); break; case 2: - do { - asm ("//__percpu_xchg_2\n" - "ldxrh %w[ret], %[ptr]\n" - "stxrh %w[loop], %w[val], %[ptr]\n" - : [loop] "=&r"(loop), [ret] "=&r"(ret), - [ptr] "+Q"(*(u16 *)ptr) - : [val] "r" (val)); - } while (loop); + asm ("//__percpu_xchg_2\n" + "1: ldxrh %w[ret], %[ptr]\n" + " stxrh %w[loop], %w[val], %[ptr]\n" + " cbnz %w[loop], 1b" + : [loop] "=&r"(loop), [ret] "=&r"(ret), + [ptr] "+Q"(*(u16 *)ptr) + : [val] "r" (val)); break; case 4: - do { - asm ("//__percpu_xchg_4\n" - "ldxr %w[ret], %[ptr]\n" - "stxr %w[loop], %w[val], %[ptr]\n" - : [loop] "=&r"(loop), [ret] "=&r"(ret), - [ptr] "+Q"(*(u32 *)ptr) - : [val] "r" (val)); - } while (loop); + asm ("//__percpu_xchg_4\n" + "1: ldxr %w[ret], %[ptr]\n" + " stxr %w[loop], %w[val], %[ptr]\n" + " cbnz %w[loop], 1b" + : [loop] "=&r"(loop), [ret] "=&r"(ret), + [ptr] "+Q"(*(u32 *)ptr) + : [val] "r" (val)); break; case 8: - do { - asm ("//__percpu_xchg_8\n" - "ldxr %[ret], %[ptr]\n" - "stxr %w[loop], %[val], %[ptr]\n" - : [loop] "=&r"(loop), [ret] "=&r"(ret), - [ptr] "+Q"(*(u64 *)ptr) - : [val] "r" (val)); - } while (loop); + asm ("//__percpu_xchg_8\n" + "1: ldxr %[ret], %[ptr]\n" + " stxr %w[loop], %[val], %[ptr]\n" + " cbnz %w[loop], 1b" + : [loop] "=&r"(loop), [ret] "=&r"(ret), + [ptr] "+Q"(*(u64 *)ptr) + : [val] "r" (val)); break; default: BUILD_BUG(); -- GitLab From e4961b0768852d9eb7383e1a5df178eacb714656 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 19 Oct 2016 16:57:08 +0300 Subject: [PATCH 0759/1167] net: core: Correctly iterate over lower adjacency list Tamir reported the following trace when processing ARP requests received via a vlan device on top of a VLAN-aware bridge: NMI watchdog: BUG: soft lockup - CPU#1 stuck for 22s! [swapper/1:0] [...] CPU: 1 PID: 0 Comm: swapper/1 Tainted: G W 4.8.0-rc7 #1 Hardware name: Mellanox Technologies Ltd. "MSN2100-CB2F"/"SA001017", BIOS 5.6.5 06/07/2016 task: ffff88017edfea40 task.stack: ffff88017ee10000 RIP: 0010:[] [] netdev_all_lower_get_next_rcu+0x33/0x60 [...] Call Trace: [] mlxsw_sp_port_lower_dev_hold+0x5a/0xa0 [mlxsw_spectrum] [] mlxsw_sp_router_netevent_event+0x80/0x150 [mlxsw_spectrum] [] notifier_call_chain+0x4a/0x70 [] atomic_notifier_call_chain+0x1a/0x20 [] call_netevent_notifiers+0x1b/0x20 [] neigh_update+0x306/0x740 [] neigh_event_ns+0x4e/0xb0 [] arp_process+0x66f/0x700 [] ? common_interrupt+0x8c/0x8c [] arp_rcv+0x139/0x1d0 [] ? vlan_do_receive+0xda/0x320 [] __netif_receive_skb_core+0x524/0xab0 [] ? dev_queue_xmit+0x10/0x20 [] ? br_forward_finish+0x3d/0xc0 [bridge] [] ? br_handle_vlan+0xf6/0x1b0 [bridge] [] __netif_receive_skb+0x18/0x60 [] netif_receive_skb_internal+0x40/0xb0 [] netif_receive_skb+0x1c/0x70 [] br_pass_frame_up+0xc6/0x160 [bridge] [] ? deliver_clone+0x37/0x50 [bridge] [] ? br_flood+0xcc/0x160 [bridge] [] br_handle_frame_finish+0x224/0x4f0 [bridge] [] br_handle_frame+0x174/0x300 [bridge] [] __netif_receive_skb_core+0x329/0xab0 [] ? find_next_bit+0x15/0x20 [] ? cpumask_next_and+0x32/0x50 [] ? load_balance+0x178/0x9b0 [] __netif_receive_skb+0x18/0x60 [] netif_receive_skb_internal+0x40/0xb0 [] netif_receive_skb+0x1c/0x70 [] mlxsw_sp_rx_listener_func+0x61/0xb0 [mlxsw_spectrum] [] mlxsw_core_skb_receive+0x187/0x200 [mlxsw_core] [] mlxsw_pci_cq_tasklet+0x63a/0x9b0 [mlxsw_pci] [] tasklet_action+0xf6/0x110 [] __do_softirq+0xf6/0x280 [] irq_exit+0xdf/0xf0 [] do_IRQ+0x54/0xd0 [] common_interrupt+0x8c/0x8c The problem is that netdev_all_lower_get_next_rcu() never advances the iterator, thereby causing the loop over the lower adjacency list to run forever. Fix this by advancing the iterator and avoid the infinite loop. Fixes: 7ce856aaaf13 ("mlxsw: spectrum: Add couple of lower device helper functions") Signed-off-by: Ido Schimmel Reported-by: Tamir Winetroub Reviewed-by: Jiri Pirko Acked-by: David Ahern Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- net/core/dev.c | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 136ae6bbe81e1..465e128699a14 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3877,7 +3877,7 @@ struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev, ldev = netdev_all_lower_get_next(dev, &(iter))) #define netdev_for_each_all_lower_dev_rcu(dev, ldev, iter) \ - for (iter = (dev)->all_adj_list.lower.next, \ + for (iter = &(dev)->all_adj_list.lower, \ ldev = netdev_all_lower_get_next_rcu(dev, &(iter)); \ ldev; \ ldev = netdev_all_lower_get_next_rcu(dev, &(iter))) diff --git a/net/core/dev.c b/net/core/dev.c index f1fe26f664588..b09ac57f43483 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5511,10 +5511,14 @@ struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev, { struct netdev_adjacent *lower; - lower = list_first_or_null_rcu(&dev->all_adj_list.lower, - struct netdev_adjacent, list); + lower = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); + + if (&lower->list == &dev->all_adj_list.lower) + return NULL; + + *iter = &lower->list; - return lower ? lower->dev : NULL; + return lower->dev; } EXPORT_SYMBOL(netdev_all_lower_get_next_rcu); -- GitLab From 97c242902c209e7d46e365335db5202634484dcb Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 18 Oct 2016 18:50:23 +0200 Subject: [PATCH 0760/1167] switchdev: Execute bridge ndos only for bridge ports We recently got the following warning after setting up a vlan device on top of an offloaded bridge and executing 'bridge link': WARNING: CPU: 0 PID: 18566 at drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c:81 mlxsw_sp_port_orig_get.part.9+0x55/0x70 [mlxsw_spectrum] [...] CPU: 0 PID: 18566 Comm: bridge Not tainted 4.8.0-rc7 #1 Hardware name: Mellanox Technologies Ltd. Mellanox switch/Mellanox switch, BIOS 4.6.5 05/21/2015 0000000000000286 00000000e64ab94f ffff880406e6f8f0 ffffffff8135eaa3 0000000000000000 0000000000000000 ffff880406e6f930 ffffffff8108c43b 0000005106e6f988 ffff8803df398840 ffff880403c60108 ffff880406e6f990 Call Trace: [] dump_stack+0x63/0x90 [] __warn+0xcb/0xf0 [] warn_slowpath_null+0x1d/0x20 [] mlxsw_sp_port_orig_get.part.9+0x55/0x70 [mlxsw_spectrum] [] mlxsw_sp_port_attr_get+0xa5/0xb0 [mlxsw_spectrum] [] switchdev_port_attr_get+0x4f/0x140 [] switchdev_port_attr_get+0x100/0x140 [] switchdev_port_attr_get+0x100/0x140 [] switchdev_port_bridge_getlink+0x5b/0xc0 [] ? switchdev_port_fdb_dump+0x90/0x90 [] rtnl_bridge_getlink+0xe7/0x190 [] netlink_dump+0x122/0x290 [] __netlink_dump_start+0x15f/0x190 [] ? rtnl_bridge_dellink+0x230/0x230 [] rtnetlink_rcv_msg+0x1a6/0x220 [] ? __kmalloc_node_track_caller+0x208/0x2c0 [] ? rtnl_bridge_dellink+0x230/0x230 [] ? rtnl_newlink+0x890/0x890 [] netlink_rcv_skb+0xa4/0xc0 [] rtnetlink_rcv+0x28/0x30 [] netlink_unicast+0x18c/0x240 [] netlink_sendmsg+0x2fb/0x3a0 [] sock_sendmsg+0x38/0x50 [] SYSC_sendto+0x101/0x190 [] ? __sys_recvmsg+0x51/0x90 [] SyS_sendto+0xe/0x10 [] entry_SYSCALL_64_fastpath+0x1a/0xa4 The problem is that the 8021q module propagates the call to ndo_bridge_getlink() via switchdev ops, but the switch driver doesn't recognize the netdev, as it's not offloaded. While we can ignore calls being made to non-bridge ports inside the driver, a better fix would be to push this check up to the switchdev layer. Note that these ndos can be called for non-bridged netdev, but this only happens in certain PF drivers which don't call the corresponding switchdev functions anyway. Fixes: 99f44bb3527b ("mlxsw: spectrum: Enable L3 interfaces on top of bridge devices") Signed-off-by: Ido Schimmel Reported-by: Tamir Winetroub Tested-by: Tamir Winetroub Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 02beb35f577fc..3b95fe980fa27 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -771,6 +771,9 @@ int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, u32 mask = BR_LEARNING | BR_LEARNING_SYNC | BR_FLOOD; int err; + if (!netif_is_bridge_port(dev)) + return -EOPNOTSUPP; + err = switchdev_port_attr_get(dev, &attr); if (err && err != -EOPNOTSUPP) return err; @@ -926,6 +929,9 @@ int switchdev_port_bridge_setlink(struct net_device *dev, struct nlattr *afspec; int err = 0; + if (!netif_is_bridge_port(dev)) + return -EOPNOTSUPP; + protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_PROTINFO); if (protinfo) { @@ -959,6 +965,9 @@ int switchdev_port_bridge_dellink(struct net_device *dev, { struct nlattr *afspec; + if (!netif_is_bridge_port(dev)) + return -EOPNOTSUPP; + afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); if (afspec) -- GitLab From 85dda4e5b0ee1f5b4e8cc93d39e475006bc61ccd Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 18 Oct 2016 18:59:34 +0200 Subject: [PATCH 0761/1167] rtnetlink: Add rtnexthop offload flag to compare mask The offload flag is a status flag and should not be used by FIB semantics for comparison. Fixes: 37ed9493699c ("rtnetlink: add RTNH_F_EXTERNAL flag for fib offload") Signed-off-by: Jiri Pirko Reviewed-by: Andy Gospodarek Signed-off-by: David S. Miller --- include/uapi/linux/rtnetlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 262f0379d83ac..5a78be5181012 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -350,7 +350,7 @@ struct rtnexthop { #define RTNH_F_OFFLOAD 8 /* offloaded route */ #define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */ -#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN) +#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD) /* Macros to handle hexthops */ -- GitLab From 3b913179c3fa89dd0e304193fa0c746fc0481447 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Thu, 13 Oct 2016 01:20:14 +0100 Subject: [PATCH 0762/1167] mm: replace get_user_pages_locked() write/force parameters with gup_flags This removes the 'write' and 'force' use from get_user_pages_locked() and replaces them with 'gup_flags' to make the use of FOLL_FORCE explicit in callers as use of this flag can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes Acked-by: Michal Hocko Reviewed-by: Jan Kara Signed-off-by: Linus Torvalds --- include/linux/mm.h | 2 +- mm/frame_vector.c | 8 +++++++- mm/gup.c | 12 +++--------- mm/nommu.c | 5 ++++- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index abd53f2eb74ea..9fe9b0438169c 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1282,7 +1282,7 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages, struct vm_area_struct **vmas); long get_user_pages_locked(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, int *locked); + unsigned int gup_flags, struct page **pages, int *locked); long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, struct page **pages, unsigned int gup_flags); diff --git a/mm/frame_vector.c b/mm/frame_vector.c index 381bb07ed14f2..81b67498bb9c5 100644 --- a/mm/frame_vector.c +++ b/mm/frame_vector.c @@ -41,10 +41,16 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, int ret = 0; int err; int locked; + unsigned int gup_flags = 0; if (nr_frames == 0) return 0; + if (write) + gup_flags |= FOLL_WRITE; + if (force) + gup_flags |= FOLL_FORCE; + if (WARN_ON_ONCE(nr_frames > vec->nr_allocated)) nr_frames = vec->nr_allocated; @@ -59,7 +65,7 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, vec->got_ref = true; vec->is_pfns = false; ret = get_user_pages_locked(start, nr_frames, - write, force, (struct page **)(vec->ptrs), &locked); + gup_flags, (struct page **)(vec->ptrs), &locked); goto out; } diff --git a/mm/gup.c b/mm/gup.c index 373d1ec006e4f..3cfb55ef0cf4e 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -848,18 +848,12 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk, * up_read(&mm->mmap_sem); */ long get_user_pages_locked(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, + unsigned int gup_flags, struct page **pages, int *locked) { - unsigned int flags = FOLL_TOUCH; - - if (write) - flags |= FOLL_WRITE; - if (force) - flags |= FOLL_FORCE; - return __get_user_pages_locked(current, current->mm, start, nr_pages, - pages, NULL, locked, true, flags); + pages, NULL, locked, true, + gup_flags | FOLL_TOUCH); } EXPORT_SYMBOL(get_user_pages_locked); diff --git a/mm/nommu.c b/mm/nommu.c index 7e27add39f7ef..842cfdd1a31e4 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -176,9 +176,12 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, EXPORT_SYMBOL(get_user_pages); long get_user_pages_locked(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, + unsigned int gup_flags, struct page **pages, int *locked) { + int write = gup_flags & FOLL_WRITE; + int force = gup_flags & FOLL_FORCE; + return get_user_pages(start, nr_pages, write, force, pages, NULL); } EXPORT_SYMBOL(get_user_pages_locked); -- GitLab From 7f23b3504a0df63b724180262c5f3f117f21bcae Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Thu, 13 Oct 2016 01:20:15 +0100 Subject: [PATCH 0763/1167] mm: replace get_vaddr_frames() write/force parameters with gup_flags This removes the 'write' and 'force' from get_vaddr_frames() and replaces them with 'gup_flags' to make the use of FOLL_FORCE explicit in callers as use of this flag can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes Acked-by: Michal Hocko Reviewed-by: Jan Kara Signed-off-by: Linus Torvalds --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 3 ++- drivers/media/platform/omap/omap_vout.c | 2 +- drivers/media/v4l2-core/videobuf2-memops.c | 6 +++++- include/linux/mm.h | 2 +- mm/frame_vector.c | 13 ++----------- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index aa92decf4233d..fbd13fabdf2da 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -488,7 +488,8 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, goto err_free; } - ret = get_vaddr_frames(start, npages, true, true, g2d_userptr->vec); + ret = get_vaddr_frames(start, npages, FOLL_FORCE | FOLL_WRITE, + g2d_userptr->vec); if (ret != npages) { DRM_ERROR("failed to get user pages from userptr.\n"); if (ret < 0) diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index e668dde6d8572..a31b95cb3b09c 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -214,7 +214,7 @@ static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp, if (!vec) return -ENOMEM; - ret = get_vaddr_frames(virtp, 1, true, false, vec); + ret = get_vaddr_frames(virtp, 1, FOLL_WRITE, vec); if (ret != 1) { frame_vector_destroy(vec); return -EINVAL; diff --git a/drivers/media/v4l2-core/videobuf2-memops.c b/drivers/media/v4l2-core/videobuf2-memops.c index 3c3b517f1d1ca..1cd322e939c70 100644 --- a/drivers/media/v4l2-core/videobuf2-memops.c +++ b/drivers/media/v4l2-core/videobuf2-memops.c @@ -42,6 +42,10 @@ struct frame_vector *vb2_create_framevec(unsigned long start, unsigned long first, last; unsigned long nr; struct frame_vector *vec; + unsigned int flags = FOLL_FORCE; + + if (write) + flags |= FOLL_WRITE; first = start >> PAGE_SHIFT; last = (start + length - 1) >> PAGE_SHIFT; @@ -49,7 +53,7 @@ struct frame_vector *vb2_create_framevec(unsigned long start, vec = frame_vector_create(nr); if (!vec) return ERR_PTR(-ENOMEM); - ret = get_vaddr_frames(start & PAGE_MASK, nr, write, true, vec); + ret = get_vaddr_frames(start & PAGE_MASK, nr, flags, vec); if (ret < 0) goto out_destroy; /* We accept only complete set of PFNs */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 9fe9b0438169c..91cc923ce985d 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1305,7 +1305,7 @@ struct frame_vector { struct frame_vector *frame_vector_create(unsigned int nr_frames); void frame_vector_destroy(struct frame_vector *vec); int get_vaddr_frames(unsigned long start, unsigned int nr_pfns, - bool write, bool force, struct frame_vector *vec); + unsigned int gup_flags, struct frame_vector *vec); void put_vaddr_frames(struct frame_vector *vec); int frame_vector_to_pages(struct frame_vector *vec); void frame_vector_to_pfns(struct frame_vector *vec); diff --git a/mm/frame_vector.c b/mm/frame_vector.c index 81b67498bb9c5..db77dcb38afda 100644 --- a/mm/frame_vector.c +++ b/mm/frame_vector.c @@ -11,10 +11,7 @@ * get_vaddr_frames() - map virtual addresses to pfns * @start: starting user address * @nr_frames: number of pages / pfns from start to map - * @write: whether pages will be written to by the caller - * @force: whether to force write access even if user mapping is - * readonly. See description of the same argument of - get_user_pages(). + * @gup_flags: flags modifying lookup behaviour * @vec: structure which receives pages / pfns of the addresses mapped. * It should have space for at least nr_frames entries. * @@ -34,23 +31,17 @@ * This function takes care of grabbing mmap_sem as necessary. */ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, - bool write, bool force, struct frame_vector *vec) + unsigned int gup_flags, struct frame_vector *vec) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; int ret = 0; int err; int locked; - unsigned int gup_flags = 0; if (nr_frames == 0) return 0; - if (write) - gup_flags |= FOLL_WRITE; - if (force) - gup_flags |= FOLL_FORCE; - if (WARN_ON_ONCE(nr_frames > vec->nr_allocated)) nr_frames = vec->nr_allocated; -- GitLab From 768ae309a96103ed02eb1e111e838c87854d8b51 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Thu, 13 Oct 2016 01:20:16 +0100 Subject: [PATCH 0764/1167] mm: replace get_user_pages() write/force parameters with gup_flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the 'write' and 'force' from get_user_pages() and replaces them with 'gup_flags' to make the use of FOLL_FORCE explicit in callers as use of this flag can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes Acked-by: Christian König Acked-by: Jesper Nilsson Acked-by: Michal Hocko Reviewed-by: Jan Kara Signed-off-by: Linus Torvalds --- arch/cris/arch-v32/drivers/cryptocop.c | 4 +--- arch/ia64/kernel/err_inject.c | 2 +- arch/x86/mm/mpx.c | 5 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 7 +++++-- drivers/gpu/drm/radeon/radeon_ttm.c | 3 ++- drivers/gpu/drm/via/via_dmablit.c | 4 ++-- drivers/infiniband/core/umem.c | 6 +++++- drivers/infiniband/hw/mthca/mthca_memfree.c | 2 +- drivers/infiniband/hw/qib/qib_user_pages.c | 3 ++- drivers/infiniband/hw/usnic/usnic_uiom.c | 5 ++++- drivers/media/v4l2-core/videobuf-dma-sg.c | 7 +++++-- drivers/misc/mic/scif/scif_rma.c | 3 +-- drivers/misc/sgi-gru/grufault.c | 2 +- drivers/platform/goldfish/goldfish_pipe.c | 3 ++- drivers/rapidio/devices/rio_mport_cdev.c | 3 ++- .../interface/vchiq_arm/vchiq_2835_arm.c | 3 +-- .../interface/vchiq_arm/vchiq_arm.c | 3 +-- drivers/virt/fsl_hypervisor.c | 4 ++-- include/linux/mm.h | 2 +- mm/gup.c | 12 +++--------- mm/mempolicy.c | 2 +- mm/nommu.c | 18 ++++-------------- 22 files changed, 49 insertions(+), 54 deletions(-) diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c index b5698c876fccd..099e170a93ee7 100644 --- a/arch/cris/arch-v32/drivers/cryptocop.c +++ b/arch/cris/arch-v32/drivers/cryptocop.c @@ -2722,7 +2722,6 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig err = get_user_pages((unsigned long int)(oper.indata + prev_ix), noinpages, 0, /* read access only for in data */ - 0, /* no force */ inpages, NULL); @@ -2736,8 +2735,7 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig if (oper.do_cipher){ err = get_user_pages((unsigned long int)oper.cipher_outdata, nooutpages, - 1, /* write access for out data */ - 0, /* no force */ + FOLL_WRITE, /* write access for out data */ outpages, NULL); up_read(¤t->mm->mmap_sem); diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c index 09f845793d12c..5ed0ea92c5bfa 100644 --- a/arch/ia64/kernel/err_inject.c +++ b/arch/ia64/kernel/err_inject.c @@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr, u64 virt_addr=simple_strtoull(buf, NULL, 16); int ret; - ret = get_user_pages(virt_addr, 1, VM_READ, 0, NULL, NULL); + ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL); if (ret<=0) { #ifdef ERR_INJ_DEBUG printk("Virtual address %lx is not existing.\n",virt_addr); diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index 80476878eb4ca..e4f800999b32d 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c @@ -544,10 +544,9 @@ static int mpx_resolve_fault(long __user *addr, int write) { long gup_ret; int nr_pages = 1; - int force = 0; - gup_ret = get_user_pages((unsigned long)addr, nr_pages, write, - force, NULL, NULL); + gup_ret = get_user_pages((unsigned long)addr, nr_pages, + write ? FOLL_WRITE : 0, NULL, NULL); /* * get_user_pages() returns number of pages gotten. * 0 means we failed to fault in and get anything, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 887483b8b8183..dcaf691f56b55 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -555,10 +555,13 @@ struct amdgpu_ttm_tt { int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages) { struct amdgpu_ttm_tt *gtt = (void *)ttm; - int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY); + unsigned int flags = 0; unsigned pinned = 0; int r; + if (!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY)) + flags |= FOLL_WRITE; + if (gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) { /* check that we only use anonymous memory to prevent problems with writeback */ @@ -581,7 +584,7 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages) list_add(&guptask.list, >t->guptasks); spin_unlock(>t->guptasklock); - r = get_user_pages(userptr, num_pages, write, 0, p, NULL); + r = get_user_pages(userptr, num_pages, flags, p, NULL); spin_lock(>t->guptasklock); list_del(&guptask.list); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 455268214b893..3de5e6e216628 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -566,7 +566,8 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm) uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE; struct page **pages = ttm->pages + pinned; - r = get_user_pages(userptr, num_pages, write, 0, pages, NULL); + r = get_user_pages(userptr, num_pages, write ? FOLL_WRITE : 0, + pages, NULL); if (r < 0) goto release_pages; diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c index 7e2a12c4fed2a..1a3ad769f8c85 100644 --- a/drivers/gpu/drm/via/via_dmablit.c +++ b/drivers/gpu/drm/via/via_dmablit.c @@ -241,8 +241,8 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) down_read(¤t->mm->mmap_sem); ret = get_user_pages((unsigned long)xfer->mem_addr, vsg->num_pages, - (vsg->direction == DMA_FROM_DEVICE), - 0, vsg->pages, NULL); + (vsg->direction == DMA_FROM_DEVICE) ? FOLL_WRITE : 0, + vsg->pages, NULL); up_read(¤t->mm->mmap_sem); if (ret != vsg->num_pages) { diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index c68746ce6624c..224ad274ea0b8 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -94,6 +94,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, unsigned long dma_attrs = 0; struct scatterlist *sg, *sg_list_start; int need_release = 0; + unsigned int gup_flags = FOLL_WRITE; if (dmasync) dma_attrs |= DMA_ATTR_WRITE_BARRIER; @@ -183,6 +184,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, if (ret) goto out; + if (!umem->writable) + gup_flags |= FOLL_FORCE; + need_release = 1; sg_list_start = umem->sg_head.sgl; @@ -190,7 +194,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, ret = get_user_pages(cur_base, min_t(unsigned long, npages, PAGE_SIZE / sizeof (struct page *)), - 1, !umem->writable, page_list, vma_list); + gup_flags, page_list, vma_list); if (ret < 0) goto out; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 6c00d04b8b285..c6fe89d79248f 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -472,7 +472,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar, goto out; } - ret = get_user_pages(uaddr & PAGE_MASK, 1, 1, 0, pages, NULL); + ret = get_user_pages(uaddr & PAGE_MASK, 1, FOLL_WRITE, pages, NULL); if (ret < 0) goto out; diff --git a/drivers/infiniband/hw/qib/qib_user_pages.c b/drivers/infiniband/hw/qib/qib_user_pages.c index 2d2b94fd3633b..75f08624ac052 100644 --- a/drivers/infiniband/hw/qib/qib_user_pages.c +++ b/drivers/infiniband/hw/qib/qib_user_pages.c @@ -67,7 +67,8 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages, for (got = 0; got < num_pages; got += ret) { ret = get_user_pages(start_page + got * PAGE_SIZE, - num_pages - got, 1, 1, + num_pages - got, + FOLL_WRITE | FOLL_FORCE, p + got, NULL); if (ret < 0) goto bail_release; diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c index a0b6ebee4d8a0..1ccee6ea5bc30 100644 --- a/drivers/infiniband/hw/usnic/usnic_uiom.c +++ b/drivers/infiniband/hw/usnic/usnic_uiom.c @@ -111,6 +111,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable, int i; int flags; dma_addr_t pa; + unsigned int gup_flags; if (!can_do_mlock()) return -EPERM; @@ -135,6 +136,8 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable, flags = IOMMU_READ | IOMMU_CACHE; flags |= (writable) ? IOMMU_WRITE : 0; + gup_flags = FOLL_WRITE; + gup_flags |= (writable) ? 0 : FOLL_FORCE; cur_base = addr & PAGE_MASK; ret = 0; @@ -142,7 +145,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable, ret = get_user_pages(cur_base, min_t(unsigned long, npages, PAGE_SIZE / sizeof(struct page *)), - 1, !writable, page_list, NULL); + gup_flags, page_list, NULL); if (ret < 0) goto out; diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index f300f060b3f34..1db0af6c7f948 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -156,6 +156,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, { unsigned long first, last; int err, rw = 0; + unsigned int flags = FOLL_FORCE; dma->direction = direction; switch (dma->direction) { @@ -178,12 +179,14 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, if (NULL == dma->pages) return -ENOMEM; + if (rw == READ) + flags |= FOLL_WRITE; + dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n", data, size, dma->nr_pages); err = get_user_pages(data & PAGE_MASK, dma->nr_pages, - rw == READ, 1, /* force */ - dma->pages, NULL); + flags, dma->pages, NULL); if (err != dma->nr_pages) { dma->nr_pages = (err >= 0) ? err : 0; diff --git a/drivers/misc/mic/scif/scif_rma.c b/drivers/misc/mic/scif/scif_rma.c index e0203b1a20fd1..f806a4471eb91 100644 --- a/drivers/misc/mic/scif/scif_rma.c +++ b/drivers/misc/mic/scif/scif_rma.c @@ -1396,8 +1396,7 @@ int __scif_pin_pages(void *addr, size_t len, int *out_prot, pinned_pages->nr_pages = get_user_pages( (u64)addr, nr_pages, - !!(prot & SCIF_PROT_WRITE), - 0, + (prot & SCIF_PROT_WRITE) ? FOLL_WRITE : 0, pinned_pages->pages, NULL); up_write(&mm->mmap_sem); diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index a2d97b9b17e34..6fb773dbcd0c3 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c @@ -198,7 +198,7 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma, #else *pageshift = PAGE_SHIFT; #endif - if (get_user_pages(vaddr, 1, write, 0, &page, NULL) <= 0) + if (get_user_pages(vaddr, 1, write ? FOLL_WRITE : 0, &page, NULL) <= 0) return -EFAULT; *paddr = page_to_phys(page); put_page(page); diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 07462d79d0400..1aba2c74160eb 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -309,7 +309,8 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer, * much memory to the process. */ down_read(¤t->mm->mmap_sem); - ret = get_user_pages(address, 1, !is_write, 0, &page, NULL); + ret = get_user_pages(address, 1, is_write ? 0 : FOLL_WRITE, + &page, NULL); up_read(¤t->mm->mmap_sem); if (ret < 0) break; diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c index 436dfe871d323..9013a585507e8 100644 --- a/drivers/rapidio/devices/rio_mport_cdev.c +++ b/drivers/rapidio/devices/rio_mport_cdev.c @@ -892,7 +892,8 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode, down_read(¤t->mm->mmap_sem); pinned = get_user_pages( (unsigned long)xfer->loc_addr & PAGE_MASK, - nr_pages, dir == DMA_FROM_DEVICE, 0, + nr_pages, + dir == DMA_FROM_DEVICE ? FOLL_WRITE : 0, page_list, NULL); up_read(¤t->mm->mmap_sem); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c index c29040fdf9a77..1091b9f1dd070 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c @@ -423,8 +423,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type, actual_pages = get_user_pages(task, task->mm, (unsigned long)buf & ~(PAGE_SIZE - 1), num_pages, - (type == PAGELIST_READ) /*Write */ , - 0 /*Force */ , + (type == PAGELIST_READ) ? FOLL_WRITE : 0, pages, NULL /*vmas */); up_read(&task->mm->mmap_sem); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index e11c0e07471bc..7b6cd4d80621e 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -1477,8 +1477,7 @@ dump_phys_mem(void *virt_addr, uint32_t num_bytes) current->mm, /* mm */ (unsigned long)virt_addr, /* start */ num_pages, /* len */ - 0, /* write */ - 0, /* force */ + 0, /* gup_flags */ pages, /* pages (array of page pointers) */ NULL); /* vmas */ up_read(¤t->mm->mmap_sem); diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c index 60bdad3a689b8..150ce2abf6c8f 100644 --- a/drivers/virt/fsl_hypervisor.c +++ b/drivers/virt/fsl_hypervisor.c @@ -245,8 +245,8 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p) /* Get the physical addresses of the source buffer */ down_read(¤t->mm->mmap_sem); num_pinned = get_user_pages(param.local_vaddr - lb_offset, - num_pages, (param.source == -1) ? READ : WRITE, - 0, pages, NULL); + num_pages, (param.source == -1) ? 0 : FOLL_WRITE, + pages, NULL); up_read(¤t->mm->mmap_sem); if (num_pinned != num_pages) { diff --git a/include/linux/mm.h b/include/linux/mm.h index 91cc923ce985d..30bb5d9631bb3 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1279,7 +1279,7 @@ long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, int write, int force, struct page **pages, struct vm_area_struct **vmas); long get_user_pages(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, + unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas); long get_user_pages_locked(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, int *locked); diff --git a/mm/gup.c b/mm/gup.c index 3cfb55ef0cf4e..bbc2e76cdd776 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -987,18 +987,12 @@ EXPORT_SYMBOL(get_user_pages_remote); * obviously don't pass FOLL_REMOTE in here. */ long get_user_pages(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, + unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas) { - unsigned int flags = FOLL_TOUCH; - - if (write) - flags |= FOLL_WRITE; - if (force) - flags |= FOLL_FORCE; - return __get_user_pages_locked(current, current->mm, start, nr_pages, - pages, vmas, NULL, false, flags); + pages, vmas, NULL, false, + gup_flags | FOLL_TOUCH); } EXPORT_SYMBOL(get_user_pages); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index ad1c96ac313c0..0b859af06b87d 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -850,7 +850,7 @@ static int lookup_node(unsigned long addr) struct page *p; int err; - err = get_user_pages(addr & PAGE_MASK, 1, 0, 0, &p, NULL); + err = get_user_pages(addr & PAGE_MASK, 1, 0, &p, NULL); if (err >= 0) { err = page_to_nid(p); put_page(p); diff --git a/mm/nommu.c b/mm/nommu.c index 842cfdd1a31e4..70cb844dfd955 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -160,18 +160,11 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, * - don't permit access to VMAs that don't support it, such as I/O mappings */ long get_user_pages(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, + unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas) { - int flags = 0; - - if (write) - flags |= FOLL_WRITE; - if (force) - flags |= FOLL_FORCE; - - return __get_user_pages(current, current->mm, start, nr_pages, flags, - pages, vmas, NULL); + return __get_user_pages(current, current->mm, start, nr_pages, + gup_flags, pages, vmas, NULL); } EXPORT_SYMBOL(get_user_pages); @@ -179,10 +172,7 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, int *locked) { - int write = gup_flags & FOLL_WRITE; - int force = gup_flags & FOLL_FORCE; - - return get_user_pages(start, nr_pages, write, force, pages, NULL); + return get_user_pages(start, nr_pages, gup_flags, pages, NULL); } EXPORT_SYMBOL(get_user_pages_locked); -- GitLab From 9beae1ea89305a9667ceaab6d0bf46a045ad71e7 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Thu, 13 Oct 2016 01:20:17 +0100 Subject: [PATCH 0765/1167] mm: replace get_user_pages_remote() write/force parameters with gup_flags This removes the 'write' and 'force' from get_user_pages_remote() and replaces them with 'gup_flags' to make the use of FOLL_FORCE explicit in callers as use of this flag can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes Acked-by: Michal Hocko Reviewed-by: Jan Kara Signed-off-by: Linus Torvalds --- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 7 +++++-- drivers/gpu/drm/i915/i915_gem_userptr.c | 6 +++++- drivers/infiniband/core/umem_odp.c | 7 +++++-- fs/exec.c | 9 +++++++-- include/linux/mm.h | 2 +- kernel/events/uprobes.c | 6 ++++-- mm/gup.c | 22 +++++++--------------- mm/memory.c | 6 +++++- security/tomoyo/domain.c | 2 +- 9 files changed, 40 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 5ce3603e6eacb..0370b842d9cc2 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -748,19 +748,22 @@ static struct page **etnaviv_gem_userptr_do_get_pages( int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT; struct page **pvec; uintptr_t ptr; + unsigned int flags = 0; pvec = drm_malloc_ab(npages, sizeof(struct page *)); if (!pvec) return ERR_PTR(-ENOMEM); + if (!etnaviv_obj->userptr.ro) + flags |= FOLL_WRITE; + pinned = 0; ptr = etnaviv_obj->userptr.ptr; down_read(&mm->mmap_sem); while (pinned < npages) { ret = get_user_pages_remote(task, mm, ptr, npages - pinned, - !etnaviv_obj->userptr.ro, 0, - pvec + pinned, NULL); + flags, pvec + pinned, NULL); if (ret < 0) break; diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index e537930c64b53..c6f780f5abc9c 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -508,6 +508,10 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) pvec = drm_malloc_gfp(npages, sizeof(struct page *), GFP_TEMPORARY); if (pvec != NULL) { struct mm_struct *mm = obj->userptr.mm->mm; + unsigned int flags = 0; + + if (!obj->userptr.read_only) + flags |= FOLL_WRITE; ret = -EFAULT; if (atomic_inc_not_zero(&mm->mm_users)) { @@ -517,7 +521,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) (work->task, mm, obj->userptr.ptr + pinned * PAGE_SIZE, npages - pinned, - !obj->userptr.read_only, 0, + flags, pvec + pinned, NULL); if (ret < 0) break; diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 75077a018675e..1f0fe3217f238 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -527,6 +527,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, u64 off; int j, k, ret = 0, start_idx, npages = 0; u64 base_virt_addr; + unsigned int flags = 0; if (access_mask == 0) return -EINVAL; @@ -556,6 +557,9 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, goto out_put_task; } + if (access_mask & ODP_WRITE_ALLOWED_BIT) + flags |= FOLL_WRITE; + start_idx = (user_virt - ib_umem_start(umem)) >> PAGE_SHIFT; k = start_idx; @@ -574,8 +578,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, */ npages = get_user_pages_remote(owning_process, owning_mm, user_virt, gup_num_pages, - access_mask & ODP_WRITE_ALLOWED_BIT, - 0, local_page_list, NULL); + flags, local_page_list, NULL); up_read(&owning_mm->mmap_sem); if (npages < 0) diff --git a/fs/exec.c b/fs/exec.c index 6fcfb3f7b1379..4e497b9ee71ee 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -191,6 +191,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, { struct page *page; int ret; + unsigned int gup_flags = FOLL_FORCE; #ifdef CONFIG_STACK_GROWSUP if (write) { @@ -199,12 +200,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, return NULL; } #endif + + if (write) + gup_flags |= FOLL_WRITE; + /* * We are doing an exec(). 'current' is the process * doing the exec and bprm->mm is the new process's mm. */ - ret = get_user_pages_remote(current, bprm->mm, pos, 1, write, - 1, &page, NULL); + ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags, + &page, NULL); if (ret <= 0) return NULL; diff --git a/include/linux/mm.h b/include/linux/mm.h index 30bb5d9631bb3..ecc4be7b67e05 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1276,7 +1276,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, struct vm_area_struct **vmas, int *nonblocking); long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, + unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas); long get_user_pages(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index d4129bb05e5d0..f9ec9add21647 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -300,7 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, retry: /* Read the page with vaddr into memory */ - ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma); + ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page, + &vma); if (ret <= 0) return ret; @@ -1710,7 +1711,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr) * but we treat this as a 'remote' access since it is * essentially a kernel access to the memory. */ - result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL); + result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page, + NULL); if (result < 0) return result; diff --git a/mm/gup.c b/mm/gup.c index bbc2e76cdd776..7aa113c2d3731 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -915,9 +915,7 @@ EXPORT_SYMBOL(get_user_pages_unlocked); * @mm: mm_struct of target mm * @start: starting user address * @nr_pages: number of pages from start to pin - * @write: whether pages will be written to by the caller - * @force: whether to force access even when user mapping is currently - * protected (but never forces write access to shared mapping). + * @gup_flags: flags modifying lookup behaviour * @pages: array that receives pointers to the pages pinned. * Should be at least nr_pages long. Or NULL, if caller * only intends to ensure the pages are faulted in. @@ -946,9 +944,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked); * or similar operation cannot guarantee anything stronger anyway because * locks can't be held over the syscall boundary. * - * If write=0, the page must not be written to. If the page is written to, - * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called - * after the page is finished with, and before put_page is called. + * If gup_flags & FOLL_WRITE == 0, the page must not be written to. If the page + * is written to, set_page_dirty (or set_page_dirty_lock, as appropriate) must + * be called after the page is finished with, and before put_page is called. * * get_user_pages is typically used for fewer-copy IO operations, to get a * handle on the memory by some means other than accesses via the user virtual @@ -965,18 +963,12 @@ EXPORT_SYMBOL(get_user_pages_unlocked); */ long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, + unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas) { - unsigned int flags = FOLL_TOUCH | FOLL_REMOTE; - - if (write) - flags |= FOLL_WRITE; - if (force) - flags |= FOLL_FORCE; - return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas, - NULL, false, flags); + NULL, false, + gup_flags | FOLL_TOUCH | FOLL_REMOTE); } EXPORT_SYMBOL(get_user_pages_remote); diff --git a/mm/memory.c b/mm/memory.c index fc1987dfd8cc7..20a9adb7b36ea 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3873,6 +3873,10 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, { struct vm_area_struct *vma; void *old_buf = buf; + unsigned int flags = FOLL_FORCE; + + if (write) + flags |= FOLL_WRITE; down_read(&mm->mmap_sem); /* ignore errors, just check how much was successfully transferred */ @@ -3882,7 +3886,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, struct page *page = NULL; ret = get_user_pages_remote(tsk, mm, addr, 1, - write, 1, &page, &vma); + flags, &page, &vma); if (ret <= 0) { #ifndef CONFIG_HAVE_IOREMAP_PROT break; diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index ade7c6cad172a..682b73af77661 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, * the execve(). */ if (get_user_pages_remote(current, bprm->mm, pos, 1, - 0, 1, &page, NULL) <= 0) + FOLL_FORCE, &page, NULL) <= 0) return false; #else page = bprm->page[pos / PAGE_SIZE]; -- GitLab From 442486ec1096781c50227b73f721a63974b0fdda Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Thu, 13 Oct 2016 01:20:18 +0100 Subject: [PATCH 0766/1167] mm: replace __access_remote_vm() write parameter with gup_flags This removes the 'write' argument from __access_remote_vm() and replaces it with 'gup_flags' as use of this function previously silently implied FOLL_FORCE, whereas after this patch callers explicitly pass this flag. We make this explicit as use of FOLL_FORCE can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes Acked-by: Michal Hocko Signed-off-by: Linus Torvalds --- mm/memory.c | 23 +++++++++++++++-------- mm/nommu.c | 9 ++++++--- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 20a9adb7b36ea..79ebed3a4c2b3 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3869,14 +3869,11 @@ EXPORT_SYMBOL_GPL(generic_access_phys); * given task for page fault accounting. */ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, - unsigned long addr, void *buf, int len, int write) + unsigned long addr, void *buf, int len, unsigned int gup_flags) { struct vm_area_struct *vma; void *old_buf = buf; - unsigned int flags = FOLL_FORCE; - - if (write) - flags |= FOLL_WRITE; + int write = gup_flags & FOLL_WRITE; down_read(&mm->mmap_sem); /* ignore errors, just check how much was successfully transferred */ @@ -3886,7 +3883,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, struct page *page = NULL; ret = get_user_pages_remote(tsk, mm, addr, 1, - flags, &page, &vma); + gup_flags, &page, &vma); if (ret <= 0) { #ifndef CONFIG_HAVE_IOREMAP_PROT break; @@ -3945,7 +3942,12 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, int access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, int len, int write) { - return __access_remote_vm(NULL, mm, addr, buf, len, write); + unsigned int flags = FOLL_FORCE; + + if (write) + flags |= FOLL_WRITE; + + return __access_remote_vm(NULL, mm, addr, buf, len, flags); } /* @@ -3958,12 +3960,17 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, { struct mm_struct *mm; int ret; + unsigned int flags = FOLL_FORCE; mm = get_task_mm(tsk); if (!mm) return 0; - ret = __access_remote_vm(tsk, mm, addr, buf, len, write); + if (write) + flags |= FOLL_WRITE; + + ret = __access_remote_vm(tsk, mm, addr, buf, len, flags); + mmput(mm); return ret; diff --git a/mm/nommu.c b/mm/nommu.c index 70cb844dfd955..bde7df35118bd 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1809,9 +1809,10 @@ void filemap_map_pages(struct fault_env *fe, EXPORT_SYMBOL(filemap_map_pages); static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, - unsigned long addr, void *buf, int len, int write) + unsigned long addr, void *buf, int len, unsigned int gup_flags) { struct vm_area_struct *vma; + int write = gup_flags & FOLL_WRITE; down_read(&mm->mmap_sem); @@ -1853,7 +1854,8 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, int access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, int len, int write) { - return __access_remote_vm(NULL, mm, addr, buf, len, write); + return __access_remote_vm(NULL, mm, addr, buf, len, + write ? FOLL_WRITE : 0); } /* @@ -1871,7 +1873,8 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in if (!mm) return 0; - len = __access_remote_vm(tsk, mm, addr, buf, len, write); + len = __access_remote_vm(tsk, mm, addr, buf, len, + write ? FOLL_WRITE : 0); mmput(mm); return len; -- GitLab From 6347e8d5bcce33fc36e651901efefbe2c93a43ef Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Thu, 13 Oct 2016 01:20:19 +0100 Subject: [PATCH 0767/1167] mm: replace access_remote_vm() write parameter with gup_flags This removes the 'write' argument from access_remote_vm() and replaces it with 'gup_flags' as use of this function previously silently implied FOLL_FORCE, whereas after this patch callers explicitly pass this flag. We make this explicit as use of FOLL_FORCE can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes Acked-by: Michal Hocko Signed-off-by: Linus Torvalds --- fs/proc/base.c | 19 +++++++++++++------ include/linux/mm.h | 2 +- mm/memory.c | 11 +++-------- mm/nommu.c | 7 +++---- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index c2964d890c9a5..8e654468ab676 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -252,7 +252,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, * Inherently racy -- command line shares address space * with code and data. */ - rv = access_remote_vm(mm, arg_end - 1, &c, 1, 0); + rv = access_remote_vm(mm, arg_end - 1, &c, 1, FOLL_FORCE); if (rv <= 0) goto out_free_page; @@ -270,7 +270,8 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, int nr_read; _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, 0); + nr_read = access_remote_vm(mm, p, page, _count, + FOLL_FORCE); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) @@ -305,7 +306,8 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, bool final; _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, 0); + nr_read = access_remote_vm(mm, p, page, _count, + FOLL_FORCE); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) @@ -354,7 +356,8 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, bool final; _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, 0); + nr_read = access_remote_vm(mm, p, page, _count, + FOLL_FORCE); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) @@ -832,6 +835,7 @@ static ssize_t mem_rw(struct file *file, char __user *buf, unsigned long addr = *ppos; ssize_t copied; char *page; + unsigned int flags = FOLL_FORCE; if (!mm) return 0; @@ -844,6 +848,9 @@ static ssize_t mem_rw(struct file *file, char __user *buf, if (!atomic_inc_not_zero(&mm->mm_users)) goto free; + if (write) + flags |= FOLL_WRITE; + while (count > 0) { int this_len = min_t(int, count, PAGE_SIZE); @@ -852,7 +859,7 @@ static ssize_t mem_rw(struct file *file, char __user *buf, break; } - this_len = access_remote_vm(mm, addr, page, this_len, write); + this_len = access_remote_vm(mm, addr, page, this_len, flags); if (!this_len) { if (!copied) copied = -EIO; @@ -965,7 +972,7 @@ static ssize_t environ_read(struct file *file, char __user *buf, this_len = min(max_len, this_len); retval = access_remote_vm(mm, (env_start + src), - page, this_len, 0); + page, this_len, FOLL_FORCE); if (retval <= 0) { ret = retval; diff --git a/include/linux/mm.h b/include/linux/mm.h index ecc4be7b67e05..f31bf90585875 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1268,7 +1268,7 @@ static inline int fixup_user_fault(struct task_struct *tsk, extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, - void *buf, int len, int write); + void *buf, int len, unsigned int gup_flags); long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, diff --git a/mm/memory.c b/mm/memory.c index 79ebed3a4c2b3..bac2d994850ec 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3935,19 +3935,14 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, * @addr: start address to access * @buf: source or destination buffer * @len: number of bytes to transfer - * @write: whether the access is a write + * @gup_flags: flags modifying lookup behaviour * * The caller must hold a reference on @mm. */ int access_remote_vm(struct mm_struct *mm, unsigned long addr, - void *buf, int len, int write) + void *buf, int len, unsigned int gup_flags) { - unsigned int flags = FOLL_FORCE; - - if (write) - flags |= FOLL_WRITE; - - return __access_remote_vm(NULL, mm, addr, buf, len, flags); + return __access_remote_vm(NULL, mm, addr, buf, len, gup_flags); } /* diff --git a/mm/nommu.c b/mm/nommu.c index bde7df35118bd..93d5bb53fc639 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1847,15 +1847,14 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, * @addr: start address to access * @buf: source or destination buffer * @len: number of bytes to transfer - * @write: whether the access is a write + * @gup_flags: flags modifying lookup behaviour * * The caller must hold a reference on @mm. */ int access_remote_vm(struct mm_struct *mm, unsigned long addr, - void *buf, int len, int write) + void *buf, int len, unsigned int gup_flags) { - return __access_remote_vm(NULL, mm, addr, buf, len, - write ? FOLL_WRITE : 0); + return __access_remote_vm(NULL, mm, addr, buf, len, gup_flags); } /* -- GitLab From 82454581d76ccb95535ba6898b39ac5baa123633 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 18 Oct 2016 13:24:07 -0700 Subject: [PATCH 0768/1167] tcp: do not export sysctl_tcp_low_latency Since commit b2fb4f54ecd4 ("tcp: uninline tcp_prequeue()") we no longer access sysctl_tcp_low_latency from a module. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 79d55eb3ec3f1..61b7be303eeca 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -86,7 +86,6 @@ int sysctl_tcp_tw_reuse __read_mostly; int sysctl_tcp_low_latency __read_mostly; -EXPORT_SYMBOL(sysctl_tcp_low_latency); #ifdef CONFIG_TCP_MD5SIG static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, -- GitLab From 137baabe351e0554d06c6d5c84059fe343e2791e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 15:47:39 +0000 Subject: [PATCH 0769/1167] mm/numa: Remove duplicated include from mprotect.c Signed-off-by: Wei Yongjun Cc: Dave Hansen Cc: linux-mm@kvack.org Cc: Andrew Morton Cc: Mel Gorman Cc: "Kirill A. Shutemov" Link: http://lkml.kernel.org/r/1476719259-6214-1-git-send-email-weiyj.lk@gmail.com Signed-off-by: Thomas Gleixner --- mm/mprotect.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mm/mprotect.c b/mm/mprotect.c index bcdbe62f3e6da..11936526b08b8 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include -- GitLab From f307ab6dcea03f9d8e4d70508fd7d1ca57cfa7f9 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Thu, 13 Oct 2016 01:20:20 +0100 Subject: [PATCH 0770/1167] mm: replace access_process_vm() write parameter with gup_flags This removes the 'write' argument from access_process_vm() and replaces it with 'gup_flags' as use of this function previously silently implied FOLL_FORCE, whereas after this patch callers explicitly pass this flag. We make this explicit as use of FOLL_FORCE can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes Acked-by: Jesper Nilsson Acked-by: Michal Hocko Acked-by: Michael Ellerman Signed-off-by: Linus Torvalds --- arch/alpha/kernel/ptrace.c | 9 ++++++--- arch/blackfin/kernel/ptrace.c | 5 +++-- arch/cris/arch-v32/kernel/ptrace.c | 4 ++-- arch/ia64/kernel/ptrace.c | 14 +++++++++----- arch/m32r/kernel/ptrace.c | 15 ++++++++++----- arch/mips/kernel/ptrace32.c | 5 +++-- arch/powerpc/kernel/ptrace32.c | 5 +++-- arch/score/kernel/ptrace.c | 10 ++++++---- arch/sparc/kernel/ptrace_64.c | 24 ++++++++++++++++-------- arch/x86/kernel/step.c | 3 ++- arch/x86/um/ptrace_32.c | 3 ++- arch/x86/um/ptrace_64.c | 3 ++- include/linux/mm.h | 3 ++- kernel/ptrace.c | 16 ++++++++++------ mm/memory.c | 8 ++------ mm/nommu.c | 6 +++--- mm/util.c | 5 +++-- 17 files changed, 84 insertions(+), 54 deletions(-) diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index d9ee81769899f..940dfb4065910 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -157,14 +157,16 @@ put_reg(struct task_struct *task, unsigned long regno, unsigned long data) static inline int read_int(struct task_struct *task, unsigned long addr, int * data) { - int copied = access_process_vm(task, addr, data, sizeof(int), 0); + int copied = access_process_vm(task, addr, data, sizeof(int), + FOLL_FORCE); return (copied == sizeof(int)) ? 0 : -EIO; } static inline int write_int(struct task_struct *task, unsigned long addr, int data) { - int copied = access_process_vm(task, addr, &data, sizeof(int), 1); + int copied = access_process_vm(task, addr, &data, sizeof(int), + FOLL_FORCE | FOLL_WRITE); return (copied == sizeof(int)) ? 0 : -EIO; } @@ -281,7 +283,8 @@ long arch_ptrace(struct task_struct *child, long request, /* When I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), + FOLL_FORCE); ret = -EIO; if (copied != sizeof(tmp)) break; diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 8b8fe671b1a6d..8d79286ee4e87 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -271,7 +271,7 @@ long arch_ptrace(struct task_struct *child, long request, case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: copied = access_process_vm(child, addr, &tmp, - to_copy, 0); + to_copy, FOLL_FORCE); if (copied) break; @@ -324,7 +324,8 @@ long arch_ptrace(struct task_struct *child, long request, case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: copied = access_process_vm(child, addr, &data, - to_copy, 1); + to_copy, + FOLL_FORCE | FOLL_WRITE); break; case BFIN_MEM_ACCESS_DMA: if (safe_dma_memcpy(paddr, &data, to_copy)) diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c index f085229cf870b..f0df654ac6fc5 100644 --- a/arch/cris/arch-v32/kernel/ptrace.c +++ b/arch/cris/arch-v32/kernel/ptrace.c @@ -147,7 +147,7 @@ long arch_ptrace(struct task_struct *child, long request, /* The trampoline page is globally mapped, no page table to traverse.*/ tmp = *(unsigned long*)addr; } else { - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), FOLL_FORCE); if (copied != sizeof(tmp)) break; @@ -279,7 +279,7 @@ static int insn_size(struct task_struct *child, unsigned long pc) int opsize = 0; /* Read the opcode at pc (do what PTRACE_PEEKTEXT would do). */ - copied = access_process_vm(child, pc, &opcode, sizeof(opcode), 0); + copied = access_process_vm(child, pc, &opcode, sizeof(opcode), FOLL_FORCE); if (copied != sizeof(opcode)) return 0; diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 6f54d511cc509..31aa8c0f68e14 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -453,7 +453,7 @@ ia64_peek (struct task_struct *child, struct switch_stack *child_stack, return 0; } } - copied = access_process_vm(child, addr, &ret, sizeof(ret), 0); + copied = access_process_vm(child, addr, &ret, sizeof(ret), FOLL_FORCE); if (copied != sizeof(ret)) return -EIO; *val = ret; @@ -489,7 +489,8 @@ ia64_poke (struct task_struct *child, struct switch_stack *child_stack, *ia64_rse_skip_regs(krbs, regnum) = val; } } - } else if (access_process_vm(child, addr, &val, sizeof(val), 1) + } else if (access_process_vm(child, addr, &val, sizeof(val), + FOLL_FORCE | FOLL_WRITE) != sizeof(val)) return -EIO; return 0; @@ -543,7 +544,8 @@ ia64_sync_user_rbs (struct task_struct *child, struct switch_stack *sw, ret = ia64_peek(child, sw, user_rbs_end, addr, &val); if (ret < 0) return ret; - if (access_process_vm(child, addr, &val, sizeof(val), 1) + if (access_process_vm(child, addr, &val, sizeof(val), + FOLL_FORCE | FOLL_WRITE) != sizeof(val)) return -EIO; } @@ -559,7 +561,8 @@ ia64_sync_kernel_rbs (struct task_struct *child, struct switch_stack *sw, /* now copy word for word from user rbs to kernel rbs: */ for (addr = user_rbs_start; addr < user_rbs_end; addr += 8) { - if (access_process_vm(child, addr, &val, sizeof(val), 0) + if (access_process_vm(child, addr, &val, sizeof(val), + FOLL_FORCE) != sizeof(val)) return -EIO; @@ -1156,7 +1159,8 @@ arch_ptrace (struct task_struct *child, long request, case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr */ - if (access_process_vm(child, addr, &data, sizeof(data), 0) + if (access_process_vm(child, addr, &data, sizeof(data), + FOLL_FORCE) != sizeof(data)) return -EIO; /* ensure return value is not mistaken for error code */ diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c index 51f5e9aa49016..c145605a981ff 100644 --- a/arch/m32r/kernel/ptrace.c +++ b/arch/m32r/kernel/ptrace.c @@ -493,7 +493,8 @@ unregister_all_debug_traps(struct task_struct *child) int i; for (i = 0; i < p->nr_trap; i++) - access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]), 1); + access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]), + FOLL_FORCE | FOLL_WRITE); p->nr_trap = 0; } @@ -537,7 +538,8 @@ embed_debug_trap(struct task_struct *child, unsigned long next_pc) unsigned long next_insn, code; unsigned long addr = next_pc & ~3; - if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), 0) + if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), + FOLL_FORCE) != sizeof(next_insn)) { return -1; /* error */ } @@ -546,7 +548,8 @@ embed_debug_trap(struct task_struct *child, unsigned long next_pc) if (register_debug_trap(child, next_pc, next_insn, &code)) { return -1; /* error */ } - if (access_process_vm(child, addr, &code, sizeof(code), 1) + if (access_process_vm(child, addr, &code, sizeof(code), + FOLL_FORCE | FOLL_WRITE) != sizeof(code)) { return -1; /* error */ } @@ -562,7 +565,8 @@ withdraw_debug_trap(struct pt_regs *regs) addr = (regs->bpc - 2) & ~3; regs->bpc -= 2; if (unregister_debug_trap(current, addr, &code)) { - access_process_vm(current, addr, &code, sizeof(code), 1); + access_process_vm(current, addr, &code, sizeof(code), + FOLL_FORCE | FOLL_WRITE); invalidate_cache(); } } @@ -589,7 +593,8 @@ void user_enable_single_step(struct task_struct *child) /* Compute next pc. */ pc = get_stack_long(child, PT_BPC); - if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0) + if (access_process_vm(child, pc&~3, &insn, sizeof(insn), + FOLL_FORCE) != sizeof(insn)) return; diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 283b5a1967d14..7e71a4e0281ba 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -70,7 +70,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, break; copied = access_process_vm(child, (u64)addrOthers, &tmp, - sizeof(tmp), 0); + sizeof(tmp), FOLL_FORCE); if (copied != sizeof(tmp)) break; ret = put_user(tmp, (u32 __user *) (unsigned long) data); @@ -179,7 +179,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, break; ret = 0; if (access_process_vm(child, (u64)addrOthers, &data, - sizeof(data), 1) == sizeof(data)) + sizeof(data), + FOLL_FORCE | FOLL_WRITE) == sizeof(data)) break; ret = -EIO; break; diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index f52b7db327c80..010b7b310237e 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -74,7 +74,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, break; copied = access_process_vm(child, (u64)addrOthers, &tmp, - sizeof(tmp), 0); + sizeof(tmp), FOLL_FORCE); if (copied != sizeof(tmp)) break; ret = put_user(tmp, (u32 __user *)data); @@ -179,7 +179,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, break; ret = 0; if (access_process_vm(child, (u64)addrOthers, &tmp, - sizeof(tmp), 1) == sizeof(tmp)) + sizeof(tmp), + FOLL_FORCE | FOLL_WRITE) == sizeof(tmp)) break; ret = -EIO; break; diff --git a/arch/score/kernel/ptrace.c b/arch/score/kernel/ptrace.c index 55836188b217c..4f7314d5f3347 100644 --- a/arch/score/kernel/ptrace.c +++ b/arch/score/kernel/ptrace.c @@ -131,7 +131,7 @@ read_tsk_long(struct task_struct *child, { int copied; - copied = access_process_vm(child, addr, res, sizeof(*res), 0); + copied = access_process_vm(child, addr, res, sizeof(*res), FOLL_FORCE); return copied != sizeof(*res) ? -EIO : 0; } @@ -142,7 +142,7 @@ read_tsk_short(struct task_struct *child, { int copied; - copied = access_process_vm(child, addr, res, sizeof(*res), 0); + copied = access_process_vm(child, addr, res, sizeof(*res), FOLL_FORCE); return copied != sizeof(*res) ? -EIO : 0; } @@ -153,7 +153,8 @@ write_tsk_short(struct task_struct *child, { int copied; - copied = access_process_vm(child, addr, &val, sizeof(val), 1); + copied = access_process_vm(child, addr, &val, sizeof(val), + FOLL_FORCE | FOLL_WRITE); return copied != sizeof(val) ? -EIO : 0; } @@ -164,7 +165,8 @@ write_tsk_long(struct task_struct *child, { int copied; - copied = access_process_vm(child, addr, &val, sizeof(val), 1); + copied = access_process_vm(child, addr, &val, sizeof(val), + FOLL_FORCE | FOLL_WRITE); return copied != sizeof(val) ? -EIO : 0; } diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index 9ddc4928a089b..ac082dd8c67d5 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c @@ -127,7 +127,8 @@ static int get_from_target(struct task_struct *target, unsigned long uaddr, if (copy_from_user(kbuf, (void __user *) uaddr, len)) return -EFAULT; } else { - int len2 = access_process_vm(target, uaddr, kbuf, len, 0); + int len2 = access_process_vm(target, uaddr, kbuf, len, + FOLL_FORCE); if (len2 != len) return -EFAULT; } @@ -141,7 +142,8 @@ static int set_to_target(struct task_struct *target, unsigned long uaddr, if (copy_to_user((void __user *) uaddr, kbuf, len)) return -EFAULT; } else { - int len2 = access_process_vm(target, uaddr, kbuf, len, 1); + int len2 = access_process_vm(target, uaddr, kbuf, len, + FOLL_FORCE | FOLL_WRITE); if (len2 != len) return -EFAULT; } @@ -505,7 +507,8 @@ static int genregs32_get(struct task_struct *target, if (access_process_vm(target, (unsigned long) ®_window[pos], - k, sizeof(*k), 0) + k, sizeof(*k), + FOLL_FORCE) != sizeof(*k)) return -EFAULT; k++; @@ -531,12 +534,14 @@ static int genregs32_get(struct task_struct *target, if (access_process_vm(target, (unsigned long) ®_window[pos], - ®, sizeof(reg), 0) + ®, sizeof(reg), + FOLL_FORCE) != sizeof(reg)) return -EFAULT; if (access_process_vm(target, (unsigned long) u, - ®, sizeof(reg), 1) + ®, sizeof(reg), + FOLL_FORCE | FOLL_WRITE) != sizeof(reg)) return -EFAULT; pos++; @@ -615,7 +620,8 @@ static int genregs32_set(struct task_struct *target, (unsigned long) ®_window[pos], (void *) k, - sizeof(*k), 1) + sizeof(*k), + FOLL_FORCE | FOLL_WRITE) != sizeof(*k)) return -EFAULT; k++; @@ -642,13 +648,15 @@ static int genregs32_set(struct task_struct *target, if (access_process_vm(target, (unsigned long) u, - ®, sizeof(reg), 0) + ®, sizeof(reg), + FOLL_FORCE) != sizeof(reg)) return -EFAULT; if (access_process_vm(target, (unsigned long) ®_window[pos], - ®, sizeof(reg), 1) + ®, sizeof(reg), + FOLL_FORCE | FOLL_WRITE) != sizeof(reg)) return -EFAULT; pos++; diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index c9a073866ca7b..a23ce84a3f6cc 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c @@ -57,7 +57,8 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs) unsigned char opcode[15]; unsigned long addr = convert_ip_to_linear(child, regs); - copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0); + copied = access_process_vm(child, addr, opcode, sizeof(opcode), + FOLL_FORCE); for (i = 0; i < copied; i++) { switch (opcode[i]) { /* popf and iret */ diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c index 5766ead6fdb96..60a5a5a85505d 100644 --- a/arch/x86/um/ptrace_32.c +++ b/arch/x86/um/ptrace_32.c @@ -36,7 +36,8 @@ int is_syscall(unsigned long addr) * slow, but that doesn't matter, since it will be called only * in case of singlestepping, if copy_from_user failed. */ - n = access_process_vm(current, addr, &instr, sizeof(instr), 0); + n = access_process_vm(current, addr, &instr, sizeof(instr), + FOLL_FORCE); if (n != sizeof(instr)) { printk(KERN_ERR "is_syscall : failed to read " "instruction from 0x%lx\n", addr); diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c index 0b5c184dd5b3b..e30202b1716ef 100644 --- a/arch/x86/um/ptrace_64.c +++ b/arch/x86/um/ptrace_64.c @@ -212,7 +212,8 @@ int is_syscall(unsigned long addr) * slow, but that doesn't matter, since it will be called only * in case of singlestepping, if copy_from_user failed. */ - n = access_process_vm(current, addr, &instr, sizeof(instr), 0); + n = access_process_vm(current, addr, &instr, sizeof(instr), + FOLL_FORCE); if (n != sizeof(instr)) { printk("is_syscall : failed to read instruction from " "0x%lx\n", addr); diff --git a/include/linux/mm.h b/include/linux/mm.h index f31bf90585875..ffbd72979ee70 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1266,7 +1266,8 @@ static inline int fixup_user_fault(struct task_struct *tsk, } #endif -extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); +extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, + unsigned int gup_flags); extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, int len, unsigned int gup_flags); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 2a99027312a6a..e6474f7272ec2 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -537,7 +537,7 @@ int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst int this_len, retval; this_len = (len > sizeof(buf)) ? sizeof(buf) : len; - retval = access_process_vm(tsk, src, buf, this_len, 0); + retval = access_process_vm(tsk, src, buf, this_len, FOLL_FORCE); if (!retval) { if (copied) break; @@ -564,7 +564,8 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds this_len = (len > sizeof(buf)) ? sizeof(buf) : len; if (copy_from_user(buf, src, this_len)) return -EFAULT; - retval = access_process_vm(tsk, dst, buf, this_len, 1); + retval = access_process_vm(tsk, dst, buf, this_len, + FOLL_FORCE | FOLL_WRITE); if (!retval) { if (copied) break; @@ -1127,7 +1128,7 @@ int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, unsigned long tmp; int copied; - copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0); + copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), FOLL_FORCE); if (copied != sizeof(tmp)) return -EIO; return put_user(tmp, (unsigned long __user *)data); @@ -1138,7 +1139,8 @@ int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, { int copied; - copied = access_process_vm(tsk, addr, &data, sizeof(data), 1); + copied = access_process_vm(tsk, addr, &data, sizeof(data), + FOLL_FORCE | FOLL_WRITE); return (copied == sizeof(data)) ? 0 : -EIO; } @@ -1155,7 +1157,8 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: - ret = access_process_vm(child, addr, &word, sizeof(word), 0); + ret = access_process_vm(child, addr, &word, sizeof(word), + FOLL_FORCE); if (ret != sizeof(word)) ret = -EIO; else @@ -1164,7 +1167,8 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, case PTRACE_POKETEXT: case PTRACE_POKEDATA: - ret = access_process_vm(child, addr, &data, sizeof(data), 1); + ret = access_process_vm(child, addr, &data, sizeof(data), + FOLL_FORCE | FOLL_WRITE); ret = (ret != sizeof(data) ? -EIO : 0); break; diff --git a/mm/memory.c b/mm/memory.c index bac2d994850ec..e18c57bdc75c4 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3951,20 +3951,16 @@ int access_remote_vm(struct mm_struct *mm, unsigned long addr, * Do not walk the page table directly, use get_user_pages */ int access_process_vm(struct task_struct *tsk, unsigned long addr, - void *buf, int len, int write) + void *buf, int len, unsigned int gup_flags) { struct mm_struct *mm; int ret; - unsigned int flags = FOLL_FORCE; mm = get_task_mm(tsk); if (!mm) return 0; - if (write) - flags |= FOLL_WRITE; - - ret = __access_remote_vm(tsk, mm, addr, buf, len, flags); + ret = __access_remote_vm(tsk, mm, addr, buf, len, gup_flags); mmput(mm); diff --git a/mm/nommu.c b/mm/nommu.c index 93d5bb53fc639..db5fd17952987 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1861,7 +1861,8 @@ int access_remote_vm(struct mm_struct *mm, unsigned long addr, * Access another process' address space. * - source/target buffer must be kernel space */ -int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) +int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, + unsigned int gup_flags) { struct mm_struct *mm; @@ -1872,8 +1873,7 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in if (!mm) return 0; - len = __access_remote_vm(tsk, mm, addr, buf, len, - write ? FOLL_WRITE : 0); + len = __access_remote_vm(tsk, mm, addr, buf, len, gup_flags); mmput(mm); return len; diff --git a/mm/util.c b/mm/util.c index 4c685bde5ebc0..952cbe7ad7b75 100644 --- a/mm/util.c +++ b/mm/util.c @@ -624,7 +624,7 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen) if (len > buflen) len = buflen; - res = access_process_vm(task, arg_start, buffer, len, 0); + res = access_process_vm(task, arg_start, buffer, len, FOLL_FORCE); /* * If the nul at the end of args has been overwritten, then @@ -639,7 +639,8 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen) if (len > buflen - res) len = buflen - res; res += access_process_vm(task, env_start, - buffer+res, len, 0); + buffer+res, len, + FOLL_FORCE); res = strnlen(buffer, res); } } -- GitLab From 854dd54245f7f1b1175b1bada613929396a571be Mon Sep 17 00:00:00 2001 From: Renat Valiullin Date: Thu, 13 Oct 2016 11:45:39 -0700 Subject: [PATCH 0771/1167] x86/vmware: Skip timer_irq_works() check on VMware The timer_irq_works() boot check may sometimes fail in a VM, when the Host is overcommitted or when the Guest is running nested. Since the intended check is unnecessary on VMware's virtual hardware, by-pass it. Signed-off-by: Renat Valiullin Acked-by: Alok N Kataria Cc: virtualization@lists.linux-foundation.org Link: http://lkml.kernel.org/r/20161013184539.GA11497@rvaliullin-vm Signed-off-by: Thomas Gleixner --- arch/x86/kernel/cpu/vmware.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index 81160578b91ac..5130985b758b9 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #define CPUID_VMWARE_INFO_LEAF 0x40000000 @@ -94,6 +95,10 @@ static void __init vmware_platform_setup(void) } else { pr_warn("Failed to get TSC freq from the hypervisor\n"); } + +#ifdef CONFIG_X86_IO_APIC + no_timer_check = 1; +#endif } /* -- GitLab From 8214899342981dbd49ae24aadbbd19e9e7830684 Mon Sep 17 00:00:00 2001 From: Piotr Luc Date: Tue, 18 Oct 2016 17:01:11 +0200 Subject: [PATCH 0772/1167] x86/cpufeature: Add AVX512_4VNNIW and AVX512_4FMAPS features AVX512_4VNNIW - Vector instructions for deep learning enhanced word variable precision. AVX512_4FMAPS - Vector instructions for deep learning floating-point single precision. These new instructions are to be used in future Intel Xeon & Xeon Phi processors. The bits 2&3 of CPUID[level:0x07, EDX] inform that new instructions are supported by a processor. The spec can be found in the Intel Software Developer Manual (SDM) or in the Instruction Set Extensions Programming Reference (ISE). Define new feature flags to enumerate the new instructions in /proc/cpuinfo accordingly to CPUID bits and add the required xsave extensions which are required for proper operation. Signed-off-by: Piotr Luc Cc: Denys Vlasenko Cc: Peter Zijlstra Cc: Brian Gerst Cc: Dave Hansen Cc: Borislav Petkov Cc: Andy Lutomirski Cc: Josh Poimboeuf Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20161018150111.29926-1-piotr.luc@intel.com Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/cpufeatures.h | 2 ++ arch/x86/kernel/cpu/scattered.c | 2 ++ arch/x86/kernel/fpu/xstate.c | 2 ++ tools/arch/x86/include/asm/cpufeatures.h | 2 ++ 4 files changed, 8 insertions(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 1188bc849ee3b..a39629206864e 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -194,6 +194,8 @@ #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ #define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */ +#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */ +#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index 8cb57df9398d9..1db8dc490b665 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -32,6 +32,8 @@ void init_scattered_cpuid_features(struct cpuinfo_x86 *c) static const struct cpuid_bit cpuid_bits[] = { { X86_FEATURE_INTEL_PT, CR_EBX,25, 0x00000007, 0 }, + { X86_FEATURE_AVX512_4VNNIW, CR_EDX, 2, 0x00000007, 0 }, + { X86_FEATURE_AVX512_4FMAPS, CR_EDX, 3, 0x00000007, 0 }, { X86_FEATURE_APERFMPERF, CR_ECX, 0, 0x00000006, 0 }, { X86_FEATURE_EPB, CR_ECX, 3, 0x00000006, 0 }, { X86_FEATURE_HW_PSTATE, CR_EDX, 7, 0x80000007, 0 }, diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 124aa5c593f8d..095ef7ddd6ae4 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -74,6 +74,8 @@ void fpu__xstate_clear_all_cpu_caps(void) setup_clear_cpu_cap(X86_FEATURE_MPX); setup_clear_cpu_cap(X86_FEATURE_XGETBV1); setup_clear_cpu_cap(X86_FEATURE_PKU); + setup_clear_cpu_cap(X86_FEATURE_AVX512_4VNNIW); + setup_clear_cpu_cap(X86_FEATURE_AVX512_4FMAPS); } /* diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 1188bc849ee3b..a39629206864e 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -194,6 +194,8 @@ #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ #define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */ +#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */ +#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ -- GitLab From 8835ca59dac2bc1e0136791abf3ccd51588803ce Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 19 Oct 2016 09:11:24 -0700 Subject: [PATCH 0773/1167] printk: suppress empty continuation lines We have a fairly common pattern where you print several things as continuations on one single line in a loop, and then at the end you do printk(KERN_CONT "\n"); to flush the buffered output. But if the output was flushed by something else (concurrent printk activity, or just system logging), we don't want that final flushing to just print an empty line. So just suppress empty continuation lines when they couldn't be merged into the line they are a continuation of. Signed-off-by: Linus Torvalds --- kernel/printk/printk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index d5e3973154739..de08fc90baafa 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1769,6 +1769,10 @@ static size_t log_output(int facility, int level, enum log_flags lflags, const c cont_flush(); } + /* Skip empty continuation lines that couldn't be added - they just flush */ + if (!text_len && (lflags & LOG_CONT)) + return 0; + /* If it doesn't end in a newline, try to buffer the current line */ if (!(lflags & LOG_NEWLINE)) { if (cont_add(facility, level, lflags, text, text_len)) -- GitLab From 1ecc281ec2f52d715dfc8cb67b6820ea813b9e52 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 17 Oct 2016 21:50:23 +0200 Subject: [PATCH 0774/1167] netfilter: x_tables: suppress kmemcheck warning Markus Trippelsdorf reports: WARNING: kmemcheck: Caught 64-bit read from uninitialized memory (ffff88001e605480) 4055601e0088ffff000000000000000090686d81ffffffff0000000000000000 u u u u u u u u u u u u u u u u i i i i i i i i u u u u u u u u ^ |RIP: 0010:[] [] nf_register_net_hook+0x51/0x160 [..] [] nf_register_net_hook+0x51/0x160 [] nf_register_net_hooks+0x3f/0xa0 [] ipt_register_table+0xe5/0x110 [..] This warning is harmless; we copy 'uninitialized' data from the hook ops but it will not be used. Long term the structures keeping run-time data should be disentangled from those only containing config-time data (such as where in the list to insert a hook), but thats -next material. Reported-by: Markus Trippelsdorf Suggested-by: Al Viro Signed-off-by: Florian Westphal Acked-by: Aaron Conole Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index e0aa7c1d02241..fc4977456c30e 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1513,7 +1513,7 @@ xt_hook_ops_alloc(const struct xt_table *table, nf_hookfn *fn) if (!num_hooks) return ERR_PTR(-EINVAL); - ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL); + ops = kcalloc(num_hooks, sizeof(*ops), GFP_KERNEL); if (ops == NULL) return ERR_PTR(-ENOMEM); -- GitLab From f61851f64b171a684f5a1fa78325756dbbaadadc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Narajowski?= Date: Wed, 19 Oct 2016 10:20:27 +0200 Subject: [PATCH 0775/1167] Bluetooth: Fix append max 11 bytes of name to scan rsp data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Append maximum of 10 + 1 bytes of name to scan response data. Complete name is appended only if exists and is <= 10 characters. Else append short name if exists or shorten complete name if not. This makes sure name is consistent across multiple advertising instances. Signed-off-by: Michał Narajowski Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_request.c | 49 +++++++++++++++++-------------------- net/bluetooth/hci_request.h | 2 ++ net/bluetooth/mgmt.c | 26 +++++++++++++------- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index e2288421fe6b7..1015d9c8d97dd 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -969,41 +969,38 @@ void __hci_req_enable_advertising(struct hci_request *req) hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); } -static u8 append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len) +u8 append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len) { - size_t complete_len; size_t short_len; - int max_len; - - max_len = HCI_MAX_AD_LENGTH - ad_len - 2; - complete_len = strlen(hdev->dev_name); - short_len = strlen(hdev->short_name); - - /* no space left for name */ - if (max_len < 1) - return ad_len; + size_t complete_len; - /* no name set */ - if (!complete_len) + /* no space left for name (+ NULL + type + len) */ + if ((HCI_MAX_AD_LENGTH - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 3) return ad_len; - /* complete name fits and is eq to max short name len or smaller */ - if (complete_len <= max_len && - complete_len <= HCI_MAX_SHORT_NAME_LENGTH) { + /* use complete name if present and fits */ + complete_len = strlen(hdev->dev_name); + if (complete_len && complete_len <= HCI_MAX_SHORT_NAME_LENGTH) return eir_append_data(ptr, ad_len, EIR_NAME_COMPLETE, - hdev->dev_name, complete_len); - } + hdev->dev_name, complete_len + 1); - /* short name set and fits */ - if (short_len && short_len <= max_len) { + /* use short name if present */ + short_len = strlen(hdev->short_name); + if (short_len) return eir_append_data(ptr, ad_len, EIR_NAME_SHORT, - hdev->short_name, short_len); - } + hdev->short_name, short_len + 1); - /* no short name set so shorten complete name */ - if (!short_len) { - return eir_append_data(ptr, ad_len, EIR_NAME_SHORT, - hdev->dev_name, max_len); + /* use shortened full name if present, we already know that name + * is longer then HCI_MAX_SHORT_NAME_LENGTH + */ + if (complete_len) { + u8 name[HCI_MAX_SHORT_NAME_LENGTH + 1]; + + memcpy(name, hdev->dev_name, HCI_MAX_SHORT_NAME_LENGTH); + name[HCI_MAX_SHORT_NAME_LENGTH] = '\0'; + + return eir_append_data(ptr, ad_len, EIR_NAME_SHORT, name, + sizeof(name)); } return ad_len; diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index 6b06629245a8c..dde77bd59f915 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -106,6 +106,8 @@ static inline void hci_update_background_scan(struct hci_dev *hdev) void hci_request_setup(struct hci_dev *hdev); void hci_request_cancel_all(struct hci_dev *hdev); +u8 append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len); + static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 736038085feb4..1fba2a03f8ae8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6017,7 +6017,15 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev, return err; } -static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data) +static u8 calculate_name_len(struct hci_dev *hdev) +{ + u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3]; + + return append_local_name(hdev, buf, 0); +} + +static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags, + bool is_adv_data) { u8 max_len = HCI_MAX_AD_LENGTH; @@ -6030,9 +6038,8 @@ static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data) if (adv_flags & MGMT_ADV_FLAG_TX_POWER) max_len -= 3; } else { - /* at least 1 byte of name should fit in */ if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME) - max_len -= 3; + max_len -= calculate_name_len(hdev); if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE)) max_len -= 4; @@ -6063,12 +6070,13 @@ static bool appearance_managed(u32 adv_flags) return adv_flags & MGMT_ADV_FLAG_APPEARANCE; } -static bool tlv_data_is_valid(u32 adv_flags, u8 *data, u8 len, bool is_adv_data) +static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + u8 len, bool is_adv_data) { int i, cur_len; u8 max_len; - max_len = tlv_data_max_len(adv_flags, is_adv_data); + max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data); if (len > max_len) return false; @@ -6215,8 +6223,8 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, goto unlock; } - if (!tlv_data_is_valid(flags, cp->data, cp->adv_data_len, true) || - !tlv_data_is_valid(flags, cp->data + cp->adv_data_len, + if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) || + !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len, cp->scan_rsp_len, false)) { err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, MGMT_STATUS_INVALID_PARAMS); @@ -6429,8 +6437,8 @@ static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev, rp.instance = cp->instance; rp.flags = cp->flags; - rp.max_adv_data_len = tlv_data_max_len(flags, true); - rp.max_scan_rsp_len = tlv_data_max_len(flags, false); + rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true); + rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false); err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO, MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); -- GitLab From 3da43104d3187184d7417569cb3360511229f761 Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Wed, 19 Oct 2016 14:25:03 +0300 Subject: [PATCH 0776/1167] ARC: Adjust cpuinfo for non-continuous cpu ids num_possible_cpus() returns how many CPUs may be present on system. However we want the highest possible CPU number. This may be differ in a sparsed possible CPUs map. Such map achived by OF for plat-eznps. For example if we have: possible cpus mask 0,3 Then: num_possible_cpus() is equal 2 while nr_cpu_ids is equal 4. Only for value 4 c_start() will provide correct cpuinfo at procfs. Signed-off-by: Noam Camus Signed-off-by: Vineet Gupta --- arch/arc/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 3df7f9c72f427..75e5409721353 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -507,7 +507,7 @@ static void *c_start(struct seq_file *m, loff_t *pos) * way to pass it w/o having to kmalloc/free a 2 byte string. * Encode cpu-id as 0xFFcccc, which is decoded by show routine. */ - return *pos < num_possible_cpus() ? cpu_to_ptr(*pos) : NULL; + return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL; } static void *c_next(struct seq_file *m, void *v, loff_t *pos) -- GitLab From 17a51f12cfbd2814fd35966a069b242569c53e27 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 18 Oct 2016 09:00:52 +0200 Subject: [PATCH 0777/1167] ahci: only try to use multi-MSI mode if there is more than 1 port We should only try to allocate multiple MSI or MSI-X vectors if the device actually has multiple ports. Otherwise pci_alloc_irq_vectors will return a single vector due to n_ports = 1, in which case we shouldn't set the AHCI_HFLAG_MULTI_MSI flag. Signed-off-by: Christoph Hellwig Fixes: 0b9e2988 ("ahci: use pci_alloc_irq_vectors") Reported-by: Emmanuel Benisty Tested-by: Emmanuel Benisty Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index ba5f11cebee2a..ed311a040fed6 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1418,21 +1418,24 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, * Message mode could be enforced. In this case assume that advantage * of multipe MSIs is negated and use single MSI mode instead. */ - nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX, - PCI_IRQ_MSIX | PCI_IRQ_MSI); - if (nvec > 0) { - if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) { - hpriv->get_irq_vector = ahci_get_irq_vector; - hpriv->flags |= AHCI_HFLAG_MULTI_MSI; - return nvec; - } + if (n_ports > 1) { + nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX, + PCI_IRQ_MSIX | PCI_IRQ_MSI); + if (nvec > 0) { + if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) { + hpriv->get_irq_vector = ahci_get_irq_vector; + hpriv->flags |= AHCI_HFLAG_MULTI_MSI; + return nvec; + } - /* - * Fallback to single MSI mode if the controller enforced MRSM - * mode. - */ - printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n"); - pci_free_irq_vectors(pdev); + /* + * Fallback to single MSI mode if the controller + * enforced MRSM mode. + */ + printk(KERN_INFO + "ahci: MRSM is on, fallback to single MSI\n"); + pci_free_irq_vectors(pdev); + } } /* -- GitLab From 75d29713b792da4782cadfaa87e802183440694e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2016 09:34:29 +0300 Subject: [PATCH 0778/1167] libnvdimm, namespace: potential NULL deref on allocation error If the kcalloc() fails then "devs" can be NULL and we dereference it checking "devs[i]". Fixes: 1b40e09a1232 ('libnvdimm: blk labels and namespace instantiation') Signed-off-by: Dan Carpenter Signed-off-by: Dan Williams --- drivers/nvdimm/namespace_devs.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 3509cff68ef9c..abe5c6bc756c2 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -2176,12 +2176,14 @@ static struct device **scan_labels(struct nd_region *nd_region) return devs; err: - for (i = 0; devs[i]; i++) - if (is_nd_blk(&nd_region->dev)) - namespace_blk_release(devs[i]); - else - namespace_pmem_release(devs[i]); - kfree(devs); + if (devs) { + for (i = 0; devs[i]; i++) + if (is_nd_blk(&nd_region->dev)) + namespace_blk_release(devs[i]); + else + namespace_pmem_release(devs[i]); + kfree(devs); + } return NULL; } -- GitLab From 3115bb02b5c23d960df5f1bf551ec394a9bb10ec Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Thu, 13 Oct 2016 09:54:21 -0600 Subject: [PATCH 0779/1167] pmem: report error on clear poison failure ACPI Clear Uncorrectable Error DSM function may fail or may be unsupported on a platform. pmem_clear_poison() returns without clearing badblocks in such cases. This failure is detected at the next read (-EIO). This behavior can lead to an issue when user keeps writing but does not read immediately. For instance, flight recorder file may be only read when it is necessary for troubleshooting. Change pmem_do_bvec() and pmem_clear_poison() to return -EIO so that filesystem can log an error message on a write error. Cc: Vishal Verma Signed-off-by: Toshi Kani Signed-off-by: Dan Williams --- drivers/nvdimm/pmem.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 42b3a82170733..24618431a14ba 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -47,7 +47,7 @@ static struct nd_region *to_region(struct pmem_device *pmem) return to_nd_region(to_dev(pmem)->parent); } -static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, +static int pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, unsigned int len) { struct device *dev = to_dev(pmem); @@ -62,8 +62,12 @@ static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, __func__, (unsigned long long) sector, cleared / 512, cleared / 512 > 1 ? "s" : ""); badblocks_clear(&pmem->bb, sector, cleared / 512); + } else { + return -EIO; } + invalidate_pmem(pmem->virt_addr + offset, len); + return 0; } static void write_pmem(void *pmem_addr, struct page *page, @@ -123,7 +127,7 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page, flush_dcache_page(page); write_pmem(pmem_addr, page, off, len); if (unlikely(bad_pmem)) { - pmem_clear_poison(pmem, pmem_off, len); + rc = pmem_clear_poison(pmem, pmem_off, len); write_pmem(pmem_addr, page, off, len); } } -- GitLab From 8ef2074d28373014d05e92b5f13364ef51075b6e Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Wed, 19 Oct 2016 09:51:05 -0600 Subject: [PATCH 0780/1167] nvme: Add tertiary number to NVME_VS NVMe 1.2.1 specification adds a tertiary element to the version number. This updates the macro and its callers to include the final number and fixup a single place in nvmet where the version was generated manually. Signed-off-by: Gabriel Krisman Bertazi Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/nvme/host/core.c | 8 ++++---- drivers/nvme/host/pci.c | 4 ++-- drivers/nvme/host/scsi.c | 4 ++-- drivers/nvme/target/core.c | 2 +- include/linux/nvme.h | 3 ++- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 2a57f5ede386c..bb168b71048da 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -900,9 +900,9 @@ static int nvme_revalidate_ns(struct nvme_ns *ns, struct nvme_id_ns **id) return -ENODEV; } - if (ns->ctrl->vs >= NVME_VS(1, 1)) + if (ns->ctrl->vs >= NVME_VS(1, 1, 0)) memcpy(ns->eui, (*id)->eui64, sizeof(ns->eui)); - if (ns->ctrl->vs >= NVME_VS(1, 2)) + if (ns->ctrl->vs >= NVME_VS(1, 2, 0)) memcpy(ns->uuid, (*id)->nguid, sizeof(ns->uuid)); return 0; @@ -1242,7 +1242,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) } page_shift = NVME_CAP_MPSMIN(cap) + 12; - if (ctrl->vs >= NVME_VS(1, 1)) + if (ctrl->vs >= NVME_VS(1, 1, 0)) ctrl->subsystem = NVME_CAP_NSSRC(cap); ret = nvme_identify_ctrl(ctrl, &id); @@ -1842,7 +1842,7 @@ static void nvme_scan_work(struct work_struct *work) return; nn = le32_to_cpu(id->nn); - if (ctrl->vs >= NVME_VS(1, 1) && + if (ctrl->vs >= NVME_VS(1, 1, 0) && !(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)) { if (!nvme_scan_ns_list(ctrl, nn)) goto done; diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index a7c6e9d749434..26a8d31b291dd 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1214,7 +1214,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) u64 cap = lo_hi_readq(dev->bar + NVME_REG_CAP); struct nvme_queue *nvmeq; - dev->subsystem = readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 1) ? + dev->subsystem = readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 1, 0) ? NVME_CAP_NSSRC(cap) : 0; if (dev->subsystem && @@ -1633,7 +1633,7 @@ static int nvme_pci_enable(struct nvme_dev *dev) * NULL as final argument to sysfs_add_file_to_group. */ - if (readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 2)) { + if (readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 2, 0)) { dev->cmb = nvme_map_cmb(dev); if (dev->cmbsz) { diff --git a/drivers/nvme/host/scsi.c b/drivers/nvme/host/scsi.c index c2a0a1c7d05d1..3eaa4d27801ee 100644 --- a/drivers/nvme/host/scsi.c +++ b/drivers/nvme/host/scsi.c @@ -606,7 +606,7 @@ static int nvme_fill_device_id_eui64(struct nvme_ns *ns, struct sg_io_hdr *hdr, eui = id_ns->eui64; len = sizeof(id_ns->eui64); - if (ns->ctrl->vs >= NVME_VS(1, 2)) { + if (ns->ctrl->vs >= NVME_VS(1, 2, 0)) { if (bitmap_empty(eui, len * 8)) { eui = id_ns->nguid; len = sizeof(id_ns->nguid); @@ -679,7 +679,7 @@ static int nvme_trans_device_id_page(struct nvme_ns *ns, struct sg_io_hdr *hdr, { int res; - if (ns->ctrl->vs >= NVME_VS(1, 1)) { + if (ns->ctrl->vs >= NVME_VS(1, 1, 0)) { res = nvme_fill_device_id_eui64(ns, hdr, resp, alloc_len); if (res != -EOPNOTSUPP) return res; diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 6559d5afa7bfd..b4cacb6f02583 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -882,7 +882,7 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn, if (!subsys) return NULL; - subsys->ver = (1 << 16) | (2 << 8) | 1; /* NVMe 1.2.1 */ + subsys->ver = NVME_VS(1, 2, 1); /* NVMe 1.2.1 */ switch (type) { case NVME_NQN_NVME: diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 7676557ce357d..086d196e68f77 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -960,6 +960,7 @@ struct nvme_completion { __le16 status; /* did the command fail, and if so, why? */ }; -#define NVME_VS(major, minor) (((major) << 16) | ((minor) << 8)) +#define NVME_VS(major, minor, tertiary) \ + (((major) << 16) | ((minor) << 8) | (tertiary)) #endif /* _LINUX_NVME_H */ -- GitLab From a446c0840e244f34c22cc13b3a62d50aa51fb4c6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 30 Sep 2016 13:51:06 +0200 Subject: [PATCH 0781/1167] nvme.h: resync with nvme-cli Import a few updates to nvme.h from nvme-cli. This mostly includes a few new fields and error codes, but also a few renames that so far are only used in user space. Also one field is moved from an array of two le64 values to one of 16 u8 values so that we can more easily access it. Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Jens Axboe --- drivers/nvme/target/admin-cmd.c | 2 +- drivers/nvme/target/discovery.c | 2 +- include/linux/nvme.h | 33 +++++++++++++++++++++++++++------ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 7ab9c9381b989..6944f246e5623 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -199,7 +199,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) */ /* we support multiple ports and multiples hosts: */ - id->mic = (1 << 0) | (1 << 1); + id->cmic = (1 << 0) | (1 << 1); /* no limit on data transfer sizes for now */ id->mdts = 0; diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c index 6f65646e89cfd..a6c25fbcff3f7 100644 --- a/drivers/nvme/target/discovery.c +++ b/drivers/nvme/target/discovery.c @@ -54,7 +54,7 @@ static void nvmet_format_discovery_entry(struct nvmf_disc_rsp_page_hdr *hdr, /* we support only dynamic controllers */ e->cntlid = cpu_to_le16(NVME_CNTLID_DYNAMIC); e->asqsz = cpu_to_le16(NVMF_AQ_DEPTH); - e->nqntype = type; + e->subtype = type; memcpy(e->trsvcid, port->disc_addr.trsvcid, NVMF_TRSVCID_SIZE); memcpy(e->traddr, port->disc_addr.traddr, NVMF_TRADDR_SIZE); memcpy(e->tsas.common, port->disc_addr.tsas.common, NVMF_TSAS_SIZE); diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 086d196e68f77..989699641e105 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -182,7 +182,7 @@ struct nvme_id_ctrl { char fr[8]; __u8 rab; __u8 ieee[3]; - __u8 mic; + __u8 cmic; __u8 mdts; __le16 cntlid; __le32 ver; @@ -202,7 +202,13 @@ struct nvme_id_ctrl { __u8 apsta; __le16 wctemp; __le16 cctemp; - __u8 rsvd270[50]; + __le16 mtfa; + __le32 hmpre; + __le32 hmmin; + __u8 tnvmcap[16]; + __u8 unvmcap[16]; + __le32 rpmbs; + __u8 rsvd316[4]; __le16 kas; __u8 rsvd322[190]; __u8 sqes; @@ -267,7 +273,7 @@ struct nvme_id_ns { __le16 nabo; __le16 nabspf; __u16 rsvd46; - __le64 nvmcap[2]; + __u8 nvmcap[16]; __u8 rsvd64[40]; __u8 nguid[16]; __u8 eui64[8]; @@ -556,8 +562,10 @@ enum nvme_admin_opcode { nvme_admin_set_features = 0x09, nvme_admin_get_features = 0x0a, nvme_admin_async_event = 0x0c, + nvme_admin_ns_mgmt = 0x0d, nvme_admin_activate_fw = 0x10, nvme_admin_download_fw = 0x11, + nvme_admin_ns_attach = 0x15, nvme_admin_keep_alive = 0x18, nvme_admin_format_nvm = 0x80, nvme_admin_security_send = 0x81, @@ -583,6 +591,7 @@ enum { NVME_FEAT_WRITE_ATOMIC = 0x0a, NVME_FEAT_ASYNC_EVENT = 0x0b, NVME_FEAT_AUTO_PST = 0x0c, + NVME_FEAT_HOST_MEM_BUF = 0x0d, NVME_FEAT_KATO = 0x0f, NVME_FEAT_SW_PROGRESS = 0x80, NVME_FEAT_HOST_ID = 0x81, @@ -745,7 +754,7 @@ struct nvmf_common_command { struct nvmf_disc_rsp_page_entry { __u8 trtype; __u8 adrfam; - __u8 nqntype; + __u8 subtype; __u8 treq; __le16 portid; __le16 cntlid; @@ -905,12 +914,23 @@ enum { NVME_SC_INVALID_VECTOR = 0x108, NVME_SC_INVALID_LOG_PAGE = 0x109, NVME_SC_INVALID_FORMAT = 0x10a, - NVME_SC_FIRMWARE_NEEDS_RESET = 0x10b, + NVME_SC_FW_NEEDS_CONV_RESET = 0x10b, NVME_SC_INVALID_QUEUE = 0x10c, NVME_SC_FEATURE_NOT_SAVEABLE = 0x10d, NVME_SC_FEATURE_NOT_CHANGEABLE = 0x10e, NVME_SC_FEATURE_NOT_PER_NS = 0x10f, - NVME_SC_FW_NEEDS_RESET_SUBSYS = 0x110, + NVME_SC_FW_NEEDS_SUBSYS_RESET = 0x110, + NVME_SC_FW_NEEDS_RESET = 0x111, + NVME_SC_FW_NEEDS_MAX_TIME = 0x112, + NVME_SC_FW_ACIVATE_PROHIBITED = 0x113, + NVME_SC_OVERLAPPING_RANGE = 0x114, + NVME_SC_NS_INSUFFICENT_CAP = 0x115, + NVME_SC_NS_ID_UNAVAILABLE = 0x116, + NVME_SC_NS_ALREADY_ATTACHED = 0x118, + NVME_SC_NS_IS_PRIVATE = 0x119, + NVME_SC_NS_NOT_ATTACHED = 0x11a, + NVME_SC_THIN_PROV_NOT_SUPP = 0x11b, + NVME_SC_CTRL_LIST_INVALID = 0x11c, /* * I/O Command Set Specific - NVM commands: @@ -941,6 +961,7 @@ enum { NVME_SC_REFTAG_CHECK = 0x284, NVME_SC_COMPARE_FAILED = 0x285, NVME_SC_ACCESS_DENIED = 0x286, + NVME_SC_UNWRITTEN_BLOCK = 0x287, NVME_SC_DNR = 0x4000, }; -- GitLab From 8d63687afda019a6e037bf9c4ceb3e514c26a35d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 30 Sep 2016 13:51:07 +0200 Subject: [PATCH 0782/1167] nvme.h: don't use uuid_be This makes life easier for nvme-cli and we don't really need the uuid type anyway to start with. Signed-off-by: Christoph Hellwig Reviewed-by: Gabriel Krisman Bertazi Reviewed-by: Jay Freyensee Signed-off-by: Jens Axboe --- include/linux/nvme.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 989699641e105..d31ff2dd1d51b 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -16,7 +16,6 @@ #define _LINUX_NVME_H #include -#include /* NQN names in commands fields specified one size */ #define NVMF_NQN_FIELD_LEN 256 @@ -803,7 +802,7 @@ struct nvmf_connect_command { }; struct nvmf_connect_data { - uuid_be hostid; + __u8 hostid[16]; __le16 cntlid; char resv4[238]; char subsysnqn[NVMF_NQN_FIELD_LEN]; -- GitLab From 329dd7681c5af84e8ea9f4494c1a304389cdfc6e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 30 Sep 2016 13:51:08 +0200 Subject: [PATCH 0783/1167] nvme.h: add an enum for cns values Ported over from nvme-cli. Signed-off-by: Christoph Hellwig Reviewed-by: Gabriel Krisman Bertazi Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- include/linux/nvme.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/nvme.h b/include/linux/nvme.h index d31ff2dd1d51b..fc3c242065939 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -281,6 +281,16 @@ struct nvme_id_ns { __u8 vs[3712]; }; +enum { + NVME_ID_CNS_NS = 0x00, + NVME_ID_CNS_CTRL = 0x01, + NVME_ID_CNS_NS_ACTIVE_LIST = 0x02, + NVME_ID_CNS_NS_PRESENT_LIST = 0x10, + NVME_ID_CNS_NS_PRESENT = 0x11, + NVME_ID_CNS_CTRL_NS_LIST = 0x12, + NVME_ID_CNS_CTRL_LIST = 0x13, +}; + enum { NVME_NS_FEAT_THIN = 1 << 0, NVME_NS_FLBAS_LBA_MASK = 0xf, -- GitLab From fa60682677c594d81e9b68b8a4046cde75a7374b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 30 Sep 2016 13:51:09 +0200 Subject: [PATCH 0784/1167] nvme: use symbolic constants for CNS values Signed-off-by: Christoph Hellwig Reviewed-by: Gabriel Krisman Bertazi Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- drivers/nvme/host/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index bb168b71048da..79e679d12f3b3 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -554,7 +554,7 @@ int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id) /* gcc-4.4.4 (at least) has issues with initializers and anon unions */ c.identify.opcode = nvme_admin_identify; - c.identify.cns = cpu_to_le32(1); + c.identify.cns = cpu_to_le32(NVME_ID_CNS_CTRL); *id = kmalloc(sizeof(struct nvme_id_ctrl), GFP_KERNEL); if (!*id) @@ -572,7 +572,7 @@ static int nvme_identify_ns_list(struct nvme_ctrl *dev, unsigned nsid, __le32 *n struct nvme_command c = { }; c.identify.opcode = nvme_admin_identify; - c.identify.cns = cpu_to_le32(2); + c.identify.cns = cpu_to_le32(NVME_ID_CNS_NS_ACTIVE_LIST); c.identify.nsid = cpu_to_le32(nsid); return nvme_submit_sync_cmd(dev->admin_q, &c, ns_list, 0x1000); } -- GitLab From e9c9346e20c1b18a3ec30defd5ff7134bcc0da6d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 30 Sep 2016 13:51:10 +0200 Subject: [PATCH 0785/1167] nvmet: use symbolic constants for CNS values Signed-off-by: Christoph Hellwig Reviewed-by: Gabriel Krisman Bertazi Reviewed-by: Jay Freyensee Signed-off-by: Jens Axboe --- drivers/nvme/target/admin-cmd.c | 6 +++--- drivers/nvme/target/discovery.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 6944f246e5623..6fe4c48a21e46 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -511,13 +511,13 @@ int nvmet_parse_admin_cmd(struct nvmet_req *req) case nvme_admin_identify: req->data_len = 4096; switch (le32_to_cpu(cmd->identify.cns)) { - case 0x00: + case NVME_ID_CNS_NS: req->execute = nvmet_execute_identify_ns; return 0; - case 0x01: + case NVME_ID_CNS_CTRL: req->execute = nvmet_execute_identify_ctrl; return 0; - case 0x02: + case NVME_ID_CNS_NS_ACTIVE_LIST: req->execute = nvmet_execute_identify_nslist; return 0; } diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c index a6c25fbcff3f7..12f39eea569f2 100644 --- a/drivers/nvme/target/discovery.c +++ b/drivers/nvme/target/discovery.c @@ -187,7 +187,7 @@ int nvmet_parse_discovery_cmd(struct nvmet_req *req) case nvme_admin_identify: req->data_len = 4096; switch (le32_to_cpu(cmd->identify.cns)) { - case 0x01: + case NVME_ID_CNS_CTRL: req->execute = nvmet_execute_identify_disc_ctrl; return 0; -- GitLab From 83aa3e0f791d458a28f91d7a50f92926f971ef7c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Oct 2016 17:21:30 +0200 Subject: [PATCH 0786/1167] nfs4: fix missing-braces warning A bugfix introduced a harmless warning for update_open_stateid: fs/nfs/nfs4proc.c:1548:2: error: missing braces around initializer [-Werror=missing-braces] Removing the zero in the initializer will do the right thing here and initialize the entire structure to zero. Fixes: 1393d9612ba0 ("NFSv4: Fix a race when updating an open_stateid") Signed-off-by: Arnd Bergmann Signed-off-by: Anna Schumaker --- fs/nfs/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ed7da820d4bfd..45b38ee4813c1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1545,7 +1545,7 @@ static int update_open_stateid(struct nfs4_state *state, struct nfs_client *clp = server->nfs_client; struct nfs_inode *nfsi = NFS_I(state->inode); struct nfs_delegation *deleg_cur; - nfs4_stateid freeme = {0}; + nfs4_stateid freeme = { }; int ret = 0; fmode &= (FMODE_READ|FMODE_WRITE); -- GitLab From c30a70d3ac60f3216e8d60d7746caad084a7eb46 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 19 Oct 2016 09:06:41 +0200 Subject: [PATCH 0787/1167] stmmac: fix and review the ptp registration. The commit commit 7086605a6ab5 ("stmmac: fix error check when init ptp") breaks the procedure added by the commit efee95f42b5d ("ptp_clock: future-proofing drivers against PTP subsystem becoming optional") So this patch tries to re-import the logic added by the latest commit above: it makes sense to have the stmmac_ptp_register as void function and, inside the main, the stmmac_init_ptp can fails in case of the capability cannot be supported by the HW. Signed-off-by: Giuseppe Cavallaro Cc: Alexandre TORGUE Cc: Rayagond Kokatanur Cc: Dan Carpenter Cc: Nicolas Pitre Acked-by: Nicolas Pitre Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 ++++-- drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 15 ++++----------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 8dc9056c10010..b15fc55f1b96a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -145,7 +145,7 @@ int stmmac_mdio_register(struct net_device *ndev); int stmmac_mdio_reset(struct mii_bus *mii); void stmmac_set_ethtool_ops(struct net_device *netdev); -int stmmac_ptp_register(struct stmmac_priv *priv); +void stmmac_ptp_register(struct stmmac_priv *priv); void stmmac_ptp_unregister(struct stmmac_priv *priv); int stmmac_resume(struct device *dev); int stmmac_suspend(struct device *dev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 6c85b61aaa0bc..48e71fad42103 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -676,7 +676,9 @@ static int stmmac_init_ptp(struct stmmac_priv *priv) priv->hwts_tx_en = 0; priv->hwts_rx_en = 0; - return stmmac_ptp_register(priv); + stmmac_ptp_register(priv); + + return 0; } static void stmmac_release_ptp(struct stmmac_priv *priv) @@ -1710,7 +1712,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) if (init_ptp) { ret = stmmac_init_ptp(priv); if (ret) - netdev_warn(priv->dev, "PTP support cannot init.\n"); + netdev_warn(priv->dev, "fail to init PTP.\n"); } #ifdef CONFIG_DEBUG_FS diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index 5d61fb27219ac..1477471f8d445 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -177,7 +177,7 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = { * Description: this function will register the ptp clock driver * to kernel. It also does some house keeping work. */ -int stmmac_ptp_register(struct stmmac_priv *priv) +void stmmac_ptp_register(struct stmmac_priv *priv) { spin_lock_init(&priv->ptp_lock); priv->ptp_clock_ops = stmmac_ptp_clock_ops; @@ -185,17 +185,10 @@ int stmmac_ptp_register(struct stmmac_priv *priv) priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops, priv->device); if (IS_ERR(priv->ptp_clock)) { - int ret = PTR_ERR(priv->ptp_clock); - + netdev_err(priv->dev, "ptp_clock_register failed\n"); priv->ptp_clock = NULL; - return ret; - } - - spin_lock_init(&priv->ptp_lock); - - netdev_dbg(priv->dev, "Added PTP HW clock successfully\n"); - - return 0; + } else if (priv->ptp_clock) + netdev_info(priv->dev, "registered PTP clock\n"); } /** -- GitLab From 7d36b9c102318aa86aceb074359305da88ce9ef9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 19 Oct 2016 20:49:39 +0900 Subject: [PATCH 0788/1167] clk: uniphier: fix memory overrun bug The first loop of this "for" statement writes memory beyond the allocated clk_hw_onecell_data. It should be: for (clk_num--; clk_num >= 0; clk_num--) ... Or more simply: while (--clk_num >= 0) ... Fixes: 734d82f4a678 ("clk: uniphier: add core support code for UniPhier clock driver") Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index f4e0f6be5f33a..84bc465d31aa1 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -79,7 +79,7 @@ static int uniphier_clk_probe(struct platform_device *pdev) hw_data->num = clk_num; /* avoid returning NULL for unused idx */ - for (; clk_num >= 0; clk_num--) + while (--clk_num >= 0) hw_data->hws[clk_num] = ERR_PTR(-EINVAL); for (p = data; p->name; p++) { -- GitLab From 5c6201e60a57c6b240d446c8a2d83063283b2743 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 19 Oct 2016 17:22:07 +0900 Subject: [PATCH 0789/1167] clk: uniphier: rename MIO clock to SD clock for Pro5, PXs2, LD20 SoCs I made a mistake as for naming for this block. The MIO block is not implemented for these 3 SoCs in the first place. The current naming will be a trouble if an SoC with both MIO and SD-ctrl blocks appear in the future. This driver has just been merged in the previous merge window. Rename it before the release. Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/uniphier-clock.txt | 16 ++++++++-------- drivers/clk/uniphier/clk-uniphier-core.c | 14 +++++++------- drivers/clk/uniphier/clk-uniphier-mio.c | 2 +- drivers/clk/uniphier/clk-uniphier.h | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/uniphier-clock.txt b/Documentation/devicetree/bindings/clock/uniphier-clock.txt index c7179d3b5c33e..812163060fa3e 100644 --- a/Documentation/devicetree/bindings/clock/uniphier-clock.txt +++ b/Documentation/devicetree/bindings/clock/uniphier-clock.txt @@ -24,7 +24,7 @@ Example: reg = <0x61840000 0x4000>; clock { - compatible = "socionext,uniphier-ld20-clock"; + compatible = "socionext,uniphier-ld11-clock"; #clock-cells = <1>; }; @@ -43,8 +43,8 @@ Provided clocks: 21: USB3 ch1 PHY1 -Media I/O (MIO) clock ---------------------- +Media I/O (MIO) clock, SD clock +------------------------------- Required properties: - compatible: should be one of the following: @@ -52,10 +52,10 @@ Required properties: "socionext,uniphier-ld4-mio-clock" - for LD4 SoC. "socionext,uniphier-pro4-mio-clock" - for Pro4 SoC. "socionext,uniphier-sld8-mio-clock" - for sLD8 SoC. - "socionext,uniphier-pro5-mio-clock" - for Pro5 SoC. - "socionext,uniphier-pxs2-mio-clock" - for PXs2/LD6b SoC. + "socionext,uniphier-pro5-sd-clock" - for Pro5 SoC. + "socionext,uniphier-pxs2-sd-clock" - for PXs2/LD6b SoC. "socionext,uniphier-ld11-mio-clock" - for LD11 SoC. - "socionext,uniphier-ld20-mio-clock" - for LD20 SoC. + "socionext,uniphier-ld20-sd-clock" - for LD20 SoC. - #clock-cells: should be 1. Example: @@ -66,7 +66,7 @@ Example: reg = <0x59810000 0x800>; clock { - compatible = "socionext,uniphier-ld20-mio-clock"; + compatible = "socionext,uniphier-ld11-mio-clock"; #clock-cells = <1>; }; @@ -112,7 +112,7 @@ Example: reg = <0x59820000 0x200>; clock { - compatible = "socionext,uniphier-ld20-peri-clock"; + compatible = "socionext,uniphier-ld11-peri-clock"; #clock-cells = <1>; }; diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index 84bc465d31aa1..26c53f7963a43 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -142,7 +142,7 @@ static const struct of_device_id uniphier_clk_match[] = { .compatible = "socionext,uniphier-ld20-clock", .data = uniphier_ld20_sys_clk_data, }, - /* Media I/O clock */ + /* Media I/O clock, SD clock */ { .compatible = "socionext,uniphier-sld3-mio-clock", .data = uniphier_sld3_mio_clk_data, @@ -160,20 +160,20 @@ static const struct of_device_id uniphier_clk_match[] = { .data = uniphier_sld3_mio_clk_data, }, { - .compatible = "socionext,uniphier-pro5-mio-clock", - .data = uniphier_pro5_mio_clk_data, + .compatible = "socionext,uniphier-pro5-sd-clock", + .data = uniphier_pro5_sd_clk_data, }, { - .compatible = "socionext,uniphier-pxs2-mio-clock", - .data = uniphier_pro5_mio_clk_data, + .compatible = "socionext,uniphier-pxs2-sd-clock", + .data = uniphier_pro5_sd_clk_data, }, { .compatible = "socionext,uniphier-ld11-mio-clock", .data = uniphier_sld3_mio_clk_data, }, { - .compatible = "socionext,uniphier-ld20-mio-clock", - .data = uniphier_pro5_mio_clk_data, + .compatible = "socionext,uniphier-ld20-sd-clock", + .data = uniphier_pro5_sd_clk_data, }, /* Peripheral clock */ { diff --git a/drivers/clk/uniphier/clk-uniphier-mio.c b/drivers/clk/uniphier/clk-uniphier-mio.c index 6aa7ec768d0bf..218d20f099cec 100644 --- a/drivers/clk/uniphier/clk-uniphier-mio.c +++ b/drivers/clk/uniphier/clk-uniphier-mio.c @@ -93,7 +93,7 @@ const struct uniphier_clk_data uniphier_sld3_mio_clk_data[] = { { /* sentinel */ } }; -const struct uniphier_clk_data uniphier_pro5_mio_clk_data[] = { +const struct uniphier_clk_data uniphier_pro5_sd_clk_data[] = { UNIPHIER_MIO_CLK_SD_FIXED, UNIPHIER_MIO_CLK_SD(0, 0), UNIPHIER_MIO_CLK_SD(1, 1), diff --git a/drivers/clk/uniphier/clk-uniphier.h b/drivers/clk/uniphier/clk-uniphier.h index 3ae184062388b..0244dba1f4cf5 100644 --- a/drivers/clk/uniphier/clk-uniphier.h +++ b/drivers/clk/uniphier/clk-uniphier.h @@ -115,7 +115,7 @@ extern const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_ld11_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_ld20_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_sld3_mio_clk_data[]; -extern const struct uniphier_clk_data uniphier_pro5_mio_clk_data[]; +extern const struct uniphier_clk_data uniphier_pro5_sd_clk_data[]; extern const struct uniphier_clk_data uniphier_ld4_peri_clk_data[]; extern const struct uniphier_clk_data uniphier_pro4_peri_clk_data[]; -- GitLab From 1dec78585328db00e33fb18dc1a6deed0e2095a5 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 19 Oct 2016 14:38:50 -0700 Subject: [PATCH 0790/1167] ARC: fix build warning in elf.h The cast valid since TASK_SIZE * 2 will never actually cause overflow. | CC fs/binfmt_elf.o | In file included from ../include/linux/elf.h:4:0, | from ../include/linux/module.h:15, | from ../fs/binfmt_elf.c:12: | ../fs/binfmt_elf.c: In function load_elf_binar: | ../arch/arc/include/asm/elf.h:57:29: warning: integer overflow in expression [-Woverflow] | #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) | ^ | ../fs/binfmt_elf.c:921:16: note: in expansion of macro ELF_ET_DYN_BASE | load_bias = ELF_ET_DYN_BASE - vaddr; Signed-off-by: Vineet Gupta --- arch/arc/include/asm/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/include/asm/elf.h b/arch/arc/include/asm/elf.h index 7096f97a14340..aa2d6da9d187b 100644 --- a/arch/arc/include/asm/elf.h +++ b/arch/arc/include/asm/elf.h @@ -54,7 +54,7 @@ extern int elf_check_arch(const struct elf32_hdr *); * the loader. We need to make sure that it is out of the way of the program * that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) +#define ELF_ET_DYN_BASE (2UL * TASK_SIZE / 3) /* * When the program starts, a1 contains a pointer to a function to be -- GitLab From 390975ac3978162ec9c6beca66f0fe83b0be33bb Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Tue, 18 Oct 2016 21:21:43 +0200 Subject: [PATCH 0791/1167] ubifs: Rename ubifs_rename2 Since ->rename2 is gone, rename ubifs_rename2() to ubifs_rename(). Suggested-by: Linus Torvalds Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index c8f60df2733eb..668ec3b90ea14 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1060,9 +1060,9 @@ static void unlock_4_inodes(struct inode *inode1, struct inode *inode2, mutex_unlock(&ubifs_inode(inode1)->ui_mutex); } -static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) +static int do_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) { struct ubifs_info *c = old_dir->i_sb->s_fs_info; struct inode *old_inode = d_inode(old_dentry); @@ -1323,7 +1323,7 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, return err; } -static int ubifs_rename2(struct inode *old_dir, struct dentry *old_dentry, +static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { @@ -1336,7 +1336,7 @@ static int ubifs_rename2(struct inode *old_dir, struct dentry *old_dentry, if (flags & RENAME_EXCHANGE) return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry); - return ubifs_rename(old_dir, old_dentry, new_dir, new_dentry, flags); + return do_rename(old_dir, old_dentry, new_dir, new_dentry, flags); } int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, @@ -1387,7 +1387,7 @@ const struct inode_operations ubifs_dir_inode_operations = { .mkdir = ubifs_mkdir, .rmdir = ubifs_rmdir, .mknod = ubifs_mknod, - .rename = ubifs_rename2, + .rename = ubifs_rename, .setattr = ubifs_setattr, .getattr = ubifs_getattr, .listxattr = ubifs_listxattr, -- GitLab From 843741c5778398ea67055067f4cc65ae6c80ca0e Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Tue, 20 Sep 2016 10:08:30 +0200 Subject: [PATCH 0792/1167] ubifs: Fix xattr_names length in exit paths When the operation fails we also have to undo the changes we made to ->xattr_names. Otherwise listxattr() will report wrong lengths. Cc: stable@vger.kernel.org Signed-off-by: Richard Weinberger --- fs/ubifs/xattr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index 6c2f4d41ed737..d9f9615bfd71a 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c @@ -172,6 +172,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, host_ui->xattr_cnt -= 1; host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); host_ui->xattr_size -= CALC_XATTR_BYTES(size); + host_ui->xattr_names -= nm->len; mutex_unlock(&host_ui->ui_mutex); out_free: make_bad_inode(inode); @@ -478,6 +479,7 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host, host_ui->xattr_cnt += 1; host_ui->xattr_size += CALC_DENT_SIZE(nm->len); host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len); + host_ui->xattr_names += nm->len; mutex_unlock(&host_ui->ui_mutex); ubifs_release_budget(c, &req); make_bad_inode(inode); -- GitLab From a15cf34fed779d3d49d76e3a7e63bd0132b6a458 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 15 Oct 2016 17:00:11 +0100 Subject: [PATCH 0793/1167] ubi: fix swapped arguments to call to ubi_alloc_aeb Static analysis by CoverityScan detected the ec and pnum arguments are in the wrong order on a call to ubi_alloc_aeb. Swap the order to fix this. Fixes: 91f4285fe389a27 ("UBI: provide helpers to allocate and free aeb elements") Signed-off-by: Colin Ian King Reviewed-by: Boris Brezillon Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/fastmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index d6384d9657885..2ff62157d3bb0 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -287,7 +287,7 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai, /* new_aeb is newer */ if (cmp_res & 1) { - victim = ubi_alloc_aeb(ai, aeb->ec, aeb->pnum); + victim = ubi_alloc_aeb(ai, aeb->pnum, aeb->ec); if (!victim) return -ENOMEM; -- GitLab From 884a3b647809cb31cf6bd948f814e93753b38502 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 13 Oct 2016 16:05:36 +0200 Subject: [PATCH 0794/1167] UBI: Fix crash in try_recover_peb() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/mtd/ubi/eba.c: In function ‘try_recover_peb’: drivers/mtd/ubi/eba.c:744: warning: ‘vid_hdr’ is used uninitialized in this function The pointer vid_hdr is indeed not initialized, leading to a crash when it is dereferenced. Fix this by obtaining the pointer from the VID buffer, like is done everywhere else. Fixes: 3291b52f9ff0acc8 ("UBI: introduce the VID buffer concept") Signed-off-by: Geert Uytterhoeven Reviewed-by: Boris Brezillon Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/eba.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 95c4048a371e8..388e46be6ad92 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -741,6 +741,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum, goto out_put; } + vid_hdr = ubi_get_vid_hdr(vidb); ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC); mutex_lock(&ubi->buf_mutex); -- GitLab From c83ed4c9dbb358b9e7707486e167e940d48bfeed Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 19 Oct 2016 12:43:07 +0200 Subject: [PATCH 0795/1167] ubifs: Abort readdir upon error If UBIFS is facing an error while walking a directory, it reports this error and ubifs_readdir() returns the error code. But the VFS readdir logic does not make the getdents system call fail in all cases. When the readdir cursor indicates that more entries are present, the system call will just return and the libc wrapper will try again since it also knows that more entries are present. This causes the libc wrapper to busy loop for ever when a directory is corrupted on UBIFS. A common approach do deal with corrupted directory entries is skipping them by setting the cursor to the next entry. On UBIFS this approach is not possible since we cannot compute the next directory entry cursor position without reading the current entry. So all we can do is setting the cursor to the "no more entries" position and make getdents exit. Cc: stable@vger.kernel.org Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 668ec3b90ea14..bd4a5e8ce4410 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -439,7 +439,7 @@ static unsigned int vfs_dent_type(uint8_t type) */ static int ubifs_readdir(struct file *file, struct dir_context *ctx) { - int err; + int err = 0; struct qstr nm; union ubifs_key key; struct ubifs_dent_node *dent; @@ -541,14 +541,12 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) kfree(file->private_data); file->private_data = NULL; - if (err != -ENOENT) { + if (err != -ENOENT) ubifs_err(c, "cannot find next direntry, error %d", err); - return err; - } /* 2 is a special value indicating that there are no more direntries */ ctx->pos = 2; - return 0; + return err; } /* Free saved readdir() state when the directory is closed */ -- GitLab From 8dedefbc38172f3fcb43a26b6d0e394dcb1ee562 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 4 Oct 2016 16:40:14 -0700 Subject: [PATCH 0796/1167] drm/fsl-dcu: enable TCON bypass mode by default Do not use encoder disable/enable callbacks to control bypass mode as this seems to mess with the signals not liked by displays. This also makes more sense since the encoder is already defined to be parallel RGB/LVDS at creation time. Signed-off-by: Stefan Agner Tested-By: Meng Yi --- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | 2 ++ drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 39 +++-------------------- 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index 0884c45aefe84..3897f5671776e 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -273,6 +273,8 @@ static int fsl_dcu_drm_pm_resume(struct device *dev) goto disable_dcu_clk; } + if (fsl_dev->tcon) + fsl_tcon_bypass_enable(fsl_dev->tcon); fsl_dcu_drm_init_planes(fsl_dev->drm); drm_atomic_helper_resume(fsl_dev->drm, fsl_dev->state); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index 26edcc899712d..e1dd75b181189 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -20,38 +20,6 @@ #include "fsl_dcu_drm_drv.h" #include "fsl_tcon.h" -static int -fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - return 0; -} - -static void fsl_dcu_drm_encoder_disable(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; - - if (fsl_dev->tcon) - fsl_tcon_bypass_disable(fsl_dev->tcon); -} - -static void fsl_dcu_drm_encoder_enable(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; - - if (fsl_dev->tcon) - fsl_tcon_bypass_enable(fsl_dev->tcon); -} - -static const struct drm_encoder_helper_funcs encoder_helper_funcs = { - .atomic_check = fsl_dcu_drm_encoder_atomic_check, - .disable = fsl_dcu_drm_encoder_disable, - .enable = fsl_dcu_drm_encoder_enable, -}; - static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder) { drm_encoder_cleanup(encoder); @@ -68,13 +36,16 @@ int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev, int ret; encoder->possible_crtcs = 1; + + /* Use bypass mode for parallel RGB/LVDS encoder */ + if (fsl_dev->tcon) + fsl_tcon_bypass_enable(fsl_dev->tcon); + ret = drm_encoder_init(fsl_dev->drm, encoder, &encoder_funcs, DRM_MODE_ENCODER_LVDS, NULL); if (ret < 0) return ret; - drm_encoder_helper_add(encoder, &encoder_helper_funcs); - return 0; } -- GitLab From b6ead864ea893ef55828be0ec0d6c10f7c1c4e30 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 4 Oct 2016 16:56:38 -0700 Subject: [PATCH 0797/1167] drm/fsl-dcu: do not transfer registers on plane init There is no need to explicitly initiate a register transfer and turn off the DCU after initializing the plane registers. In fact, this is harmful and leads to unnecessary flickers if the DCU has been left on by the bootloader. Signed-off-by: Stefan Agner Tested-By: Meng Yi --- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c index a7e5486bd1e93..9e6f7d8112b32 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c @@ -211,11 +211,6 @@ void fsl_dcu_drm_init_planes(struct drm_device *dev) for (j = 1; j <= fsl_dev->soc->layer_regs; j++) regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(i, j), 0); } - regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, - DCU_MODE_DCU_MODE_MASK, - DCU_MODE_DCU_MODE(DCU_MODE_OFF)); - regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, - DCU_UPDATE_MODE_READREG); } struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev) -- GitLab From 9789037695018e25902469ea0e540c07580b940f Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 5 Oct 2016 14:37:57 -0700 Subject: [PATCH 0798/1167] drm/fsl-dcu: do not transfer registers in mode_set_nofb Do not schedule a transfer of mode settings early. Modes should get applied on on CRTC enable where we also enable the pixel clock. Signed-off-by: Stefan Agner Tested-By: Meng Yi --- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c index 3371635cd4d70..5ad1d68c8194a 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c @@ -116,8 +116,6 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) | DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) | DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL)); - regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, - DCU_UPDATE_MODE_READREG); return; } -- GitLab From 0a70c998d0c571c66d0ba8ffd9f803392a53193d Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 4 Oct 2016 17:40:29 -0700 Subject: [PATCH 0799/1167] drm/fsl-dcu: enable pixel clock when enabling CRTC The pixel clock should not be on if the CRTC is not in use, hence move clock enable/disable calls into CRTC callbacks. Signed-off-by: Stefan Agner Tested-By: Meng Yi --- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c | 2 ++ drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | 21 +-------------------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c index 5ad1d68c8194a..b2d5e188b1b88 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c @@ -51,6 +51,7 @@ static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc) DCU_MODE_DCU_MODE(DCU_MODE_OFF)); regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG); + clk_disable_unprepare(fsl_dev->pix_clk); } static void fsl_dcu_drm_crtc_enable(struct drm_crtc *crtc) @@ -58,6 +59,7 @@ static void fsl_dcu_drm_crtc_enable(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; + clk_prepare_enable(fsl_dev->pix_clk); regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, DCU_MODE_DCU_MODE_MASK, DCU_MODE_DCU_MODE(DCU_MODE_NORMAL)); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index 3897f5671776e..e04efbed1a54f 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -267,12 +267,6 @@ static int fsl_dcu_drm_pm_resume(struct device *dev) return ret; } - ret = clk_prepare_enable(fsl_dev->pix_clk); - if (ret < 0) { - dev_err(dev, "failed to enable pix clk\n"); - goto disable_dcu_clk; - } - if (fsl_dev->tcon) fsl_tcon_bypass_enable(fsl_dev->tcon); fsl_dcu_drm_init_planes(fsl_dev->drm); @@ -286,10 +280,6 @@ static int fsl_dcu_drm_pm_resume(struct device *dev) enable_irq(fsl_dev->irq); return 0; - -disable_dcu_clk: - clk_disable_unprepare(fsl_dev->clk); - return ret; } #endif @@ -403,18 +393,12 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev) goto disable_clk; } - ret = clk_prepare_enable(fsl_dev->pix_clk); - if (ret < 0) { - dev_err(dev, "failed to enable pix clk\n"); - goto unregister_pix_clk; - } - fsl_dev->tcon = fsl_tcon_init(dev); drm = drm_dev_alloc(driver, dev); if (IS_ERR(drm)) { ret = PTR_ERR(drm); - goto disable_pix_clk; + goto unregister_pix_clk; } fsl_dev->dev = dev; @@ -435,8 +419,6 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev) unref: drm_dev_unref(drm); -disable_pix_clk: - clk_disable_unprepare(fsl_dev->pix_clk); unregister_pix_clk: clk_unregister(fsl_dev->pix_clk); disable_clk: @@ -449,7 +431,6 @@ static int fsl_dcu_drm_remove(struct platform_device *pdev) struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev); clk_disable_unprepare(fsl_dev->clk); - clk_disable_unprepare(fsl_dev->pix_clk); clk_unregister(fsl_dev->pix_clk); drm_put_dev(fsl_dev->drm); -- GitLab From 02eb924fabc5b699c0d9d354491e6f0767e3c139 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 6 Oct 2016 10:07:07 -0500 Subject: [PATCH 0800/1167] target/user: Use sense_reason_t in tcmu_queue_cmd_ring Instead of using -ERROR-style returns, use sense_reason_t. This lets us remove tcmu_pass_op(), and return more correct sense values. Signed-off-by: Andy Grover Signed-off-by: Bryant G. Ly Reviewed-by: Christoph Hellwig Reviewed-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 62bf4fe5704a9..0cd1c61ba2edd 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -389,7 +389,8 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_size, size_t d return true; } -static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) +static sense_reason_t +tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) { struct tcmu_dev *udev = tcmu_cmd->tcmu_dev; struct se_cmd *se_cmd = tcmu_cmd->se_cmd; @@ -405,7 +406,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) DECLARE_BITMAP(old_bitmap, DATA_BLOCK_BITS); if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; /* * Must be a certain minimum size for response sense info, but @@ -450,7 +451,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) finish_wait(&udev->wait_cmdr, &__wait); if (!ret) { pr_warn("tcmu: command timed out\n"); - return -ETIMEDOUT; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } spin_lock_irq(&udev->cmdr_lock); @@ -526,10 +527,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) mod_timer(&udev->timeout, round_jiffies_up(jiffies + msecs_to_jiffies(TCMU_TIME_OUT))); - return 0; + return TCM_NO_SENSE; } -static int tcmu_queue_cmd(struct se_cmd *se_cmd) +static sense_reason_t +tcmu_queue_cmd(struct se_cmd *se_cmd) { struct se_device *se_dev = se_cmd->se_dev; struct tcmu_dev *udev = TCMU_DEV(se_dev); @@ -538,10 +540,10 @@ static int tcmu_queue_cmd(struct se_cmd *se_cmd) tcmu_cmd = tcmu_alloc_cmd(se_cmd); if (!tcmu_cmd) - return -ENOMEM; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; ret = tcmu_queue_cmd_ring(tcmu_cmd); - if (ret < 0) { + if (ret != TCM_NO_SENSE) { pr_err("TCMU: Could not queue command\n"); spin_lock_irq(&udev->commands_lock); idr_remove(&udev->commands, tcmu_cmd->cmd_id); @@ -1128,21 +1130,10 @@ static sector_t tcmu_get_blocks(struct se_device *dev) dev->dev_attrib.block_size); } -static sense_reason_t -tcmu_pass_op(struct se_cmd *se_cmd) -{ - int ret = tcmu_queue_cmd(se_cmd); - - if (ret != 0) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - else - return TCM_NO_SENSE; -} - static sense_reason_t tcmu_parse_cdb(struct se_cmd *cmd) { - return passthrough_parse_cdb(cmd, tcmu_pass_op); + return passthrough_parse_cdb(cmd, tcmu_queue_cmd); } static const struct target_backend_ops tcmu_ops = { -- GitLab From 554617b2bbe25c3fb3c80c28fe7a465884bb40b1 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 25 Aug 2016 08:55:53 -0700 Subject: [PATCH 0801/1167] target/user: Return an error if cmd data size is too large Userspace should be implementing VPD B0 (Block Limits) to inform the initiator of max data size, but just in case we do get a too-large request, do what the spec says and return INVALID_CDB_FIELD. Make sure to unlock udev->cmdr_lock before returning. Signed-off-by: Andy Grover Reviewed-by: Christoph Hellwig Reviewed-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 0cd1c61ba2edd..5de1eac17fed4 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -433,11 +433,14 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents)); data_length += se_cmd->t_bidi_data_sg->length; } - if ((command_size > (udev->cmdr_size / 2)) - || data_length > udev->data_size) - pr_warn("TCMU: Request of size %zu/%zu may be too big for %u/%zu " + if ((command_size > (udev->cmdr_size / 2)) || + data_length > udev->data_size) { + pr_warn("TCMU: Request of size %zu/%zu is too big for %u/%zu " "cmd/data ring buffers\n", command_size, data_length, udev->cmdr_size, udev->data_size); + spin_unlock_irq(&udev->cmdr_lock); + return TCM_INVALID_CDB_FIELD; + } while (!is_ring_space_avail(udev, command_size, data_length)) { int ret; -- GitLab From 3d9b95558f5874ac5d63a057813dc66b480de7e1 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 25 Aug 2016 08:55:54 -0700 Subject: [PATCH 0802/1167] target/user: Fix comments to not refer to data ring We no longer use a ringbuffer for the data area, so this might cause confusion. Just call it the data area. Signed-off-by: Andy Grover Reviewed-by: Christoph Hellwig Reviewed-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 5de1eac17fed4..47562509b4892 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -96,7 +96,7 @@ struct tcmu_dev { size_t dev_size; u32 cmdr_size; u32 cmdr_last_cleaned; - /* Offset of data ring from start of mb */ + /* Offset of data area from start of mb */ /* Must add data_off and mb_addr to get the address */ size_t data_off; size_t data_size; @@ -349,7 +349,7 @@ static inline size_t spc_bitmap_free(unsigned long *bitmap) /* * We can't queue a command until we have space available on the cmd ring *and* - * space available on the data ring. + * space available on the data area. * * Called with ring lock held. */ @@ -436,7 +436,7 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) if ((command_size > (udev->cmdr_size / 2)) || data_length > udev->data_size) { pr_warn("TCMU: Request of size %zu/%zu is too big for %u/%zu " - "cmd/data ring buffers\n", command_size, data_length, + "cmd ring/data area\n", command_size, data_length, udev->cmdr_size, udev->data_size); spin_unlock_irq(&udev->cmdr_lock); return TCM_INVALID_CDB_FIELD; @@ -491,9 +491,7 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) bitmap_copy(old_bitmap, udev->data_bitmap, DATA_BLOCK_BITS); - /* - * Fix up iovecs, and handle if allocation in data ring wrapped. - */ + /* Handle allocating space from the data area */ iov = &entry->req.iov[0]; iov_cnt = 0; copy_to_data_area = (se_cmd->data_direction == DMA_TO_DEVICE @@ -566,7 +564,7 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { /* * cmd has been completed already from timeout, just reclaim - * data ring space and free cmd + * data area space and free cmd */ free_data_area(udev, cmd); -- GitLab From 3fc6a642e4355abef986b2dd11672216fb18212e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 2 Sep 2016 15:30:34 +0100 Subject: [PATCH 0803/1167] iscsi-target: fix spelling mistake "Unsolicitied" -> "Unsolicited" Trivial fix to spelling mistakes in pr_debug message and comments Signed-off-by: Colin Ian King Reviewed-by: Bart Van Assche Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 2 +- drivers/target/iscsi/iscsi_target_login.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 39b928c2849d7..1aaf1f3148b2c 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -2982,7 +2982,7 @@ iscsit_build_nopin_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x," " StatSN: 0x%08x, Length %u\n", (nopout_response) ? - "Solicitied" : "Unsolicitied", cmd->init_task_tag, + "Solicited" : "Unsolicited", cmd->init_task_tag, cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size); } EXPORT_SYMBOL(iscsit_build_nopin_rsp); diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index adf419fa42918..15f79a2ca34ab 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -434,7 +434,7 @@ static int iscsi_login_zero_tsih_s2( /* * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for - * Immediate Data + Unsolicitied Data-OUT if necessary.. + * Immediate Data + Unsolicited Data-OUT if necessary.. */ param = iscsi_find_param_from_key("MaxRecvDataSegmentLength", conn->param_list); @@ -646,7 +646,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn) { struct iscsi_session *sess = conn->sess; /* - * FIXME: Unsolicitied NopIN support for ISER + * FIXME: Unsolicited NopIN support for ISER */ if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) return; -- GitLab From 1a40f0a36fb669226f0fd29aaece5ff7b6399e80 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Thu, 15 Sep 2016 21:20:11 +0530 Subject: [PATCH 0804/1167] iscsi-target: fix iscsi cmd leak If iscsi-target receives NOP OUT with ITT and TTT set to 0xffffffff it allocates iscsi_cmd but does not free the cmd, so free iscsi_cmd in this case. Signed-off-by: Varun Prakash Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 1aaf1f3148b2c..b7d747e92c7ab 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1804,6 +1804,10 @@ int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, * Otherwise, initiator is not expecting a NOPIN is response. * Just ignore for now. */ + + if (cmd) + iscsit_free_cmd(cmd, false); + return 0; } EXPORT_SYMBOL(iscsit_process_nop_out); -- GitLab From 527268df31e57cf2b6d417198717c6d6afdb1e3e Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 4 Oct 2016 16:37:05 -0700 Subject: [PATCH 0805/1167] target: Re-add missing SCF_ACK_KREF assignment in v4.1.y This patch fixes a regression in >= v4.1.y code where the original SCF_ACK_KREF assignment in target_get_sess_cmd() was dropped upstream in commit 054922bb, but the series for addressing TMR ABORT_TASK + LUN_RESET with fabric session reinstatement in commit febe562c20 still depends on this code in transport_cmd_finish_abort(). The regression manifests itself as a se_cmd->cmd_kref +1 leak, where ABORT_TASK + LUN_RESET can hang indefinately for a specific I_T session for drivers using SCF_ACK_KREF, resulting in hung kthreads. This patch has been verified with v4.1.y code. Reported-by: Vaibhav Tandon Tested-by: Vaibhav Tandon Cc: Vaibhav Tandon Cc: stable@vger.kernel.org # 4.1+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 6094a6beddde9..00ec46413146a 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2547,8 +2547,10 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) * fabric acknowledgement that requires two target_put_sess_cmd() * invocations before se_cmd descriptor release. */ - if (ack_kref) + if (ack_kref) { kref_get(&se_cmd->cmd_kref); + se_cmd->se_cmd_flags |= SCF_ACK_KREF; + } spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); if (se_sess->sess_tearing_down) { -- GitLab From 449a137846c84829a328757cd21fd9ca65c08519 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 8 Oct 2016 17:26:44 -0700 Subject: [PATCH 0806/1167] target: Make EXTENDED_COPY 0xe4 failure return COPY TARGET DEVICE NOT REACHABLE This patch addresses a bug where EXTENDED_COPY across multiple LUNs results in a CHECK_CONDITION when the source + destination are not located on the same physical node. ESX Host environments expect sense COPY_ABORTED w/ COPY TARGET DEVICE NOT REACHABLE to be returned when this occurs, in order to signal fallback to local copy method. As described in section 6.3.3 of spc4r22: "If it is not possible to complete processing of a segment because the copy manager is unable to establish communications with a copy target device, because the copy target device does not respond to INQUIRY, or because the data returned in response to INQUIRY indicates an unsupported logical unit, then the EXTENDED COPY command shall be terminated with CHECK CONDITION status, with the sense key set to COPY ABORTED, and the additional sense code set to COPY TARGET DEVICE NOT REACHABLE." Tested on v4.1.y with ESX v5.5u2+ with BlockCopy across multiple nodes. Reported-by: Nixon Vincent Tested-by: Nixon Vincent Cc: Nixon Vincent Tested-by: Dinesh Israni Signed-off-by: Dinesh Israni Cc: Dinesh Israni Cc: stable@vger.kernel.org # 3.14+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 7 +++++++ drivers/target/target_core_xcopy.c | 22 ++++++++++++++++------ include/target/target_core_base.h | 1 + 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 00ec46413146a..000bc6d077ead 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1706,6 +1706,7 @@ void transport_generic_request_failure(struct se_cmd *cmd, case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED: case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: + case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE: break; case TCM_OUT_OF_RESOURCES: sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; @@ -2873,6 +2874,12 @@ static const struct sense_info sense_info_table[] = { .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */ .add_sector_info = true, }, + [TCM_COPY_TARGET_DEVICE_NOT_REACHABLE] = { + .key = COPY_ABORTED, + .asc = 0x0d, + .ascq = 0x02, /* COPY TARGET DEVICE NOT REACHABLE */ + + }, [TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = { /* * Returning ILLEGAL REQUEST would cause immediate IO errors on diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 75cd85426ae3a..f2a1443ecb33f 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -104,7 +104,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op } mutex_unlock(&g_device_mutex); - pr_err("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); + pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); return -EINVAL; } @@ -185,7 +185,7 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, struct xcopy_op *xop, unsigned char *p, - unsigned short tdll) + unsigned short tdll, sense_reason_t *sense_ret) { struct se_device *local_dev = se_cmd->se_dev; unsigned char *desc = p; @@ -193,6 +193,8 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, unsigned short start = 0; bool src = true; + *sense_ret = TCM_INVALID_PARAMETER_LIST; + if (offset != 0) { pr_err("XCOPY target descriptor list length is not" " multiple of %d\n", XCOPY_TARGET_DESC_LEN); @@ -243,9 +245,16 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true); else rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false); - - if (rc < 0) + /* + * If a matching IEEE NAA 0x83 descriptor for the requested device + * is not located on this node, return COPY_ABORTED with ASQ/ASQC + * 0x0d/0x02 - COPY_TARGET_DEVICE_NOT_REACHABLE to request the + * initiator to fall back to normal copy method. + */ + if (rc < 0) { + *sense_ret = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE; goto out; + } pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n", xop->src_dev, &xop->src_tid_wwn[0]); @@ -816,7 +825,8 @@ static void target_xcopy_do_work(struct work_struct *work) xcopy_pt_undepend_remotedev(xop); kfree(xop); - pr_warn("target_xcopy_do_work: Setting X-COPY CHECK_CONDITION -> sending response\n"); + pr_warn_ratelimited("target_xcopy_do_work: rc: %d, Setting X-COPY CHECK_CONDITION" + " -> sending response\n", rc); ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION; target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION); } @@ -875,7 +885,7 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage, tdll, sdll, inline_dl); - rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll); + rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret); if (rc <= 0) goto out; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index fb8e3b6febdff..c2119008990a3 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -177,6 +177,7 @@ enum tcm_sense_reason_table { TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED = R(0x15), TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = R(0x16), TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = R(0x17), + TCM_COPY_TARGET_DEVICE_NOT_REACHABLE = R(0x18), #undef R }; -- GitLab From 926317de33998c112c5510301868ea9aa34097e2 Mon Sep 17 00:00:00 2001 From: Dinesh Israni Date: Mon, 10 Oct 2016 20:22:03 -0700 Subject: [PATCH 0807/1167] target: Don't override EXTENDED_COPY xcopy_pt_cmd SCSI status code This patch addresses a bug where a local EXTENDED_COPY WRITE or READ backend I/O request would always return SAM_STAT_CHECK_CONDITION, even if underlying xcopy_pt_cmd->se_cmd generated a different SCSI status code. ESX host environments expect to hit SAM_STAT_RESERVATION_CONFLICT for certain scenarios, and SAM_STAT_CHECK_CONDITION results in non-retriable status for these cases. Tested on v4.1.y with ESX v5.5u2+ with local IBLOCK backend copy. Reported-by: Nixon Vincent Tested-by: Nixon Vincent Cc: Nixon Vincent Tested-by: Dinesh Israni Signed-off-by: Dinesh Israni Cc: Dinesh Israni Cc: stable@vger.kernel.org # 3.14+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_xcopy.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index f2a1443ecb33f..094a1440eacb3 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -662,6 +662,7 @@ static int target_xcopy_read_source( rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0], remote_port, true); if (rc < 0) { + ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status; transport_generic_free_cmd(se_cmd, 0); return rc; } @@ -673,6 +674,7 @@ static int target_xcopy_read_source( rc = target_xcopy_issue_pt_cmd(xpt_cmd); if (rc < 0) { + ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status; transport_generic_free_cmd(se_cmd, 0); return rc; } @@ -723,6 +725,7 @@ static int target_xcopy_write_destination( remote_port, false); if (rc < 0) { struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd; + ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status; /* * If the failure happened before the t_mem_list hand-off in * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that @@ -738,6 +741,7 @@ static int target_xcopy_write_destination( rc = target_xcopy_issue_pt_cmd(xpt_cmd); if (rc < 0) { + ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status; se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; transport_generic_free_cmd(se_cmd, 0); return rc; @@ -824,10 +828,14 @@ static void target_xcopy_do_work(struct work_struct *work) out: xcopy_pt_undepend_remotedev(xop); kfree(xop); - - pr_warn_ratelimited("target_xcopy_do_work: rc: %d, Setting X-COPY CHECK_CONDITION" - " -> sending response\n", rc); - ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION; + /* + * Don't override an error scsi status if it has already been set + */ + if (ec_cmd->scsi_status == SAM_STAT_GOOD) { + pr_warn_ratelimited("target_xcopy_do_work: rc: %d, Setting X-COPY" + " CHECK_CONDITION -> sending response\n", rc); + ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION; + } target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION); } -- GitLab From 61f36166c245e563c7a2b624f4c78c5ce0f680d6 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 16 Oct 2016 00:27:42 -0700 Subject: [PATCH 0808/1167] Revert "target: Fix residual overflow handling in target_complete_cmd_with_length" This reverts commit c1ccbfe0311e2380a6d2dcb0714b36904f5d586f. Reverting this patch, as it incorrectly assumes the additional length for INQUIRY in target_complete_cmd_with_length() is SCSI allocation length, which breaks existing user-space code when SCSI allocation length is smaller than additional length. root@scsi-mq:~# sg_inq --len=4 -vvvv /dev/sdb found bsg_major=253 open /dev/sdb with flags=0x800 inquiry cdb: 12 00 00 00 04 00 duration=0 ms inquiry: pass-through requested 4 bytes (data-in) but got -28 bytes inquiry: pass-through can't get negative bytes, say it got none inquiry: got too few bytes (0) INQUIRY resid (32) should never exceed requested len=4 inquiry: failed requesting 4 byte response: Malformed response to SCSI command [resid=32] AFAICT the original change was not to address a specific host issue, so go ahead and revert to original logic for now. Cc: Douglas Gilbert Cc: Martin K. Petersen Cc: Sumit Rai Cc: stable@vger.kernel.org # 4.8+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 000bc6d077ead..e825d580ccee7 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -754,15 +754,7 @@ EXPORT_SYMBOL(target_complete_cmd); void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) { - if (scsi_status != SAM_STAT_GOOD) { - return; - } - - /* - * Calculate new residual count based upon length of SCSI data - * transferred. - */ - if (length < cmd->data_length) { + if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) { if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { cmd->residual_count += cmd->data_length - length; } else { @@ -771,12 +763,6 @@ void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int len } cmd->data_length = length; - } else if (length > cmd->data_length) { - cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; - cmd->residual_count = length - cmd->data_length; - } else { - cmd->se_cmd_flags &= ~(SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT); - cmd->residual_count = 0; } target_complete_cmd(cmd, scsi_status); -- GitLab From 1d55a4bfd080ff4c6c96acfccfb7cdd2615ed6c2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 20 Oct 2016 15:40:55 +1100 Subject: [PATCH 0809/1167] xfs: remove redundant assignment of ifp Remove redundant ifp = ifp statement, it does nothing. Found with static analysis by CoverityScan. Signed-off-by: Colin Ian King Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_bmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index c27344cf38e17..0283b7eaf973c 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -5204,7 +5204,7 @@ xfs_bunmapi_cow( ep = xfs_bmap_search_extents(ip, del->br_startoff, XFS_COW_FORK, &eof, &eidx, &got, &new); - ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); ifp = ifp; + ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); ASSERT((eidx >= 0) && (eidx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))); ASSERT(del->br_blockcount > 0); -- GitLab From 1be7f9be0efa4e90547f50b8188f4e70710a1173 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Oct 2016 15:41:48 +1100 Subject: [PATCH 0810/1167] xfs: Fix uninitialized variable in xfs_reflink_reserve_cow_range() with gcc 4.1.2: fs/xfs/xfs_reflink.c: In function xfs_reflink_reserve_cow_range: fs/xfs/xfs_reflink.c:327: warning: error may be used uninitialized in this function Indeed, if "count" is zero, the function will return an uninitialized error value. While "count" is unlikely to be zero, this function is called through the public iomap API. Hence fix this by preinitializing error to zero. Fixes: 2a06705cd5954030 ("xfs: create delalloc extents in CoW fork") Signed-off-by: Geert Uytterhoeven Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner --- fs/xfs/xfs_reflink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 5965e9455d91e..d48a7cc2fe007 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -324,7 +324,7 @@ xfs_reflink_reserve_cow_range( struct xfs_mount *mp = ip->i_mount; xfs_fileoff_t offset_fsb, end_fsb; bool skipped = false; - int error; + int error = 0; trace_xfs_reflink_reserve_cow_range(ip, offset, count); -- GitLab From f1b8243c55ca6fd2a3898e2f586b8cfcfff684bb Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 20 Oct 2016 15:42:30 +1100 Subject: [PATCH 0811/1167] xfs: add some 'static' annotations sparse reported that several variables and a function were not forward-declared anywhere and therefore should be 'static'. Found with sparse by running 'make C=2 CF=-D__CHECK_ENDIAN__ fs/xfs/' Signed-off-by: Eric Biggers Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_btree.c | 2 +- fs/xfs/xfs_sysfs.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 5c8e6f2ce44f4..0e80993c8a591 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -4826,7 +4826,7 @@ xfs_btree_calc_size( return rval; } -int +static int xfs_btree_count_blocks_helper( struct xfs_btree_cur *cur, int level, diff --git a/fs/xfs/xfs_sysfs.c b/fs/xfs/xfs_sysfs.c index 5f8d55d29a11c..276d3023d60f8 100644 --- a/fs/xfs/xfs_sysfs.c +++ b/fs/xfs/xfs_sysfs.c @@ -512,13 +512,13 @@ static struct attribute *xfs_error_attrs[] = { }; -struct kobj_type xfs_error_cfg_ktype = { +static struct kobj_type xfs_error_cfg_ktype = { .release = xfs_sysfs_release, .sysfs_ops = &xfs_sysfs_ops, .default_attrs = xfs_error_attrs, }; -struct kobj_type xfs_error_ktype = { +static struct kobj_type xfs_error_ktype = { .release = xfs_sysfs_release, .sysfs_ops = &xfs_sysfs_ops, }; -- GitLab From 0ee7a3f6b5b2f22bb69bfc6c60d0ea0777003098 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:44:14 +1100 Subject: [PATCH 0812/1167] xfs: don't take the IOLOCK exclusive for direct I/O page invalidation XFS historically took the iolock exclusive when invalidating pages before direct I/O operations to protect against writeback starvations. But this writeback starvation issues has been fixed a long time ago in the core writeback code, and all other file systems manage to do without the exclusive lock. Convert XFS over to avoid the exclusive lock in this case, and also move to range invalidations like done by the other file systems. Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Reviewed-by: Carlos Maiolino Signed-off-by: Dave Chinner --- fs/xfs/xfs_file.c | 98 +++++++++++++++-------------------------------- 1 file changed, 30 insertions(+), 68 deletions(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index a314fc7b56fa5..0dc9971d3c84a 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -249,6 +249,7 @@ xfs_file_dio_aio_read( struct xfs_inode *ip = XFS_I(inode); loff_t isize = i_size_read(inode); size_t count = iov_iter_count(to); + loff_t end = iocb->ki_pos + count - 1; struct iov_iter data; struct xfs_buftarg *target; ssize_t ret = 0; @@ -272,49 +273,21 @@ xfs_file_dio_aio_read( file_accessed(iocb->ki_filp); - /* - * Locking is a bit tricky here. If we take an exclusive lock for direct - * IO, we effectively serialise all new concurrent read IO to this file - * and block it behind IO that is currently in progress because IO in - * progress holds the IO lock shared. We only need to hold the lock - * exclusive to blow away the page cache, so only take lock exclusively - * if the page cache needs invalidation. This allows the normal direct - * IO case of no page cache pages to proceeed concurrently without - * serialisation. - */ xfs_rw_ilock(ip, XFS_IOLOCK_SHARED); if (mapping->nrpages) { - xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); - xfs_rw_ilock(ip, XFS_IOLOCK_EXCL); + ret = filemap_write_and_wait_range(mapping, iocb->ki_pos, end); + if (ret) + goto out_unlock; /* - * The generic dio code only flushes the range of the particular - * I/O. Because we take an exclusive lock here, this whole - * sequence is considerably more expensive for us. This has a - * noticeable performance impact for any file with cached pages, - * even when outside of the range of the particular I/O. - * - * Hence, amortize the cost of the lock against a full file - * flush and reduce the chances of repeated iolock cycles going - * forward. + * Invalidate whole pages. This can return an error if we fail + * to invalidate a page, but this should never happen on XFS. + * Warn if it does fail. */ - if (mapping->nrpages) { - ret = filemap_write_and_wait(mapping); - if (ret) { - xfs_rw_iunlock(ip, XFS_IOLOCK_EXCL); - return ret; - } - - /* - * Invalidate whole pages. This can return an error if - * we fail to invalidate a page, but this should never - * happen on XFS. Warn if it does fail. - */ - ret = invalidate_inode_pages2(mapping); - WARN_ON_ONCE(ret); - ret = 0; - } - xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL); + ret = invalidate_inode_pages2_range(mapping, + iocb->ki_pos >> PAGE_SHIFT, end >> PAGE_SHIFT); + WARN_ON_ONCE(ret); + ret = 0; } data = *to; @@ -324,8 +297,9 @@ xfs_file_dio_aio_read( iocb->ki_pos += ret; iov_iter_advance(to, ret); } - xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); +out_unlock: + xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); return ret; } @@ -570,61 +544,49 @@ xfs_file_dio_aio_write( if ((iocb->ki_pos | count) & target->bt_logical_sectormask) return -EINVAL; - /* "unaligned" here means not aligned to a filesystem block */ - if ((iocb->ki_pos & mp->m_blockmask) || - ((iocb->ki_pos + count) & mp->m_blockmask)) - unaligned_io = 1; - /* - * We don't need to take an exclusive lock unless there page cache needs - * to be invalidated or unaligned IO is being executed. We don't need to - * consider the EOF extension case here because - * xfs_file_aio_write_checks() will relock the inode as necessary for - * EOF zeroing cases and fill out the new inode size as appropriate. + * Don't take the exclusive iolock here unless the I/O is unaligned to + * the file system block size. We don't need to consider the EOF + * extension case here because xfs_file_aio_write_checks() will relock + * the inode as necessary for EOF zeroing cases and fill out the new + * inode size as appropriate. */ - if (unaligned_io || mapping->nrpages) + if ((iocb->ki_pos & mp->m_blockmask) || + ((iocb->ki_pos + count) & mp->m_blockmask)) { + unaligned_io = 1; iolock = XFS_IOLOCK_EXCL; - else + } else { iolock = XFS_IOLOCK_SHARED; - xfs_rw_ilock(ip, iolock); - - /* - * Recheck if there are cached pages that need invalidate after we got - * the iolock to protect against other threads adding new pages while - * we were waiting for the iolock. - */ - if (mapping->nrpages && iolock == XFS_IOLOCK_SHARED) { - xfs_rw_iunlock(ip, iolock); - iolock = XFS_IOLOCK_EXCL; - xfs_rw_ilock(ip, iolock); } + xfs_rw_ilock(ip, iolock); + ret = xfs_file_aio_write_checks(iocb, from, &iolock); if (ret) goto out; count = iov_iter_count(from); end = iocb->ki_pos + count - 1; - /* - * See xfs_file_dio_aio_read() for why we do a full-file flush here. - */ if (mapping->nrpages) { - ret = filemap_write_and_wait(VFS_I(ip)->i_mapping); + ret = filemap_write_and_wait_range(mapping, iocb->ki_pos, end); if (ret) goto out; + /* * Invalidate whole pages. This can return an error if we fail * to invalidate a page, but this should never happen on XFS. * Warn if it does fail. */ - ret = invalidate_inode_pages2(VFS_I(ip)->i_mapping); + ret = invalidate_inode_pages2_range(mapping, + iocb->ki_pos >> PAGE_SHIFT, end >> PAGE_SHIFT); WARN_ON_ONCE(ret); ret = 0; } /* * If we are doing unaligned IO, wait for all other IO to drain, - * otherwise demote the lock if we had to flush cached pages + * otherwise demote the lock if we had to take the exclusive lock + * for other reasons in xfs_file_aio_write_checks. */ if (unaligned_io) inode_dio_wait(inode); -- GitLab From fe23759eaf2f6540de20c1623f066aad967ff9c9 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Thu, 20 Oct 2016 15:44:53 +1100 Subject: [PATCH 0813/1167] xfs: remove pointless error goto in xfs_bmap_remap_alloc The commit: f65306ea xfs: map an inode's offset to an exact physical block added a pointless error0: target; remove it. Addresses-Coverity-Id: 1373865 Signed-off-by: Eric Sandeen Reviewed-by: Bill O'Donnell Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_bmap.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 0283b7eaf973c..80bdb11ca6bfb 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -3974,9 +3974,6 @@ xfs_bmap_remap_alloc( * allocating, so skip that check by pretending to be freeing. */ error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); - if (error) - goto error0; -error0: xfs_perag_put(args.pag); if (error) trace_xfs_bmap_remap_alloc_error(ap->ip, error, _RET_IP_); -- GitLab From d099245297e28fc9f8493edd9d5a1f0967a72511 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 20 Oct 2016 15:45:40 +1100 Subject: [PATCH 0814/1167] xfs: unset MS_ACTIVE if mount fails As part of the inode block map intent log item recovery process, we had to set the IRECOVERY flag to prevent an unlinked inode from being truncated during the first iput call. This required us to set MS_ACTIVE so that iput puts the inode on the lru instead of immediately evicting the inode. Unfortunately, if the mount fails later on, the inodes that have been loaded (root dir and realtime) actually need to be evicted since we're aborting the mount. If we don't clear MS_ACTIVE in the failure step, those inodes are not evicted and therefore leak. The leak was found by running xfs/130 and rmmoding xfs immediately after the test. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner --- fs/xfs/xfs_mount.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index fc7873942bea5..b341f10cf4810 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1009,6 +1009,7 @@ xfs_mountfs( out_quota: xfs_qm_unmount_quotas(mp); out_rtunmount: + mp->m_super->s_flags &= ~MS_ACTIVE; xfs_rtunmount_inodes(mp); out_rele_rip: IRELE(rip); -- GitLab From 58d789678546d46d7bbd809dd7dab417c0f23655 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 20 Oct 2016 15:46:18 +1100 Subject: [PATCH 0815/1167] libxfs: clean up _calc_dquots_per_chunk The function xfs_calc_dquots_per_chunk takes a parameter in units of basic blocks. The kernel seems to get the units wrong, but userspace got 'fixed' by commenting out the unnecessary conversion. Fix both. cc: Signed-off-by: Darrick J. Wong Reviewed-by: Eric Sandeen Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_dquot_buf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c index 3cc3cf7674746..ac9a003dd29ac 100644 --- a/fs/xfs/libxfs/xfs_dquot_buf.c +++ b/fs/xfs/libxfs/xfs_dquot_buf.c @@ -191,8 +191,7 @@ xfs_dquot_buf_verify_crc( if (mp->m_quotainfo) ndquots = mp->m_quotainfo->qi_dqperchunk; else - ndquots = xfs_calc_dquots_per_chunk( - XFS_BB_TO_FSB(mp, bp->b_length)); + ndquots = xfs_calc_dquots_per_chunk(bp->b_length); for (i = 0; i < ndquots; i++, d++) { if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk), -- GitLab From 8cdcc8102c0cfad20513ed1bfb96e0e9963928a8 Mon Sep 17 00:00:00 2001 From: Roger Willcocks Date: Thu, 20 Oct 2016 15:48:38 +1100 Subject: [PATCH 0816/1167] libxfs: v3 inodes are only valid on crc-enabled filesystems xfs_repair was not detecting that version 3 inodes are invalid for for non-CRC filesystems. The result is specific inode corruptions go undetected and hence aren't repaired if only the version number is out of range. The core of the problem is that the XFS_DINODE_GOOD_VERSION() macro doesn't know that valid inode versions are dependent on a superblock version number. Fix this in libxfs, and propagate the new function out into the rest of xfsprogs to fix the issue. [Darrick: port to kernel from xfsprogs] Reported-by: Leslie Rhorer Signed-off-by: Roger Willcocks Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_format.h | 1 - fs/xfs/libxfs/xfs_inode_buf.c | 13 ++++++++++++- fs/xfs/libxfs/xfs_inode_buf.h | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index f6547fc5e016e..6b7579e7b60a2 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -865,7 +865,6 @@ typedef struct xfs_timestamp { * padding field for v3 inodes. */ #define XFS_DINODE_MAGIC 0x494e /* 'IN' */ -#define XFS_DINODE_GOOD_VERSION(v) ((v) >= 1 && (v) <= 3) typedef struct xfs_dinode { __be16 di_magic; /* inode magic # = XFS_DINODE_MAGIC */ __be16 di_mode; /* mode and type of file */ diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c index 8de9a3a29589b..134424fac434f 100644 --- a/fs/xfs/libxfs/xfs_inode_buf.c +++ b/fs/xfs/libxfs/xfs_inode_buf.c @@ -57,6 +57,17 @@ xfs_inobp_check( } #endif +bool +xfs_dinode_good_version( + struct xfs_mount *mp, + __u8 version) +{ + if (xfs_sb_version_hascrc(&mp->m_sb)) + return version == 3; + + return version == 1 || version == 2; +} + /* * If we are doing readahead on an inode buffer, we might be in log recovery * reading an inode allocation buffer that hasn't yet been replayed, and hence @@ -91,7 +102,7 @@ xfs_inode_buf_verify( dip = xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog)); di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) && - XFS_DINODE_GOOD_VERSION(dip->di_version); + xfs_dinode_good_version(mp, dip->di_version); if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, XFS_RANDOM_ITOBP_INOTOBP))) { diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h index 62d9d4681c8c2..3cfe12a4f58ac 100644 --- a/fs/xfs/libxfs/xfs_inode_buf.h +++ b/fs/xfs/libxfs/xfs_inode_buf.h @@ -74,6 +74,8 @@ void xfs_inode_from_disk(struct xfs_inode *ip, struct xfs_dinode *from); void xfs_log_dinode_to_disk(struct xfs_log_dinode *from, struct xfs_dinode *to); +bool xfs_dinode_good_version(struct xfs_mount *mp, __u8 version); + #if defined(DEBUG) void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); #else -- GitLab From 4fbc2c65255f77b315a4ee3ccac397d677a35737 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:48:54 +1100 Subject: [PATCH 0817/1167] xfs: remove the same fs check from xfs_file_share_range The VFS already does the check, and the placement of this duplicate is in the way of the following locking rework. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/xfs_file.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 0dc9971d3c84a..194f8f396e4d0 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -965,9 +965,6 @@ xfs_file_share_range( IS_SWAPFILE(inode_out)) return -ETXTBSY; - /* Reflink only works within this filesystem. */ - if (inode_in->i_sb != inode_out->i_sb) - return -EXDEV; same_inode = (inode_in->i_ino == inode_out->i_ino); /* Don't reflink dirs, pipes, sockets... */ -- GitLab From a62e82b35b97e60e9e22a4e303900f342139822f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:49:03 +1100 Subject: [PATCH 0818/1167] xfs: fix the same_inode check in xfs_file_share_range The VFS i_ino is an unsigned long, while XFS inode numbers are 64-bit wide, so checking i_ino for equality could lead to rate false positives on 32-bit architectures. Just compare the inode pointers themselves to be safe. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/xfs_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 194f8f396e4d0..d5b835e82b2d4 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -965,7 +965,7 @@ xfs_file_share_range( IS_SWAPFILE(inode_out)) return -ETXTBSY; - same_inode = (inode_in->i_ino == inode_out->i_ino); + same_inode = (inode_in == inode_out); /* Don't reflink dirs, pipes, sockets... */ if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode)) -- GitLab From 576177818e6f1e65f6109ed4a8fae8b60131c861 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:49:19 +1100 Subject: [PATCH 0819/1167] xfs: move inode locking from xfs_reflink_remap_range to xfs_file_share_range We need the iolock protection to stabilizie the IS_SWAPFILE and IS_IMMUTABLE values, as well as preventing new buffered writers re-dirtying the file data that we just wrote out. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/xfs_file.c | 62 +++++++++++++++++++++++++++++--------------- fs/xfs/xfs_reflink.c | 15 ----------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index d5b835e82b2d4..663761edd778c 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -958,38 +958,54 @@ xfs_file_share_range( inode_out = file_inode(file_out); bs = inode_out->i_sb->s_blocksize; + /* Lock both files against IO */ + same_inode = (inode_in == inode_out); + if (same_inode) { + xfs_ilock(XFS_I(inode_in), XFS_IOLOCK_EXCL); + xfs_ilock(XFS_I(inode_in), XFS_MMAPLOCK_EXCL); + } else { + xfs_lock_two_inodes(XFS_I(inode_in), XFS_I(inode_out), + XFS_IOLOCK_EXCL); + xfs_lock_two_inodes(XFS_I(inode_in), XFS_I(inode_out), + XFS_MMAPLOCK_EXCL); + } + /* Don't touch certain kinds of inodes */ + ret = -EPERM; if (IS_IMMUTABLE(inode_out)) - return -EPERM; - if (IS_SWAPFILE(inode_in) || - IS_SWAPFILE(inode_out)) - return -ETXTBSY; - - same_inode = (inode_in == inode_out); + goto out_unlock; + ret = -ETXTBSY; + if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out)) + goto out_unlock; /* Don't reflink dirs, pipes, sockets... */ + ret = -EISDIR; if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode)) - return -EISDIR; + goto out_unlock; + ret = -EINVAL; if (S_ISFIFO(inode_in->i_mode) || S_ISFIFO(inode_out->i_mode)) - return -EINVAL; + goto out_unlock; if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode)) - return -EINVAL; + goto out_unlock; /* Don't share DAX file data for now. */ if (IS_DAX(inode_in) || IS_DAX(inode_out)) - return -EINVAL; + goto out_unlock; /* Are we going all the way to the end? */ isize = i_size_read(inode_in); - if (isize == 0) - return 0; + if (isize == 0) { + ret = 0; + goto out_unlock; + } + if (len == 0) len = isize - pos_in; /* Ensure offsets don't wrap and the input is inside i_size */ if (pos_in + len < pos_in || pos_out + len < pos_out || pos_in + len > isize) - return -EINVAL; + goto out_unlock; /* Don't allow dedupe past EOF in the dest file */ if (is_dedupe) { @@ -997,7 +1013,7 @@ xfs_file_share_range( disize = i_size_read(inode_out); if (pos_out >= disize || pos_out + len > disize) - return -EINVAL; + goto out_unlock; } /* If we're linking to EOF, continue to the block boundary. */ @@ -1009,28 +1025,32 @@ xfs_file_share_range( /* Only reflink if we're aligned to block boundaries */ if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) || !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs)) - return -EINVAL; + goto out_unlock; /* Don't allow overlapped reflink within the same file */ if (same_inode && pos_out + blen > pos_in && pos_out < pos_in + blen) - return -EINVAL; + goto out_unlock; /* Wait for the completion of any pending IOs on srcfile */ ret = xfs_file_wait_for_io(inode_in, pos_in, len); if (ret) - goto out; + goto out_unlock; ret = xfs_file_wait_for_io(inode_out, pos_out, len); if (ret) - goto out; + goto out_unlock; if (is_dedupe) flags |= XFS_REFLINK_DEDUPE; ret = xfs_reflink_remap_range(XFS_I(inode_in), pos_in, XFS_I(inode_out), pos_out, len, flags); - if (ret < 0) - goto out; -out: +out_unlock: + xfs_iunlock(XFS_I(inode_in), XFS_MMAPLOCK_EXCL); + xfs_iunlock(XFS_I(inode_in), XFS_IOLOCK_EXCL); + if (!same_inode) { + xfs_iunlock(XFS_I(inode_out), XFS_MMAPLOCK_EXCL); + xfs_iunlock(XFS_I(inode_out), XFS_IOLOCK_EXCL); + } return ret; } diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index d48a7cc2fe007..3b1c1a6bb5da9 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -1341,15 +1341,6 @@ xfs_reflink_remap_range( trace_xfs_reflink_remap_range(src, srcoff, len, dest, destoff); - /* Lock both files against IO */ - if (src->i_ino == dest->i_ino) { - xfs_ilock(src, XFS_IOLOCK_EXCL); - xfs_ilock(src, XFS_MMAPLOCK_EXCL); - } else { - xfs_lock_two_inodes(src, dest, XFS_IOLOCK_EXCL); - xfs_lock_two_inodes(src, dest, XFS_MMAPLOCK_EXCL); - } - /* * Check that the extents are the same. */ @@ -1401,12 +1392,6 @@ xfs_reflink_remap_range( goto out_error; out_error: - xfs_iunlock(src, XFS_MMAPLOCK_EXCL); - xfs_iunlock(src, XFS_IOLOCK_EXCL); - if (src->i_ino != dest->i_ino) { - xfs_iunlock(dest, XFS_MMAPLOCK_EXCL); - xfs_iunlock(dest, XFS_IOLOCK_EXCL); - } if (error) trace_xfs_reflink_remap_range_error(dest, error, _RET_IP_); return error; -- GitLab From ec40759902556f21f37641ad9f19d02c4dd4b555 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:49:55 +1100 Subject: [PATCH 0820/1167] xfs: remove xfs_file_wait_for_io filemap_write_and_wait_range operates on full pages, so there is no need for the rounding operations. Additionally this allows us to micro-optimize by skipping the second inode_dio_wait for a intra-file clone. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/xfs_file.c | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 663761edd778c..93729752bccb3 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -909,32 +909,6 @@ xfs_file_fallocate( return error; } -/* - * Flush all file writes out to disk. - */ -static int -xfs_file_wait_for_io( - struct inode *inode, - loff_t offset, - size_t len) -{ - loff_t rounding; - loff_t ioffset; - loff_t iendoffset; - loff_t bs; - int ret; - - bs = inode->i_sb->s_blocksize; - inode_dio_wait(inode); - - rounding = max_t(xfs_off_t, bs, PAGE_SIZE); - ioffset = round_down(offset, rounding); - iendoffset = round_up(offset + len, rounding) - 1; - ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, - iendoffset); - return ret; -} - /* Hook up to the VFS reflink function */ STATIC int xfs_file_share_range( @@ -1031,11 +1005,18 @@ xfs_file_share_range( if (same_inode && pos_out + blen > pos_in && pos_out < pos_in + blen) goto out_unlock; - /* Wait for the completion of any pending IOs on srcfile */ - ret = xfs_file_wait_for_io(inode_in, pos_in, len); + /* Wait for the completion of any pending IOs on both files */ + inode_dio_wait(inode_in); + if (!same_inode) + inode_dio_wait(inode_out); + + ret = filemap_write_and_wait_range(inode_in->i_mapping, + pos_in, pos_in + len - 1); if (ret) goto out_unlock; - ret = xfs_file_wait_for_io(inode_out, pos_out, len); + + ret = filemap_write_and_wait_range(inode_out->i_mapping, + pos_out, pos_out + len - 1); if (ret) goto out_unlock; -- GitLab From 5faaf4fa0a20d38edc4df57baf24ea35b7e91178 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:50:07 +1100 Subject: [PATCH 0821/1167] xfs: merge xfs_reflink_remap_range and xfs_file_share_range There is no clear division of responsibility between those functions, so just merge them into one to keep the code simple. Also move xfs_file_wait_for_io to xfs_reflink.c together with its only caller. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/xfs_file.c | 132 +------------------------------- fs/xfs/xfs_reflink.c | 178 +++++++++++++++++++++++++++++++++---------- fs/xfs/xfs_reflink.h | 7 +- 3 files changed, 143 insertions(+), 174 deletions(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 93729752bccb3..6e4f7f900fea4 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -909,132 +909,6 @@ xfs_file_fallocate( return error; } -/* Hook up to the VFS reflink function */ -STATIC int -xfs_file_share_range( - struct file *file_in, - loff_t pos_in, - struct file *file_out, - loff_t pos_out, - u64 len, - bool is_dedupe) -{ - struct inode *inode_in; - struct inode *inode_out; - ssize_t ret; - loff_t bs; - loff_t isize; - int same_inode; - loff_t blen; - unsigned int flags = 0; - - inode_in = file_inode(file_in); - inode_out = file_inode(file_out); - bs = inode_out->i_sb->s_blocksize; - - /* Lock both files against IO */ - same_inode = (inode_in == inode_out); - if (same_inode) { - xfs_ilock(XFS_I(inode_in), XFS_IOLOCK_EXCL); - xfs_ilock(XFS_I(inode_in), XFS_MMAPLOCK_EXCL); - } else { - xfs_lock_two_inodes(XFS_I(inode_in), XFS_I(inode_out), - XFS_IOLOCK_EXCL); - xfs_lock_two_inodes(XFS_I(inode_in), XFS_I(inode_out), - XFS_MMAPLOCK_EXCL); - } - - /* Don't touch certain kinds of inodes */ - ret = -EPERM; - if (IS_IMMUTABLE(inode_out)) - goto out_unlock; - ret = -ETXTBSY; - if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out)) - goto out_unlock; - - /* Don't reflink dirs, pipes, sockets... */ - ret = -EISDIR; - if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode)) - goto out_unlock; - ret = -EINVAL; - if (S_ISFIFO(inode_in->i_mode) || S_ISFIFO(inode_out->i_mode)) - goto out_unlock; - if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode)) - goto out_unlock; - - /* Don't share DAX file data for now. */ - if (IS_DAX(inode_in) || IS_DAX(inode_out)) - goto out_unlock; - - /* Are we going all the way to the end? */ - isize = i_size_read(inode_in); - if (isize == 0) { - ret = 0; - goto out_unlock; - } - - if (len == 0) - len = isize - pos_in; - - /* Ensure offsets don't wrap and the input is inside i_size */ - if (pos_in + len < pos_in || pos_out + len < pos_out || - pos_in + len > isize) - goto out_unlock; - - /* Don't allow dedupe past EOF in the dest file */ - if (is_dedupe) { - loff_t disize; - - disize = i_size_read(inode_out); - if (pos_out >= disize || pos_out + len > disize) - goto out_unlock; - } - - /* If we're linking to EOF, continue to the block boundary. */ - if (pos_in + len == isize) - blen = ALIGN(isize, bs) - pos_in; - else - blen = len; - - /* Only reflink if we're aligned to block boundaries */ - if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) || - !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs)) - goto out_unlock; - - /* Don't allow overlapped reflink within the same file */ - if (same_inode && pos_out + blen > pos_in && pos_out < pos_in + blen) - goto out_unlock; - - /* Wait for the completion of any pending IOs on both files */ - inode_dio_wait(inode_in); - if (!same_inode) - inode_dio_wait(inode_out); - - ret = filemap_write_and_wait_range(inode_in->i_mapping, - pos_in, pos_in + len - 1); - if (ret) - goto out_unlock; - - ret = filemap_write_and_wait_range(inode_out->i_mapping, - pos_out, pos_out + len - 1); - if (ret) - goto out_unlock; - - if (is_dedupe) - flags |= XFS_REFLINK_DEDUPE; - ret = xfs_reflink_remap_range(XFS_I(inode_in), pos_in, XFS_I(inode_out), - pos_out, len, flags); - -out_unlock: - xfs_iunlock(XFS_I(inode_in), XFS_MMAPLOCK_EXCL); - xfs_iunlock(XFS_I(inode_in), XFS_IOLOCK_EXCL); - if (!same_inode) { - xfs_iunlock(XFS_I(inode_out), XFS_MMAPLOCK_EXCL); - xfs_iunlock(XFS_I(inode_out), XFS_IOLOCK_EXCL); - } - return ret; -} - STATIC ssize_t xfs_file_copy_range( struct file *file_in, @@ -1046,7 +920,7 @@ xfs_file_copy_range( { int error; - error = xfs_file_share_range(file_in, pos_in, file_out, pos_out, + error = xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out, len, false); if (error) return error; @@ -1061,7 +935,7 @@ xfs_file_clone_range( loff_t pos_out, u64 len) { - return xfs_file_share_range(file_in, pos_in, file_out, pos_out, + return xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out, len, false); } @@ -1084,7 +958,7 @@ xfs_file_dedupe_range( if (len > XFS_MAX_DEDUPE_LEN) len = XFS_MAX_DEDUPE_LEN; - error = xfs_file_share_range(src_file, loff, dst_file, dst_loff, + error = xfs_reflink_remap_range(src_file, loff, dst_file, dst_loff, len, true); if (error) return error; diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 3b1c1a6bb5da9..6592daa833a40 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -1312,19 +1312,26 @@ xfs_compare_extents( */ int xfs_reflink_remap_range( - struct xfs_inode *src, - xfs_off_t srcoff, - struct xfs_inode *dest, - xfs_off_t destoff, - xfs_off_t len, - unsigned int flags) + struct file *file_in, + loff_t pos_in, + struct file *file_out, + loff_t pos_out, + u64 len, + bool is_dedupe) { + struct inode *inode_in = file_inode(file_in); + struct xfs_inode *src = XFS_I(inode_in); + struct inode *inode_out = file_inode(file_out); + struct xfs_inode *dest = XFS_I(inode_out); struct xfs_mount *mp = src->i_mount; + loff_t bs = inode_out->i_sb->s_blocksize; + bool same_inode = (inode_in == inode_out); xfs_fileoff_t sfsbno, dfsbno; xfs_filblks_t fsblen; - int error; xfs_extlen_t cowextsize; - bool is_same; + loff_t isize; + ssize_t ret; + loff_t blen; if (!xfs_sb_version_hasreflink(&mp->m_sb)) return -EOPNOTSUPP; @@ -1332,48 +1339,135 @@ xfs_reflink_remap_range( if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; + /* Lock both files against IO */ + if (same_inode) { + xfs_ilock(src, XFS_IOLOCK_EXCL); + xfs_ilock(src, XFS_MMAPLOCK_EXCL); + } else { + xfs_lock_two_inodes(src, dest, XFS_IOLOCK_EXCL); + xfs_lock_two_inodes(src, dest, XFS_MMAPLOCK_EXCL); + } + + /* Don't touch certain kinds of inodes */ + ret = -EPERM; + if (IS_IMMUTABLE(inode_out)) + goto out_unlock; + + ret = -ETXTBSY; + if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out)) + goto out_unlock; + + + /* Don't reflink dirs, pipes, sockets... */ + ret = -EISDIR; + if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode)) + goto out_unlock; + ret = -EINVAL; + if (S_ISFIFO(inode_in->i_mode) || S_ISFIFO(inode_out->i_mode)) + goto out_unlock; + if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode)) + goto out_unlock; + /* Don't reflink realtime inodes */ if (XFS_IS_REALTIME_INODE(src) || XFS_IS_REALTIME_INODE(dest)) - return -EINVAL; + goto out_unlock; + + /* Don't share DAX file data for now. */ + if (IS_DAX(inode_in) || IS_DAX(inode_out)) + goto out_unlock; + + /* Are we going all the way to the end? */ + isize = i_size_read(inode_in); + if (isize == 0) { + ret = 0; + goto out_unlock; + } + + if (len == 0) + len = isize - pos_in; + + /* Ensure offsets don't wrap and the input is inside i_size */ + if (pos_in + len < pos_in || pos_out + len < pos_out || + pos_in + len > isize) + goto out_unlock; - if (flags & ~XFS_REFLINK_ALL) - return -EINVAL; + /* Don't allow dedupe past EOF in the dest file */ + if (is_dedupe) { + loff_t disize; - trace_xfs_reflink_remap_range(src, srcoff, len, dest, destoff); + disize = i_size_read(inode_out); + if (pos_out >= disize || pos_out + len > disize) + goto out_unlock; + } + + /* If we're linking to EOF, continue to the block boundary. */ + if (pos_in + len == isize) + blen = ALIGN(isize, bs) - pos_in; + else + blen = len; + + /* Only reflink if we're aligned to block boundaries */ + if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) || + !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs)) + goto out_unlock; + + /* Don't allow overlapped reflink within the same file */ + if (same_inode) { + if (pos_out + blen > pos_in && pos_out < pos_in + blen) + goto out_unlock; + } + + /* Wait for the completion of any pending IOs on both files */ + inode_dio_wait(inode_in); + if (!same_inode) + inode_dio_wait(inode_out); + + ret = filemap_write_and_wait_range(inode_in->i_mapping, + pos_in, pos_in + len - 1); + if (ret) + goto out_unlock; + + ret = filemap_write_and_wait_range(inode_out->i_mapping, + pos_out, pos_out + len - 1); + if (ret) + goto out_unlock; + + trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out); /* * Check that the extents are the same. */ - if (flags & XFS_REFLINK_DEDUPE) { - is_same = false; - error = xfs_compare_extents(VFS_I(src), srcoff, VFS_I(dest), - destoff, len, &is_same); - if (error) - goto out_error; + if (is_dedupe) { + bool is_same = false; + + ret = xfs_compare_extents(inode_in, pos_in, inode_out, pos_out, + len, &is_same); + if (ret) + goto out_unlock; if (!is_same) { - error = -EBADE; - goto out_error; + ret = -EBADE; + goto out_unlock; } } - error = xfs_reflink_set_inode_flag(src, dest); - if (error) - goto out_error; + ret = xfs_reflink_set_inode_flag(src, dest); + if (ret) + goto out_unlock; /* * Invalidate the page cache so that we can clear any CoW mappings * in the destination file. */ - truncate_inode_pages_range(&VFS_I(dest)->i_data, destoff, - PAGE_ALIGN(destoff + len) - 1); + truncate_inode_pages_range(&inode_out->i_data, pos_out, + PAGE_ALIGN(pos_out + len) - 1); - dfsbno = XFS_B_TO_FSBT(mp, destoff); - sfsbno = XFS_B_TO_FSBT(mp, srcoff); + dfsbno = XFS_B_TO_FSBT(mp, pos_out); + sfsbno = XFS_B_TO_FSBT(mp, pos_in); fsblen = XFS_B_TO_FSB(mp, len); - error = xfs_reflink_remap_blocks(src, sfsbno, dest, dfsbno, fsblen, - destoff + len); - if (error) - goto out_error; + ret = xfs_reflink_remap_blocks(src, sfsbno, dest, dfsbno, fsblen, + pos_out + len); + if (ret) + goto out_unlock; /* * Carry the cowextsize hint from src to dest if we're sharing the @@ -1381,20 +1475,24 @@ xfs_reflink_remap_range( * has a cowextsize hint, and the destination file does not. */ cowextsize = 0; - if (srcoff == 0 && len == i_size_read(VFS_I(src)) && + if (pos_in == 0 && len == i_size_read(inode_in) && (src->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) && - destoff == 0 && len >= i_size_read(VFS_I(dest)) && + pos_out == 0 && len >= i_size_read(inode_out) && !(dest->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE)) cowextsize = src->i_d.di_cowextsize; - error = xfs_reflink_update_dest(dest, destoff + len, cowextsize); - if (error) - goto out_error; + ret = xfs_reflink_update_dest(dest, pos_out + len, cowextsize); -out_error: - if (error) - trace_xfs_reflink_remap_range_error(dest, error, _RET_IP_); - return error; +out_unlock: + xfs_iunlock(src, XFS_MMAPLOCK_EXCL); + xfs_iunlock(src, XFS_IOLOCK_EXCL); + if (src->i_ino != dest->i_ino) { + xfs_iunlock(dest, XFS_MMAPLOCK_EXCL); + xfs_iunlock(dest, XFS_IOLOCK_EXCL); + } + if (ret) + trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_); + return ret; } /* diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h index 5dc3c8ac12aa5..7ddd9f69560da 100644 --- a/fs/xfs/xfs_reflink.h +++ b/fs/xfs/xfs_reflink.h @@ -43,11 +43,8 @@ extern int xfs_reflink_cancel_cow_range(struct xfs_inode *ip, xfs_off_t offset, extern int xfs_reflink_end_cow(struct xfs_inode *ip, xfs_off_t offset, xfs_off_t count); extern int xfs_reflink_recover_cow(struct xfs_mount *mp); -#define XFS_REFLINK_DEDUPE 1 /* only reflink if contents match */ -#define XFS_REFLINK_ALL (XFS_REFLINK_DEDUPE) -extern int xfs_reflink_remap_range(struct xfs_inode *src, xfs_off_t srcoff, - struct xfs_inode *dest, xfs_off_t destoff, xfs_off_t len, - unsigned int flags); +extern int xfs_reflink_remap_range(struct file *file_in, loff_t pos_in, + struct file *file_out, loff_t pos_out, u64 len, bool is_dedupe); extern int xfs_reflink_clear_inode_flag(struct xfs_inode *ip, struct xfs_trans **tpp); extern int xfs_reflink_unshare(struct xfs_inode *ip, xfs_off_t offset, -- GitLab From d33fd776f992332be110f6ceca6dad60cb5d513f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:51:28 +1100 Subject: [PATCH 0822/1167] iomap: add IOMAP_REPORT This allows the file system to tell a FIEMAP from a read operation, and thus avoids the need to report flags that aren't actually used in the read path. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/iomap.c | 2 +- include/linux/iomap.h | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/fs/iomap.c b/fs/iomap.c index 013d1d36fbbf7..a92204012e2d8 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -561,7 +561,7 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, } while (len > 0) { - ret = iomap_apply(inode, start, len, 0, ops, &ctx, + ret = iomap_apply(inode, start, len, IOMAP_REPORT, ops, &ctx, iomap_fiemap_actor); /* inode with no (attribute) mapping will give ENOENT */ if (ret == -ENOENT) diff --git a/include/linux/iomap.h b/include/linux/iomap.h index e63e288dee836..7892f55a1866d 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -19,11 +19,15 @@ struct vm_fault; #define IOMAP_UNWRITTEN 0x04 /* blocks allocated @blkno in unwritten state */ /* - * Flags for iomap mappings: + * Flags for all iomap mappings: */ -#define IOMAP_F_MERGED 0x01 /* contains multiple blocks/extents */ -#define IOMAP_F_SHARED 0x02 /* block shared with another file */ -#define IOMAP_F_NEW 0x04 /* blocks have been newly allocated */ +#define IOMAP_F_NEW 0x01 /* blocks have been newly allocated */ + +/* + * Flags that only need to be reported for IOMAP_REPORT requests: + */ +#define IOMAP_F_MERGED 0x10 /* contains multiple blocks/extents */ +#define IOMAP_F_SHARED 0x20 /* block shared with another file */ /* * Magic value for blkno: @@ -42,8 +46,9 @@ struct iomap { /* * Flags for iomap_begin / iomap_end. No flag implies a read. */ -#define IOMAP_WRITE (1 << 0) -#define IOMAP_ZERO (1 << 1) +#define IOMAP_WRITE (1 << 0) /* writing, must allocate blocks */ +#define IOMAP_ZERO (1 << 1) /* zeroing operation, may skip holes */ +#define IOMAP_REPORT (1 << 2) /* report extent status, e.g. FIEMAP */ struct iomap_ops { /* -- GitLab From 0a0af28cad9a43d90f13c2047bd8ee3d4cffb7f3 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 20 Oct 2016 15:51:50 +1100 Subject: [PATCH 0823/1167] xfs: add xfs_trim_extent This helpers allows to trim an extent to a subset of it's original range while making sure the block numbers in it remain valid, In the future xfs_trim_extent and xfs_bmapi_trim_map should probably be merged in some form. Signed-off-by: Darrick J. Wong [hch: split from a previous patch from Darrick, moved around and added support for "raw" delayed extents"] Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_bmap.c | 33 +++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_bmap.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 80bdb11ca6bfb..381e7659598c9 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -3996,6 +3996,39 @@ xfs_bmap_alloc( return xfs_bmap_btalloc(ap); } +/* Trim extent to fit a logical block range. */ +void +xfs_trim_extent( + struct xfs_bmbt_irec *irec, + xfs_fileoff_t bno, + xfs_filblks_t len) +{ + xfs_fileoff_t distance; + xfs_fileoff_t end = bno + len; + + if (irec->br_startoff + irec->br_blockcount <= bno || + irec->br_startoff >= end) { + irec->br_blockcount = 0; + return; + } + + if (irec->br_startoff < bno) { + distance = bno - irec->br_startoff; + if (isnullstartblock(irec->br_startblock)) + irec->br_startblock = DELAYSTARTBLOCK; + if (irec->br_startblock != DELAYSTARTBLOCK && + irec->br_startblock != HOLESTARTBLOCK) + irec->br_startblock += distance; + irec->br_startoff += distance; + irec->br_blockcount -= distance; + } + + if (end < irec->br_startoff + irec->br_blockcount) { + distance = irec->br_startoff + irec->br_blockcount - end; + irec->br_blockcount -= distance; + } +} + /* * Trim the returned map to the required bounds */ diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index f97db71325645..eb86af0c988bd 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -190,6 +190,8 @@ void xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt, #define XFS_BMAP_TRACE_EXLIST(ip,c,w) #endif +void xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno, + xfs_filblks_t len); int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd); void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork); void xfs_bmap_add_free(struct xfs_mount *mp, struct xfs_defer_ops *dfops, -- GitLab From 62c5ac89de7d5eecdbaa94ca3d554b0bd41578b1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:52:00 +1100 Subject: [PATCH 0824/1167] xfs: handle "raw" delayed extents xfs_reflink_trim_around_shared Delalloc extents in the extent list contain the number of reserved indirect blocks in their startblock value and don't use the magic DELAYSTARTBLOCK constant. Ensure that xfs_reflink_trim_around_shared handles them properly by checking for isnullstartblock(). Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_reflink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 6592daa833a40..6c4c215634ec6 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -182,7 +182,8 @@ xfs_reflink_trim_around_shared( if (!xfs_is_reflink_inode(ip) || ISUNWRITTEN(irec) || irec->br_startblock == HOLESTARTBLOCK || - irec->br_startblock == DELAYSTARTBLOCK) { + irec->br_startblock == DELAYSTARTBLOCK || + isnullstartblock(irec->br_startblock)) { *shared = false; return 0; } -- GitLab From 5f9268ca53aca992106d74edde3e7cf6c1be60a0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:53:32 +1100 Subject: [PATCH 0825/1167] xfs: don't bother looking at the refcount tree for reads There is no need to trim an extent into a shared or non-shared one, or report any flags for plain old reads. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_iomap.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index d907eb9f8ef32..1dabf2eb136ac 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -996,11 +996,14 @@ xfs_file_iomap_begin( return error; } - /* Trim the mapping to the nearest shared extent boundary. */ - error = xfs_reflink_trim_around_shared(ip, &imap, &shared, &trimmed); - if (error) { - xfs_iunlock(ip, lockmode); - return error; + if (flags & (IOMAP_WRITE | IOMAP_ZERO | IOMAP_REPORT)) { + /* Trim the mapping to the nearest shared extent boundary. */ + error = xfs_reflink_trim_around_shared(ip, &imap, &shared, + &trimmed); + if (error) { + xfs_iunlock(ip, lockmode); + return error; + } } if ((flags & IOMAP_WRITE) && imap_needs_alloc(inode, &imap, nimaps)) { -- GitLab From 3ba020befef030aaabbd5eb82a09f6ddf02a9542 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:53:50 +1100 Subject: [PATCH 0826/1167] xfs: optimize writes to reflink files Instead of reserving space as the first thing in write_begin move it past reading the extent in the data fork. That way we only have to read from the data fork once and can reuse that information for trimming the extent to the shared/unshared boundary. Additionally this allows to easily limit the actual write size to said boundary, and avoid a roundtrip on the ilock. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_iomap.c | 56 +++++++++++------ fs/xfs/xfs_reflink.c | 142 ++++++++++++++++++------------------------- fs/xfs/xfs_reflink.h | 4 +- fs/xfs/xfs_trace.h | 3 +- 4 files changed, 100 insertions(+), 105 deletions(-) diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 1dabf2eb136ac..436e109bb01e5 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -566,6 +566,17 @@ xfs_file_iomap_begin_delay( xfs_bmap_search_extents(ip, offset_fsb, XFS_DATA_FORK, &eof, &idx, &got, &prev); if (!eof && got.br_startoff <= offset_fsb) { + if (xfs_is_reflink_inode(ip)) { + bool shared; + + end_fsb = min(XFS_B_TO_FSB(mp, offset + count), + maxbytes_fsb); + xfs_trim_extent(&got, offset_fsb, end_fsb - offset_fsb); + error = xfs_reflink_reserve_cow(ip, &got, &shared); + if (error) + goto out_unlock; + } + trace_xfs_iomap_found(ip, offset, count, 0, &got); goto done; } @@ -961,19 +972,13 @@ xfs_file_iomap_begin( struct xfs_mount *mp = ip->i_mount; struct xfs_bmbt_irec imap; xfs_fileoff_t offset_fsb, end_fsb; - bool shared, trimmed; int nimaps = 1, error = 0; + bool shared = false, trimmed = false; unsigned lockmode; if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; - if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { - error = xfs_reflink_reserve_cow_range(ip, offset, length); - if (error < 0) - return error; - } - if ((flags & IOMAP_WRITE) && !IS_DAX(inode) && !xfs_get_extsz_hint(ip)) { /* Reserve delalloc blocks for regular writeback. */ @@ -981,7 +986,16 @@ xfs_file_iomap_begin( iomap); } - lockmode = xfs_ilock_data_map_shared(ip); + /* + * COW writes will allocate delalloc space, so we need to make sure + * to take the lock exclusively here. + */ + if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { + lockmode = XFS_ILOCK_EXCL; + xfs_ilock(ip, XFS_ILOCK_EXCL); + } else { + lockmode = xfs_ilock_data_map_shared(ip); + } ASSERT(offset <= mp->m_super->s_maxbytes); if ((xfs_fsize_t)offset + length > mp->m_super->s_maxbytes) @@ -991,19 +1005,24 @@ xfs_file_iomap_begin( error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap, &nimaps, 0); - if (error) { - xfs_iunlock(ip, lockmode); - return error; - } + if (error) + goto out_unlock; - if (flags & (IOMAP_WRITE | IOMAP_ZERO | IOMAP_REPORT)) { + if (flags & IOMAP_REPORT) { /* Trim the mapping to the nearest shared extent boundary. */ error = xfs_reflink_trim_around_shared(ip, &imap, &shared, &trimmed); - if (error) { - xfs_iunlock(ip, lockmode); - return error; - } + if (error) + goto out_unlock; + } + + if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { + error = xfs_reflink_reserve_cow(ip, &imap, &shared); + if (error) + goto out_unlock; + + end_fsb = imap.br_startoff + imap.br_blockcount; + length = XFS_FSB_TO_B(mp, end_fsb) - offset; } if ((flags & IOMAP_WRITE) && imap_needs_alloc(inode, &imap, nimaps)) { @@ -1042,6 +1061,9 @@ xfs_file_iomap_begin( if (shared) iomap->flags |= IOMAP_F_SHARED; return 0; +out_unlock: + xfs_iunlock(ip, lockmode); + return error; } static int diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 6c4c215634ec6..9c477de3c1acb 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -228,50 +228,54 @@ xfs_reflink_trim_around_shared( } } -/* Create a CoW reservation for a range of blocks within a file. */ -static int -__xfs_reflink_reserve_cow( +/* + * Trim the passed in imap to the next shared/unshared extent boundary, and + * if imap->br_startoff points to a shared extent reserve space for it in the + * COW fork. In this case *shared is set to true, else to false. + * + * Note that imap will always contain the block numbers for the existing blocks + * in the data fork, as the upper layers need them for read-modify-write + * operations. + */ +int +xfs_reflink_reserve_cow( struct xfs_inode *ip, - xfs_fileoff_t *offset_fsb, - xfs_fileoff_t end_fsb, - bool *skipped) + struct xfs_bmbt_irec *imap, + bool *shared) { - struct xfs_bmbt_irec got, prev, imap; - xfs_fileoff_t orig_end_fsb; - int nimaps, eof = 0, error = 0; - bool shared = false, trimmed = false; + struct xfs_bmbt_irec got, prev; + xfs_fileoff_t end_fsb, orig_end_fsb; + int eof = 0, error = 0; + bool trimmed; xfs_extnum_t idx; xfs_extlen_t align; - /* Already reserved? Skip the refcount btree access. */ - xfs_bmap_search_extents(ip, *offset_fsb, XFS_COW_FORK, &eof, &idx, + /* + * Search the COW fork extent list first. This serves two purposes: + * first this implement the speculative preallocation using cowextisze, + * so that we also unshared block adjacent to shared blocks instead + * of just the shared blocks themselves. Second the lookup in the + * extent list is generally faster than going out to the shared extent + * tree. + */ + xfs_bmap_search_extents(ip, imap->br_startoff, XFS_COW_FORK, &eof, &idx, &got, &prev); - if (!eof && got.br_startoff <= *offset_fsb) { - end_fsb = orig_end_fsb = got.br_startoff + got.br_blockcount; - trace_xfs_reflink_cow_found(ip, &got); - goto done; - } + if (!eof && got.br_startoff <= imap->br_startoff) { + trace_xfs_reflink_cow_found(ip, imap); + xfs_trim_extent(imap, got.br_startoff, got.br_blockcount); - /* Read extent from the source file. */ - nimaps = 1; - error = xfs_bmapi_read(ip, *offset_fsb, end_fsb - *offset_fsb, - &imap, &nimaps, 0); - if (error) - goto out_unlock; - ASSERT(nimaps == 1); + *shared = true; + return 0; + } /* Trim the mapping to the nearest shared extent boundary. */ - error = xfs_reflink_trim_around_shared(ip, &imap, &shared, &trimmed); + error = xfs_reflink_trim_around_shared(ip, imap, shared, &trimmed); if (error) - goto out_unlock; - - end_fsb = orig_end_fsb = imap.br_startoff + imap.br_blockcount; + return error; /* Not shared? Just report the (potentially capped) extent. */ - if (!shared) { - *skipped = true; - goto done; - } + if (!*shared) + return 0; /* * Fork all the shared blocks from our write offset until the end of @@ -279,72 +283,38 @@ __xfs_reflink_reserve_cow( */ error = xfs_qm_dqattach_locked(ip, 0); if (error) - goto out_unlock; + return error; + + end_fsb = orig_end_fsb = imap->br_startoff + imap->br_blockcount; align = xfs_eof_alignment(ip, xfs_get_cowextsz_hint(ip)); if (align) end_fsb = roundup_64(end_fsb, align); retry: - error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, *offset_fsb, - end_fsb - *offset_fsb, &got, - &prev, &idx, eof); + error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff, + end_fsb - imap->br_startoff, &got, &prev, &idx, eof); switch (error) { case 0: break; case -ENOSPC: case -EDQUOT: /* retry without any preallocation */ - trace_xfs_reflink_cow_enospc(ip, &imap); + trace_xfs_reflink_cow_enospc(ip, imap); if (end_fsb != orig_end_fsb) { end_fsb = orig_end_fsb; goto retry; } /*FALLTHRU*/ default: - goto out_unlock; + return error; } if (end_fsb != orig_end_fsb) xfs_inode_set_cowblocks_tag(ip); trace_xfs_reflink_cow_alloc(ip, &got); -done: - *offset_fsb = end_fsb; -out_unlock: - return error; -} - -/* Create a CoW reservation for part of a file. */ -int -xfs_reflink_reserve_cow_range( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t count) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t offset_fsb, end_fsb; - bool skipped = false; - int error = 0; - - trace_xfs_reflink_reserve_cow_range(ip, offset, count); - - offset_fsb = XFS_B_TO_FSBT(mp, offset); - end_fsb = XFS_B_TO_FSB(mp, offset + count); - - xfs_ilock(ip, XFS_ILOCK_EXCL); - while (offset_fsb < end_fsb) { - error = __xfs_reflink_reserve_cow(ip, &offset_fsb, end_fsb, - &skipped); - if (error) { - trace_xfs_reflink_reserve_cow_range_error(ip, error, - _RET_IP_); - break; - } - } - xfs_iunlock(ip, XFS_ILOCK_EXCL); - - return error; + return 0; } /* Allocate all CoW reservations covering a range of blocks in a file. */ @@ -359,9 +329,8 @@ __xfs_reflink_allocate_cow( struct xfs_defer_ops dfops; struct xfs_trans *tp; xfs_fsblock_t first_block; - xfs_fileoff_t next_fsb; int nimaps = 1, error; - bool skipped = false; + bool shared; xfs_defer_init(&dfops, &first_block); @@ -372,33 +341,38 @@ __xfs_reflink_allocate_cow( xfs_ilock(ip, XFS_ILOCK_EXCL); - next_fsb = *offset_fsb; - error = __xfs_reflink_reserve_cow(ip, &next_fsb, end_fsb, &skipped); + /* Read extent from the source file. */ + nimaps = 1; + error = xfs_bmapi_read(ip, *offset_fsb, end_fsb - *offset_fsb, + &imap, &nimaps, 0); + if (error) + goto out_unlock; + ASSERT(nimaps == 1); + + error = xfs_reflink_reserve_cow(ip, &imap, &shared); if (error) goto out_trans_cancel; - if (skipped) { - *offset_fsb = next_fsb; + if (!shared) { + *offset_fsb = imap.br_startoff + imap.br_blockcount; goto out_trans_cancel; } xfs_trans_ijoin(tp, ip, 0); - error = xfs_bmapi_write(tp, ip, *offset_fsb, next_fsb - *offset_fsb, + error = xfs_bmapi_write(tp, ip, imap.br_startoff, imap.br_blockcount, XFS_BMAPI_COWFORK, &first_block, XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK), &imap, &nimaps, &dfops); if (error) goto out_trans_cancel; - /* We might not have been able to map the whole delalloc extent */ - *offset_fsb = min(*offset_fsb + imap.br_blockcount, next_fsb); - error = xfs_defer_finish(&tp, &dfops, NULL); if (error) goto out_trans_cancel; error = xfs_trans_commit(tp); + *offset_fsb = imap.br_startoff + imap.br_blockcount; out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h index 7ddd9f69560da..fad11607c9adf 100644 --- a/fs/xfs/xfs_reflink.h +++ b/fs/xfs/xfs_reflink.h @@ -26,8 +26,8 @@ extern int xfs_reflink_find_shared(struct xfs_mount *mp, xfs_agnumber_t agno, extern int xfs_reflink_trim_around_shared(struct xfs_inode *ip, struct xfs_bmbt_irec *irec, bool *shared, bool *trimmed); -extern int xfs_reflink_reserve_cow_range(struct xfs_inode *ip, - xfs_off_t offset, xfs_off_t count); +extern int xfs_reflink_reserve_cow(struct xfs_inode *ip, + struct xfs_bmbt_irec *imap, bool *shared); extern int xfs_reflink_allocate_cow_range(struct xfs_inode *ip, xfs_off_t offset, xfs_off_t count); extern bool xfs_reflink_find_cow_mapping(struct xfs_inode *ip, xfs_off_t offset, diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index ad188d3a83f37..72f9f6b7a76af 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -3346,7 +3346,7 @@ DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_alloc); DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_found); DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_enospc); -DEFINE_RW_EVENT(xfs_reflink_reserve_cow_range); +DEFINE_RW_EVENT(xfs_reflink_reserve_cow); DEFINE_RW_EVENT(xfs_reflink_allocate_cow_range); DEFINE_INODE_IREC_EVENT(xfs_reflink_bounce_dio_write); @@ -3358,7 +3358,6 @@ DEFINE_SIMPLE_IO_EVENT(xfs_reflink_end_cow); DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_remap); DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_remap_piece); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_reserve_cow_range_error); DEFINE_INODE_ERROR_EVENT(xfs_reflink_allocate_cow_range_error); DEFINE_INODE_ERROR_EVENT(xfs_reflink_cancel_cow_range_error); DEFINE_INODE_ERROR_EVENT(xfs_reflink_end_cow_error); -- GitLab From fa5c836ca8eb5bad6316ddfc066acbc4e2485356 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:54:14 +1100 Subject: [PATCH 0827/1167] xfs: refactor xfs_bunmapi_cow Split out two helpers for deleting delayed or real extents from the COW fork. This allows to call them directly from xfs_reflink_cow_end_io once that function is refactored to iterate the extent tree. It will also allow to reuse the delalloc deletion from xfs_bunmapi in the future. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_bmap.c | 374 +++++++++++++++++++++++---------------- fs/xfs/libxfs/xfs_bmap.h | 5 + fs/xfs/xfs_reflink.c | 5 - 3 files changed, 225 insertions(+), 159 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 381e7659598c9..d7ad51132f4ff 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -4859,6 +4859,219 @@ xfs_bmap_split_indlen( return stolen; } +int +xfs_bmap_del_extent_delay( + struct xfs_inode *ip, + int whichfork, + xfs_extnum_t *idx, + struct xfs_bmbt_irec *got, + struct xfs_bmbt_irec *del) +{ + struct xfs_mount *mp = ip->i_mount; + struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); + struct xfs_bmbt_irec new; + int64_t da_old, da_new, da_diff = 0; + xfs_fileoff_t del_endoff, got_endoff; + xfs_filblks_t got_indlen, new_indlen, stolen; + int error = 0, state = 0; + bool isrt; + + XFS_STATS_INC(mp, xs_del_exlist); + + isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); + del_endoff = del->br_startoff + del->br_blockcount; + got_endoff = got->br_startoff + got->br_blockcount; + da_old = startblockval(got->br_startblock); + da_new = 0; + + ASSERT(*idx >= 0); + ASSERT(*idx < ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); + ASSERT(del->br_blockcount > 0); + ASSERT(got->br_startoff <= del->br_startoff); + ASSERT(got_endoff >= del_endoff); + + if (isrt) { + int64_t rtexts = XFS_FSB_TO_B(mp, del->br_blockcount); + + do_div(rtexts, mp->m_sb.sb_rextsize); + xfs_mod_frextents(mp, rtexts); + } + + /* + * Update the inode delalloc counter now and wait to update the + * sb counters as we might have to borrow some blocks for the + * indirect block accounting. + */ + xfs_trans_reserve_quota_nblks(NULL, ip, -((long)del->br_blockcount), 0, + isrt ? XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS); + ip->i_delayed_blks -= del->br_blockcount; + + if (whichfork == XFS_COW_FORK) + state |= BMAP_COWFORK; + + if (got->br_startoff == del->br_startoff) + state |= BMAP_LEFT_CONTIG; + if (got_endoff == del_endoff) + state |= BMAP_RIGHT_CONTIG; + + switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) { + case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: + /* + * Matches the whole extent. Delete the entry. + */ + xfs_iext_remove(ip, *idx, 1, state); + --*idx; + break; + case BMAP_LEFT_CONTIG: + /* + * Deleting the first part of the extent. + */ + trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); + got->br_startoff = del_endoff; + got->br_blockcount -= del->br_blockcount; + da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, + got->br_blockcount), da_old); + got->br_startblock = nullstartblock((int)da_new); + xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); + trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); + break; + case BMAP_RIGHT_CONTIG: + /* + * Deleting the last part of the extent. + */ + trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); + got->br_blockcount = got->br_blockcount - del->br_blockcount; + da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, + got->br_blockcount), da_old); + got->br_startblock = nullstartblock((int)da_new); + xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); + trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); + break; + case 0: + /* + * Deleting the middle of the extent. + * + * Distribute the original indlen reservation across the two new + * extents. Steal blocks from the deleted extent if necessary. + * Stealing blocks simply fudges the fdblocks accounting below. + * Warn if either of the new indlen reservations is zero as this + * can lead to delalloc problems. + */ + trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); + + got->br_blockcount = del->br_startoff - got->br_startoff; + got_indlen = xfs_bmap_worst_indlen(ip, got->br_blockcount); + + new.br_blockcount = got_endoff - del_endoff; + new_indlen = xfs_bmap_worst_indlen(ip, new.br_blockcount); + + WARN_ON_ONCE(!got_indlen || !new_indlen); + stolen = xfs_bmap_split_indlen(da_old, &got_indlen, &new_indlen, + del->br_blockcount); + + got->br_startblock = nullstartblock((int)got_indlen); + xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); + trace_xfs_bmap_post_update(ip, *idx, 0, _THIS_IP_); + + new.br_startoff = del_endoff; + new.br_state = got->br_state; + new.br_startblock = nullstartblock((int)new_indlen); + + ++*idx; + xfs_iext_insert(ip, *idx, 1, &new, state); + + da_new = got_indlen + new_indlen - stolen; + del->br_blockcount -= stolen; + break; + } + + ASSERT(da_old >= da_new); + da_diff = da_old - da_new; + if (!isrt) + da_diff += del->br_blockcount; + if (da_diff) + xfs_mod_fdblocks(mp, da_diff, false); + return error; +} + +void +xfs_bmap_del_extent_cow( + struct xfs_inode *ip, + xfs_extnum_t *idx, + struct xfs_bmbt_irec *got, + struct xfs_bmbt_irec *del) +{ + struct xfs_mount *mp = ip->i_mount; + struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); + struct xfs_bmbt_irec new; + xfs_fileoff_t del_endoff, got_endoff; + int state = BMAP_COWFORK; + + XFS_STATS_INC(mp, xs_del_exlist); + + del_endoff = del->br_startoff + del->br_blockcount; + got_endoff = got->br_startoff + got->br_blockcount; + + ASSERT(*idx >= 0); + ASSERT(*idx < ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); + ASSERT(del->br_blockcount > 0); + ASSERT(got->br_startoff <= del->br_startoff); + ASSERT(got_endoff >= del_endoff); + ASSERT(!isnullstartblock(got->br_startblock)); + + if (got->br_startoff == del->br_startoff) + state |= BMAP_LEFT_CONTIG; + if (got_endoff == del_endoff) + state |= BMAP_RIGHT_CONTIG; + + switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) { + case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: + /* + * Matches the whole extent. Delete the entry. + */ + xfs_iext_remove(ip, *idx, 1, state); + --*idx; + break; + case BMAP_LEFT_CONTIG: + /* + * Deleting the first part of the extent. + */ + trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); + got->br_startoff = del_endoff; + got->br_blockcount -= del->br_blockcount; + got->br_startblock = del->br_startblock + del->br_blockcount; + xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); + trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); + break; + case BMAP_RIGHT_CONTIG: + /* + * Deleting the last part of the extent. + */ + trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); + got->br_blockcount -= del->br_blockcount; + xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); + trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); + break; + case 0: + /* + * Deleting the middle of the extent. + */ + trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); + got->br_blockcount = del->br_startoff - got->br_startoff; + xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); + trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); + + new.br_startoff = del_endoff; + new.br_blockcount = got_endoff - del_endoff; + new.br_state = got->br_state; + new.br_startblock = del->br_startblock + del->br_blockcount; + + ++*idx; + xfs_iext_insert(ip, *idx, 1, &new, state); + break; + } +} + /* * Called by xfs_bmapi to update file extent records and the btree * after removing space (or undoing a delayed allocation). @@ -5207,167 +5420,20 @@ xfs_bunmapi_cow( struct xfs_inode *ip, struct xfs_bmbt_irec *del) { - xfs_filblks_t da_new; - xfs_filblks_t da_old; - xfs_fsblock_t del_endblock = 0; - xfs_fileoff_t del_endoff; - int delay; struct xfs_bmbt_rec_host *ep; - int error; struct xfs_bmbt_irec got; - xfs_fileoff_t got_endoff; - struct xfs_ifork *ifp; - struct xfs_mount *mp; - xfs_filblks_t nblks; struct xfs_bmbt_irec new; - /* REFERENCED */ - uint qfield; - xfs_filblks_t temp; - xfs_filblks_t temp2; - int state = BMAP_COWFORK; int eof; xfs_extnum_t eidx; - mp = ip->i_mount; - XFS_STATS_INC(mp, xs_del_exlist); - ep = xfs_bmap_search_extents(ip, del->br_startoff, XFS_COW_FORK, &eof, - &eidx, &got, &new); - - ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); - ASSERT((eidx >= 0) && (eidx < ifp->if_bytes / - (uint)sizeof(xfs_bmbt_rec_t))); - ASSERT(del->br_blockcount > 0); - ASSERT(got.br_startoff <= del->br_startoff); - del_endoff = del->br_startoff + del->br_blockcount; - got_endoff = got.br_startoff + got.br_blockcount; - ASSERT(got_endoff >= del_endoff); - delay = isnullstartblock(got.br_startblock); - ASSERT(isnullstartblock(del->br_startblock) == delay); - qfield = 0; - error = 0; - /* - * If deleting a real allocation, must free up the disk space. - */ - if (!delay) { - nblks = del->br_blockcount; - qfield = XFS_TRANS_DQ_BCOUNT; - /* - * Set up del_endblock and cur for later. - */ - del_endblock = del->br_startblock + del->br_blockcount; - da_old = da_new = 0; - } else { - da_old = startblockval(got.br_startblock); - da_new = 0; - nblks = 0; - } - qfield = qfield; - nblks = nblks; - - /* - * Set flag value to use in switch statement. - * Left-contig is 2, right-contig is 1. - */ - switch (((got.br_startoff == del->br_startoff) << 1) | - (got_endoff == del_endoff)) { - case 3: - /* - * Matches the whole extent. Delete the entry. - */ - xfs_iext_remove(ip, eidx, 1, BMAP_COWFORK); - --eidx; - break; - - case 2: - /* - * Deleting the first part of the extent. - */ - trace_xfs_bmap_pre_update(ip, eidx, state, _THIS_IP_); - xfs_bmbt_set_startoff(ep, del_endoff); - temp = got.br_blockcount - del->br_blockcount; - xfs_bmbt_set_blockcount(ep, temp); - if (delay) { - temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), - da_old); - xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); - trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_); - da_new = temp; - break; - } - xfs_bmbt_set_startblock(ep, del_endblock); - trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_); - break; - - case 1: - /* - * Deleting the last part of the extent. - */ - temp = got.br_blockcount - del->br_blockcount; - trace_xfs_bmap_pre_update(ip, eidx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, temp); - if (delay) { - temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), - da_old); - xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); - trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_); - da_new = temp; - break; - } - trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_); - break; - - case 0: - /* - * Deleting the middle of the extent. - */ - temp = del->br_startoff - got.br_startoff; - trace_xfs_bmap_pre_update(ip, eidx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, temp); - new.br_startoff = del_endoff; - temp2 = got_endoff - del_endoff; - new.br_blockcount = temp2; - new.br_state = got.br_state; - if (!delay) { - new.br_startblock = del_endblock; - } else { - temp = xfs_bmap_worst_indlen(ip, temp); - xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); - temp2 = xfs_bmap_worst_indlen(ip, temp2); - new.br_startblock = nullstartblock((int)temp2); - da_new = temp + temp2; - while (da_new > da_old) { - if (temp) { - temp--; - da_new--; - xfs_bmbt_set_startblock(ep, - nullstartblock((int)temp)); - } - if (da_new == da_old) - break; - if (temp2) { - temp2--; - da_new--; - new.br_startblock = - nullstartblock((int)temp2); - } - } - } - trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_); - xfs_iext_insert(ip, eidx + 1, 1, &new, state); - ++eidx; - break; - } - - /* - * Account for change in delayed indirect blocks. - * Nothing to do for disk quota accounting here. - */ - ASSERT(da_old >= da_new); - if (da_old > da_new) - xfs_mod_fdblocks(mp, (int64_t)(da_old - da_new), false); - - return error; + &eidx, &got, &new); + ASSERT(ep); + if (isnullstartblock(got.br_startblock)) + xfs_bmap_del_extent_delay(ip, XFS_COW_FORK, &eidx, &got, del); + else + xfs_bmap_del_extent_cow(ip, &eidx, &got, del); + return 0; } /* diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index eb86af0c988bd..5f18248cbac2b 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -224,6 +224,11 @@ int xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip, xfs_extnum_t nexts, xfs_fsblock_t *firstblock, struct xfs_defer_ops *dfops, int *done); int xfs_bunmapi_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *del); +int xfs_bmap_del_extent_delay(struct xfs_inode *ip, int whichfork, + xfs_extnum_t *idx, struct xfs_bmbt_irec *got, + struct xfs_bmbt_irec *del); +void xfs_bmap_del_extent_cow(struct xfs_inode *ip, xfs_extnum_t *idx, + struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del); int xfs_check_nostate_extents(struct xfs_ifork *ifp, xfs_extnum_t idx, xfs_extnum_t num); uint xfs_default_attroffset(struct xfs_inode *ip); diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 9c477de3c1acb..09bd5dcd90cde 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -534,11 +534,6 @@ xfs_reflink_cancel_cow_blocks( trace_xfs_reflink_cancel_cow(ip, &irec); if (irec.br_startblock == DELAYSTARTBLOCK) { - /* Free a delayed allocation. */ - xfs_mod_fdblocks(ip->i_mount, irec.br_blockcount, - false); - ip->i_delayed_blks -= irec.br_blockcount; - /* Remove the mapping from the CoW fork. */ error = xfs_bunmapi_cow(ip, &irec); if (error) -- GitLab From 3e0ee78f7a5a8ed43b129e9e4c5c0ff10c71df74 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:54:31 +1100 Subject: [PATCH 0828/1167] xfs: optimize xfs_reflink_cancel_cow_blocks Rewrite xfs_reflink_cancel_cow_blocks so that we only do a search for the first extent in the extent list and then iterate over the remaining extents using the extent index, passing the extent we operate on directly to xfs_bmap_del_extent_delay or xfs_bmap_del_extent_cow instead of going through xfs_bunmapi and doing yet another extent list lookup. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_reflink.c | 51 ++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 09bd5dcd90cde..1e9c589d22cce 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -511,53 +511,49 @@ xfs_reflink_cancel_cow_blocks( xfs_fileoff_t offset_fsb, xfs_fileoff_t end_fsb) { - struct xfs_bmbt_irec irec; - xfs_filblks_t count_fsb; + struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); + struct xfs_bmbt_irec got, prev, del; + xfs_extnum_t idx; xfs_fsblock_t firstfsb; struct xfs_defer_ops dfops; - int error = 0; - int nimaps; + int error = 0, eof = 0; if (!xfs_is_reflink_inode(ip)) return 0; - /* Go find the old extent in the CoW fork. */ - while (offset_fsb < end_fsb) { - nimaps = 1; - count_fsb = (xfs_filblks_t)(end_fsb - offset_fsb); - error = xfs_bmapi_read(ip, offset_fsb, count_fsb, &irec, - &nimaps, XFS_BMAPI_COWFORK); - if (error) - break; - ASSERT(nimaps == 1); + xfs_bmap_search_extents(ip, offset_fsb, XFS_COW_FORK, &eof, &idx, + &got, &prev); + if (eof) + return 0; - trace_xfs_reflink_cancel_cow(ip, &irec); + while (got.br_startoff < end_fsb) { + del = got; + xfs_trim_extent(&del, offset_fsb, end_fsb - offset_fsb); + trace_xfs_reflink_cancel_cow(ip, &del); - if (irec.br_startblock == DELAYSTARTBLOCK) { - /* Remove the mapping from the CoW fork. */ - error = xfs_bunmapi_cow(ip, &irec); + if (isnullstartblock(del.br_startblock)) { + error = xfs_bmap_del_extent_delay(ip, XFS_COW_FORK, + &idx, &got, &del); if (error) break; - } else if (irec.br_startblock == HOLESTARTBLOCK) { - /* empty */ } else { xfs_trans_ijoin(*tpp, ip, 0); xfs_defer_init(&dfops, &firstfsb); /* Free the CoW orphan record. */ error = xfs_refcount_free_cow_extent(ip->i_mount, - &dfops, irec.br_startblock, - irec.br_blockcount); + &dfops, del.br_startblock, + del.br_blockcount); if (error) break; xfs_bmap_add_free(ip->i_mount, &dfops, - irec.br_startblock, irec.br_blockcount, + del.br_startblock, del.br_blockcount, NULL); /* Update quota accounting */ xfs_trans_mod_dquot_byino(*tpp, ip, XFS_TRANS_DQ_BCOUNT, - -(long)irec.br_blockcount); + -(long)del.br_blockcount); /* Roll the transaction */ error = xfs_defer_finish(tpp, &dfops, ip); @@ -567,13 +563,12 @@ xfs_reflink_cancel_cow_blocks( } /* Remove the mapping from the CoW fork. */ - error = xfs_bunmapi_cow(ip, &irec); - if (error) - break; + xfs_bmap_del_extent_cow(ip, &idx, &got, &del); } - /* Roll on... */ - offset_fsb = irec.br_startoff + irec.br_blockcount; + if (++idx >= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)) + return 0; + xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got); } return error; -- GitLab From c1112b6e626637ec09319883b63e705a931c398b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:54:45 +1100 Subject: [PATCH 0829/1167] xfs: optimize xfs_reflink_end_cow Instead of doing a full extent list search for each extent that is to be deleted using xfs_bmapi_read and then doing another one inside of xfs_bunmapi_cow use the same scheme that xfs_bumapi uses: look up the last extent to be deleted and then use the extent index to walk downward until we are outside the range to be deleted. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_reflink.c | 119 ++++++++++++++++++++----------------------- fs/xfs/xfs_trace.h | 1 - 2 files changed, 56 insertions(+), 64 deletions(-) diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 1e9c589d22cce..cd308f119e20c 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -633,25 +633,26 @@ xfs_reflink_end_cow( xfs_off_t offset, xfs_off_t count) { - struct xfs_bmbt_irec irec; - struct xfs_bmbt_irec uirec; + struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); + struct xfs_bmbt_irec got, prev, del; struct xfs_trans *tp; xfs_fileoff_t offset_fsb; xfs_fileoff_t end_fsb; - xfs_filblks_t count_fsb; xfs_fsblock_t firstfsb; struct xfs_defer_ops dfops; - int error; + int error, eof = 0; unsigned int resblks; - xfs_filblks_t ilen; xfs_filblks_t rlen; - int nimaps; + xfs_extnum_t idx; trace_xfs_reflink_end_cow(ip, offset, count); + /* No COW extents? That's easy! */ + if (ifp->if_bytes == 0) + return 0; + offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset); end_fsb = XFS_B_TO_FSB(ip->i_mount, offset + count); - count_fsb = (xfs_filblks_t)(end_fsb - offset_fsb); /* Start a rolling transaction to switch the mappings */ resblks = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK); @@ -663,72 +664,65 @@ xfs_reflink_end_cow( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); - /* Go find the old extent in the CoW fork. */ - while (offset_fsb < end_fsb) { - /* Read extent from the source file */ - nimaps = 1; - count_fsb = (xfs_filblks_t)(end_fsb - offset_fsb); - error = xfs_bmapi_read(ip, offset_fsb, count_fsb, &irec, - &nimaps, XFS_BMAPI_COWFORK); - if (error) - goto out_cancel; - ASSERT(nimaps == 1); + xfs_bmap_search_extents(ip, end_fsb - 1, XFS_COW_FORK, &eof, &idx, + &got, &prev); - ASSERT(irec.br_startblock != DELAYSTARTBLOCK); - trace_xfs_reflink_cow_remap(ip, &irec); + /* If there is a hole at end_fsb - 1 go to the previous extent */ + if (eof || got.br_startoff > end_fsb) { + ASSERT(idx > 0); + xfs_bmbt_get_all(xfs_iext_get_ext(ifp, --idx), &got); + } - /* - * We can have a hole in the CoW fork if part of a directio - * write is CoW but part of it isn't. - */ - rlen = ilen = irec.br_blockcount; - if (irec.br_startblock == HOLESTARTBLOCK) + /* Walk backwards until we're out of the I/O range... */ + while (got.br_startoff + got.br_blockcount > offset_fsb) { + del = got; + xfs_trim_extent(&del, offset_fsb, end_fsb - offset_fsb); + + /* Extent delete may have bumped idx forward */ + if (!del.br_blockcount) { + idx--; goto next_extent; + } + + ASSERT(!isnullstartblock(got.br_startblock)); /* Unmap the old blocks in the data fork. */ - while (rlen) { - xfs_defer_init(&dfops, &firstfsb); - error = __xfs_bunmapi(tp, ip, irec.br_startoff, - &rlen, 0, 1, &firstfsb, &dfops); - if (error) - goto out_defer; - - /* - * Trim the extent to whatever got unmapped. - * Remember, bunmapi works backwards. - */ - uirec.br_startblock = irec.br_startblock + rlen; - uirec.br_startoff = irec.br_startoff + rlen; - uirec.br_blockcount = irec.br_blockcount - rlen; - irec.br_blockcount = rlen; - trace_xfs_reflink_cow_remap_piece(ip, &uirec); + xfs_defer_init(&dfops, &firstfsb); + rlen = del.br_blockcount; + error = __xfs_bunmapi(tp, ip, del.br_startoff, &rlen, 0, 1, + &firstfsb, &dfops); + if (error) + goto out_defer; - /* Free the CoW orphan record. */ - error = xfs_refcount_free_cow_extent(tp->t_mountp, - &dfops, uirec.br_startblock, - uirec.br_blockcount); - if (error) - goto out_defer; + /* Trim the extent to whatever got unmapped. */ + if (rlen) { + xfs_trim_extent(&del, del.br_startoff + rlen, + del.br_blockcount - rlen); + } + trace_xfs_reflink_cow_remap(ip, &del); - /* Map the new blocks into the data fork. */ - error = xfs_bmap_map_extent(tp->t_mountp, &dfops, - ip, &uirec); - if (error) - goto out_defer; + /* Free the CoW orphan record. */ + error = xfs_refcount_free_cow_extent(tp->t_mountp, &dfops, + del.br_startblock, del.br_blockcount); + if (error) + goto out_defer; - /* Remove the mapping from the CoW fork. */ - error = xfs_bunmapi_cow(ip, &uirec); - if (error) - goto out_defer; + /* Map the new blocks into the data fork. */ + error = xfs_bmap_map_extent(tp->t_mountp, &dfops, ip, &del); + if (error) + goto out_defer; - error = xfs_defer_finish(&tp, &dfops, ip); - if (error) - goto out_defer; - } + /* Remove the mapping from the CoW fork. */ + xfs_bmap_del_extent_cow(ip, &idx, &got, &del); + + error = xfs_defer_finish(&tp, &dfops, ip); + if (error) + goto out_defer; next_extent: - /* Roll on... */ - offset_fsb = irec.br_startoff + ilen; + if (idx < 0) + break; + xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got); } error = xfs_trans_commit(tp); @@ -739,7 +733,6 @@ xfs_reflink_end_cow( out_defer: xfs_defer_cancel(&dfops); -out_cancel: xfs_trans_cancel(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); out: diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 72f9f6b7a76af..0907752be62d3 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -3356,7 +3356,6 @@ DEFINE_INODE_IREC_EVENT(xfs_reflink_trim_irec); DEFINE_SIMPLE_IO_EVENT(xfs_reflink_cancel_cow_range); DEFINE_SIMPLE_IO_EVENT(xfs_reflink_end_cow); DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_remap); -DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_remap_piece); DEFINE_INODE_ERROR_EVENT(xfs_reflink_allocate_cow_range_error); DEFINE_INODE_ERROR_EVENT(xfs_reflink_cancel_cow_range_error); -- GitLab From 64e6428ddd00f864e3ca105f914a2b6920c2bc41 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 15:54:59 +1100 Subject: [PATCH 0830/1167] xfs: remove xfs_bunmapi_cow Since no one uses it anymore. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_bmap.c | 22 ---------------------- fs/xfs/libxfs/xfs_bmap.h | 1 - 2 files changed, 23 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index d7ad51132f4ff..c6eb21940783e 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -5414,28 +5414,6 @@ xfs_bmap_del_extent( return error; } -/* Remove an extent from the CoW fork. Similar to xfs_bmap_del_extent. */ -int -xfs_bunmapi_cow( - struct xfs_inode *ip, - struct xfs_bmbt_irec *del) -{ - struct xfs_bmbt_rec_host *ep; - struct xfs_bmbt_irec got; - struct xfs_bmbt_irec new; - int eof; - xfs_extnum_t eidx; - - ep = xfs_bmap_search_extents(ip, del->br_startoff, XFS_COW_FORK, &eof, - &eidx, &got, &new); - ASSERT(ep); - if (isnullstartblock(got.br_startblock)) - xfs_bmap_del_extent_delay(ip, XFS_COW_FORK, &eidx, &got, del); - else - xfs_bmap_del_extent_cow(ip, &eidx, &got, del); - return 0; -} - /* * Unmap (remove) blocks from a file. * If nexts is nonzero then the number of extents to remove is limited to diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index 5f18248cbac2b..7cae6ec27fa6b 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -223,7 +223,6 @@ int xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, int flags, xfs_extnum_t nexts, xfs_fsblock_t *firstblock, struct xfs_defer_ops *dfops, int *done); -int xfs_bunmapi_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *del); int xfs_bmap_del_extent_delay(struct xfs_inode *ip, int whichfork, xfs_extnum_t *idx, struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del); -- GitLab From aed3f249f93fe15f16242bbd4e6c3931674b8d91 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 3 Oct 2016 12:36:24 -0700 Subject: [PATCH 0831/1167] thermal: intel_pch_thermal: Add an ACPI passive trip On the platforms which has an ACPI companion device associated with PCH thermal device, read passive trip temperature via ACPI _PSV control method. Signed-off-by: Srinivas Pandruvada Signed-off-by: Zhang Rui --- drivers/thermal/intel_pch_thermal.c | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/thermal/intel_pch_thermal.c b/drivers/thermal/intel_pch_thermal.c index 9b4815e81b0df..5cf644a2c0121 100644 --- a/drivers/thermal/intel_pch_thermal.c +++ b/drivers/thermal/intel_pch_thermal.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -66,9 +67,53 @@ struct pch_thermal_device { unsigned long crt_temp; int hot_trip_id; unsigned long hot_temp; + int psv_trip_id; + unsigned long psv_temp; bool bios_enabled; }; +#ifdef CONFIG_ACPI + +/* + * On some platforms, there is a companion ACPI device, which adds + * passive trip temperature using _PSV method. There is no specific + * passive temperature setting in MMIO interface of this PCI device. + */ +static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd, + int *nr_trips) +{ + struct acpi_device *adev; + + ptd->psv_trip_id = -1; + + adev = ACPI_COMPANION(&ptd->pdev->dev); + if (adev) { + unsigned long long r; + acpi_status status; + + status = acpi_evaluate_integer(adev->handle, "_PSV", NULL, + &r); + if (ACPI_SUCCESS(status)) { + unsigned long trip_temp; + + trip_temp = DECI_KELVIN_TO_MILLICELSIUS(r); + if (trip_temp) { + ptd->psv_temp = trip_temp; + ptd->psv_trip_id = *nr_trips; + ++(*nr_trips); + } + } + } +} +#else +static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd, + int *nr_trips) +{ + ptd->psv_trip_id = -1; + +} +#endif + static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips) { u8 tsel; @@ -119,6 +164,8 @@ static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips) ++(*nr_trips); } + pch_wpt_add_acpi_psv_trip(ptd, nr_trips); + return 0; } @@ -194,6 +241,8 @@ static int pch_get_trip_type(struct thermal_zone_device *tzd, int trip, *type = THERMAL_TRIP_CRITICAL; else if (ptd->hot_trip_id == trip) *type = THERMAL_TRIP_HOT; + else if (ptd->psv_trip_id == trip) + *type = THERMAL_TRIP_PASSIVE; else return -EINVAL; @@ -208,6 +257,8 @@ static int pch_get_trip_temp(struct thermal_zone_device *tzd, int trip, int *tem *temp = ptd->crt_temp; else if (ptd->hot_trip_id == trip) *temp = ptd->hot_temp; + else if (ptd->psv_trip_id == trip) + *temp = ptd->psv_temp; else return -EINVAL; -- GitLab From 33086a9a3071812a829d4b63bed826736a5d8b17 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 3 Oct 2016 12:36:02 -0700 Subject: [PATCH 0832/1167] thermal: intel_pch_thermal: Enable Haswell PCH Added missing support for Haswell PCH thermal sensor. Signed-off-by: Srinivas Pandruvada Signed-off-by: Zhang Rui --- drivers/thermal/intel_pch_thermal.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/thermal/intel_pch_thermal.c b/drivers/thermal/intel_pch_thermal.c index 5cf644a2c0121..19bf2028e5084 100644 --- a/drivers/thermal/intel_pch_thermal.c +++ b/drivers/thermal/intel_pch_thermal.c @@ -25,6 +25,8 @@ #include /* Intel PCH thermal Device IDs */ +#define PCH_THERMAL_DID_HSW_1 0x9C24 /* Haswell PCH */ +#define PCH_THERMAL_DID_HSW_2 0x8C24 /* Haswell PCH */ #define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */ #define PCH_THERMAL_DID_SKL 0x9D31 /* Skylake PCH */ @@ -293,6 +295,11 @@ static int intel_pch_thermal_probe(struct pci_dev *pdev, ptd->ops = &pch_dev_ops_wpt; dev_name = "pch_skylake"; break; + case PCH_THERMAL_DID_HSW_1: + case PCH_THERMAL_DID_HSW_2: + ptd->ops = &pch_dev_ops_wpt; + dev_name = "pch_haswell"; + break; default: dev_err(&pdev->dev, "unknown pch thermal device\n"); return -ENODEV; @@ -375,6 +382,8 @@ static int intel_pch_thermal_resume(struct device *device) static struct pci_device_id intel_pch_thermal_id[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_2) }, { 0, }, }; MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id); -- GitLab From 3105f234e0aba43e44e277c20f9b32ee8add43d4 Mon Sep 17 00:00:00 2001 From: Eric Ernst Date: Thu, 6 Oct 2016 08:56:49 -0700 Subject: [PATCH 0833/1167] thermal/powerclamp: correct cpu support check Initial logic for checking CPU match resulted in OR of CPU features rather than the intended AND. Updated to use boot_cpu_has macro rather than x86_match_cpu. In addition, MWAIT is the only required CPU feature for idle injection to work. Drop other feature requirements since they are only needed for optimal efficiency. CC: stable@vger.kernel.org #v4.7 Signed-off-by: Eric Ernst Acked-by: Jacob Pan Signed-off-by: Zhang Rui --- drivers/thermal/intel_powerclamp.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 0e4dc0afcfd24..7a223074df3d4 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -669,20 +669,10 @@ static struct thermal_cooling_device_ops powerclamp_cooling_ops = { .set_cur_state = powerclamp_set_cur_state, }; -static const struct x86_cpu_id intel_powerclamp_ids[] __initconst = { - { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_MWAIT }, - { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_ARAT }, - { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_NONSTOP_TSC }, - { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_CONSTANT_TSC}, - {} -}; -MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids); - static int __init powerclamp_probe(void) { - if (!x86_match_cpu(intel_powerclamp_ids)) { - pr_err("Intel powerclamp does not run on family %d model %d\n", - boot_cpu_data.x86, boot_cpu_data.x86_model); + if (!boot_cpu_has(X86_FEATURE_MWAIT)) { + pr_err("CPU does not support MWAIT"); return -ENODEV; } -- GitLab From caef78b6cdeddf4ad364f95910bba6b43b8eb9bf Mon Sep 17 00:00:00 2001 From: Alex Thorlton Date: Wed, 19 Oct 2016 20:48:51 -0500 Subject: [PATCH 0834/1167] x86/platform/UV: Fix support for EFI_OLD_MEMMAP after BIOS callback updates Some time ago, we brought our UV BIOS callback code up to speed with the new EFI memory mapping scheme, in commit: d1be84a232e3 ("x86/uv: Update uv_bios_call() to use efi_call_virt_pointer()") By leveraging some changes that I made to a few of the EFI runtime callback mechanisms, in commit: 80e75596079f ("efi: Convert efi_call_virt() to efi_call_virt_pointer()") This got everything running smoothly on UV, with the new EFI mapping code. However, this left one, small loose end, in that EFI_OLD_MEMMAP (a.k.a. efi=old_map) will no longer work on UV, on kernels that include the aforementioned changes. At the time this was not a major issue (in fact, it still really isn't), but there's no reason that EFI_OLD_MEMMAP *shouldn't* work on our systems. This commit adds a check into uv_bios_call(), to see if we have the EFI_OLD_MEMMAP bit set in efi.flags. If it is set, we fall back to using our old callback method, which uses efi_call() directly on the __va() of our function pointer. Signed-off-by: Alex Thorlton Acked-by: Matt Fleming Cc: # v4.7 and later Cc: Andy Lutomirski Cc: Ard Biesheuvel Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Dimitri Sivanich Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Masahiro Yamada Cc: Mike Travis Cc: Peter Zijlstra Cc: Russ Anderson Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1476928131-170101-1-git-send-email-athorlton@sgi.com Signed-off-by: Ingo Molnar --- arch/x86/platform/uv/bios_uv.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86/platform/uv/bios_uv.c b/arch/x86/platform/uv/bios_uv.c index b4d5e95fe4dfe..4a6a5a26c5829 100644 --- a/arch/x86/platform/uv/bios_uv.c +++ b/arch/x86/platform/uv/bios_uv.c @@ -40,7 +40,15 @@ s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5) */ return BIOS_STATUS_UNIMPLEMENTED; - ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5); + /* + * If EFI_OLD_MEMMAP is set, we need to fall back to using our old EFI + * callback method, which uses efi_call() directly, with the kernel page tables: + */ + if (unlikely(test_bit(EFI_OLD_MEMMAP, &efi.flags))) + ret = efi_call((void *)__va(tab->function), (u64)which, a1, a2, a3, a4, a5); + else + ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5); + return ret; } EXPORT_SYMBOL_GPL(uv_bios_call); -- GitLab From 0a1eb2d474edfe75466be6b4677ad84e5e8ca3f5 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 30 Sep 2016 10:58:56 -0700 Subject: [PATCH 0835/1167] fs/proc: Stop reporting eip and esp in /proc/PID/stat Reporting these fields on a non-current task is dangerous. If the task is in any state other than normal kernel code, they may contain garbage or even kernel addresses on some architectures. (x86_64 used to do this. I bet lots of architectures still do.) With CONFIG_THREAD_INFO_IN_TASK=y, it can OOPS, too. As far as I know, there are no use programs that make any material use of these fields, so just get rid of them. Reported-by: Jann Horn Signed-off-by: Andy Lutomirski Acked-by: Thomas Gleixner Cc: Al Viro Cc: Andrew Morton Cc: Borislav Petkov Cc: Brian Gerst Cc: Kees Cook Cc: Linus Torvalds Cc: Linux API Cc: Peter Zijlstra Cc: Tetsuo Handa Cc: Tycho Andersen Link: http://lkml.kernel.org/r/a5fed4c3f4e33ed25d4bb03567e329bc5a712bcc.1475257877.git.luto@kernel.org Signed-off-by: Ingo Molnar --- fs/proc/array.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/proc/array.c b/fs/proc/array.c index 89600fd5963d4..81818adb8e9ee 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -412,10 +412,11 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, mm = get_task_mm(task); if (mm) { vsize = task_vsize(mm); - if (permitted) { - eip = KSTK_EIP(task); - esp = KSTK_ESP(task); - } + /* + * esp and eip are intentionally zeroed out. There is no + * non-racy way to read them without freezing the task. + * Programs that need reliable values can use ptrace(2). + */ } get_task_comm(tcomm, task); -- GitLab From b18cb64ead400c01bf1580eeba330ace51f8087d Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 30 Sep 2016 10:58:57 -0700 Subject: [PATCH 0836/1167] fs/proc: Stop trying to report thread stacks This reverts more of: b76437579d13 ("procfs: mark thread stack correctly in proc//maps") ... which was partially reverted by: 65376df58217 ("proc: revert /proc//maps [stack:TID] annotation") Originally, /proc/PID/task/TID/maps was the same as /proc/TID/maps. In current kernels, /proc/PID/maps (or /proc/TID/maps even for threads) shows "[stack]" for VMAs in the mm's stack address range. In contrast, /proc/PID/task/TID/maps uses KSTK_ESP to guess the target thread's stack's VMA. This is racy, probably returns garbage and, on arches with CONFIG_TASK_INFO_IN_THREAD=y, is also crash-prone: KSTK_ESP is not safe to use on tasks that aren't known to be running ordinary process-context kernel code. This patch removes the difference and just shows "[stack]" for VMAs in the mm's stack range. This is IMO much more sensible -- the actual "stack" address really is treated specially by the VM code, and the current thread stack isn't even well-defined for programs that frequently switch stacks on their own. Reported-by: Jann Horn Signed-off-by: Andy Lutomirski Acked-by: Thomas Gleixner Cc: Al Viro Cc: Andrew Morton Cc: Borislav Petkov Cc: Brian Gerst Cc: Johannes Weiner Cc: Kees Cook Cc: Linus Torvalds Cc: Linux API Cc: Peter Zijlstra Cc: Tycho Andersen Link: http://lkml.kernel.org/r/3e678474ec14e0a0ec34c611016753eea2e1b8ba.1475257877.git.luto@kernel.org Signed-off-by: Ingo Molnar --- Documentation/filesystems/proc.txt | 26 -------------------------- fs/proc/task_mmu.c | 29 ++++++++++------------------- fs/proc/task_nommu.c | 28 ++++++++++------------------ 3 files changed, 20 insertions(+), 63 deletions(-) diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 219ffd41a9117..74329fd0add22 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -395,32 +395,6 @@ is not associated with a file: or if empty, the mapping is anonymous. -The /proc/PID/task/TID/maps is a view of the virtual memory from the viewpoint -of the individual tasks of a process. In this file you will see a mapping marked -as [stack] if that task sees it as a stack. Hence, for the example above, the -task-level map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this: - -08048000-08049000 r-xp 00000000 03:00 8312 /opt/test -08049000-0804a000 rw-p 00001000 03:00 8312 /opt/test -0804a000-0806b000 rw-p 00000000 00:00 0 [heap] -a7cb1000-a7cb2000 ---p 00000000 00:00 0 -a7cb2000-a7eb2000 rw-p 00000000 00:00 0 -a7eb2000-a7eb3000 ---p 00000000 00:00 0 -a7eb3000-a7ed5000 rw-p 00000000 00:00 0 [stack] -a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6 -a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6 -a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6 -a800b000-a800e000 rw-p 00000000 00:00 0 -a800e000-a8022000 r-xp 00000000 03:00 14462 /lib/libpthread.so.0 -a8022000-a8023000 r--p 00013000 03:00 14462 /lib/libpthread.so.0 -a8023000-a8024000 rw-p 00014000 03:00 14462 /lib/libpthread.so.0 -a8024000-a8027000 rw-p 00000000 00:00 0 -a8027000-a8043000 r-xp 00000000 03:00 8317 /lib/ld-linux.so.2 -a8043000-a8044000 r--p 0001b000 03:00 8317 /lib/ld-linux.so.2 -a8044000-a8045000 rw-p 0001c000 03:00 8317 /lib/ld-linux.so.2 -aff35000-aff4a000 rw-p 00000000 00:00 0 -ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso] - The /proc/PID/smaps is an extension based on maps, showing the memory consumption for each of the process's mappings. For each of mappings there is a series of lines such as the following: diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 6909582ce5e5b..35b92d81692f0 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -266,24 +266,15 @@ static int do_maps_open(struct inode *inode, struct file *file, * /proc/PID/maps that is the stack of the main task. */ static int is_stack(struct proc_maps_private *priv, - struct vm_area_struct *vma, int is_pid) + struct vm_area_struct *vma) { - int stack = 0; - - if (is_pid) { - stack = vma->vm_start <= vma->vm_mm->start_stack && - vma->vm_end >= vma->vm_mm->start_stack; - } else { - struct inode *inode = priv->inode; - struct task_struct *task; - - rcu_read_lock(); - task = pid_task(proc_pid(inode), PIDTYPE_PID); - if (task) - stack = vma_is_stack_for_task(vma, task); - rcu_read_unlock(); - } - return stack; + /* + * We make no effort to guess what a given thread considers to be + * its "stack". It's not even well-defined for programs written + * languages like Go. + */ + return vma->vm_start <= vma->vm_mm->start_stack && + vma->vm_end >= vma->vm_mm->start_stack; } static void @@ -354,7 +345,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) goto done; } - if (is_stack(priv, vma, is_pid)) + if (is_stack(priv, vma)) name = "[stack]"; } @@ -1669,7 +1660,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) seq_file_path(m, file, "\n\t= "); } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { seq_puts(m, " heap"); - } else if (is_stack(proc_priv, vma, is_pid)) { + } else if (is_stack(proc_priv, vma)) { seq_puts(m, " stack"); } diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index faacb0c0d8576..37175621e8906 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -124,25 +124,17 @@ unsigned long task_statm(struct mm_struct *mm, } static int is_stack(struct proc_maps_private *priv, - struct vm_area_struct *vma, int is_pid) + struct vm_area_struct *vma) { struct mm_struct *mm = vma->vm_mm; - int stack = 0; - - if (is_pid) { - stack = vma->vm_start <= mm->start_stack && - vma->vm_end >= mm->start_stack; - } else { - struct inode *inode = priv->inode; - struct task_struct *task; - - rcu_read_lock(); - task = pid_task(proc_pid(inode), PIDTYPE_PID); - if (task) - stack = vma_is_stack_for_task(vma, task); - rcu_read_unlock(); - } - return stack; + + /* + * We make no effort to guess what a given thread considers to be + * its "stack". It's not even well-defined for programs written + * languages like Go. + */ + return vma->vm_start <= mm->start_stack && + vma->vm_end >= mm->start_stack; } /* @@ -184,7 +176,7 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, if (file) { seq_pad(m, ' '); seq_file_path(m, file, ""); - } else if (mm && is_stack(priv, vma, is_pid)) { + } else if (mm && is_stack(priv, vma)) { seq_pad(m, ' '); seq_printf(m, "[stack]"); } -- GitLab From d17af5056cf9e9fc05e68832f7c15687fcc12281 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 30 Sep 2016 10:58:58 -0700 Subject: [PATCH 0837/1167] mm: Change vm_is_stack_for_task() to vm_is_stack_for_current() Asking for a non-current task's stack can't be done without races unless the task is frozen in kernel mode. As far as I know, vm_is_stack_for_task() never had a safe non-current use case. The __unused annotation is because some KSTK_ESP implementations ignore their parameter, which IMO is further justification for this patch. Signed-off-by: Andy Lutomirski Acked-by: Thomas Gleixner Cc: Al Viro Cc: Andrew Morton Cc: Borislav Petkov Cc: Brian Gerst Cc: Jann Horn Cc: Kees Cook Cc: Linus Torvalds Cc: Linux API Cc: Peter Zijlstra Cc: Tycho Andersen Link: http://lkml.kernel.org/r/4c3f68f426e6c061ca98b4fc7ef85ffbb0a25b0c.1475257877.git.luto@kernel.org Signed-off-by: Ingo Molnar --- include/linux/mm.h | 2 +- mm/util.c | 4 +++- security/selinux/hooks.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index e9caec6a51e97..a658a5167bce9 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1391,7 +1391,7 @@ static inline int stack_guard_page_end(struct vm_area_struct *vma, !vma_growsup(vma->vm_next, addr); } -int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t); +int vma_is_stack_for_current(struct vm_area_struct *vma); extern unsigned long move_page_tables(struct vm_area_struct *vma, unsigned long old_addr, struct vm_area_struct *new_vma, diff --git a/mm/util.c b/mm/util.c index 662cddf914af2..c174e8921995b 100644 --- a/mm/util.c +++ b/mm/util.c @@ -230,8 +230,10 @@ void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, } /* Check if the vma is being used as a stack by this task */ -int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t) +int vma_is_stack_for_current(struct vm_area_struct *vma) { + struct task_struct * __maybe_unused t = current; + return (vma->vm_start <= KSTK_ESP(t) && vma->vm_end >= KSTK_ESP(t)); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 085057936287b..09fd6108e4213 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3557,7 +3557,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, } else if (!vma->vm_file && ((vma->vm_start <= vma->vm_mm->start_stack && vma->vm_end >= vma->vm_mm->start_stack) || - vma_is_stack_for_task(vma, current))) { + vma_is_stack_for_current(vma))) { rc = current_has_perm(current, PROCESS__EXECSTACK); } else if (vma->vm_file && vma->anon_vma) { /* -- GitLab From 6add49fff9233a5c43011eb42b521257cbaa9bda Mon Sep 17 00:00:00 2001 From: Jacob Siverskog Date: Thu, 20 Oct 2016 09:05:09 +0200 Subject: [PATCH 0838/1167] Bluetooth: btwilink: Fix probe return value Probe functions should return 0 on success. This driver's probe returns the value returned by hci_register_dev(), which is the hci index. This works for systems with only one hci device (id = 0) but for systems where the btwilink device ends up with an id larger than 0, things will start to fall apart. Make the probe function return 0 on success. Signed-off-by: Jacob Siverskog Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btwilink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index ef51c9c864c59..b6bb58c41df5b 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -310,7 +310,7 @@ static int bt_ti_probe(struct platform_device *pdev) BT_DBG("HCI device registered (hdev %p)", hdev); dev_set_drvdata(&pdev->dev, hst); - return err; + return 0; } static int bt_ti_remove(struct platform_device *pdev) -- GitLab From 87261d19046aeaeed8eb3d2793fde850ae1b5c9e Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 19 Oct 2016 14:40:54 +0100 Subject: [PATCH 0839/1167] arm64: Cortex-A53 errata workaround: check for kernel addresses Commit 7dd01aef0557 ("arm64: trap userspace "dc cvau" cache operation on errata-affected core") adds code to execute cache maintenance instructions in the kernel on behalf of userland on CPUs with certain ARM CPU errata. It turns out that the address hasn't been checked to be a valid user space address, allowing userland to clean cache lines in kernel space. Fix this by introducing an address check before executing the instructions on behalf of userland. Since the address doesn't come via a syscall parameter, we can't just reject tagged pointers and instead have to remove the tag when checking against the user address limit. Cc: Fixes: 7dd01aef0557 ("arm64: trap userspace "dc cvau" cache operation on errata-affected core") Reported-by: Kristina Martsenko Signed-off-by: Andre Przywara [will: rework commit message + replace access_ok with max_user_addr()] Signed-off-by: Will Deacon --- arch/arm64/include/asm/uaccess.h | 8 ++++++++ arch/arm64/kernel/traps.c | 27 +++++++++++++++------------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index bcaf6fba1b65b..55d0adbf65098 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -21,6 +21,7 @@ /* * User space memory access functions */ +#include #include #include #include @@ -102,6 +103,13 @@ static inline void set_fs(mm_segment_t fs) flag; \ }) +/* + * When dealing with data aborts or instruction traps we may end up with + * a tagged userland pointer. Clear the tag to get a sane pointer to pass + * on to access_ok(), for instance. + */ +#define untagged_addr(addr) sign_extend64(addr, 55) + #define access_ok(type, addr, size) __range_ok(addr, size) #define user_addr_max get_fs diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 5ff020f8fb7f6..7255c9d6cfb70 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -434,18 +434,21 @@ void cpu_enable_cache_maint_trap(void *__unused) } #define __user_cache_maint(insn, address, res) \ - asm volatile ( \ - "1: " insn ", %1\n" \ - " mov %w0, #0\n" \ - "2:\n" \ - " .pushsection .fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: mov %w0, %w2\n" \ - " b 2b\n" \ - " .popsection\n" \ - _ASM_EXTABLE(1b, 3b) \ - : "=r" (res) \ - : "r" (address), "i" (-EFAULT) ) + if (untagged_addr(address) >= user_addr_max()) \ + res = -EFAULT; \ + else \ + asm volatile ( \ + "1: " insn ", %1\n" \ + " mov %w0, #0\n" \ + "2:\n" \ + " .pushsection .fixup,\"ax\"\n" \ + " .align 2\n" \ + "3: mov %w0, %w2\n" \ + " b 2b\n" \ + " .popsection\n" \ + _ASM_EXTABLE(1b, 3b) \ + : "=r" (res) \ + : "r" (address), "i" (-EFAULT) ) static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs) { -- GitLab From 2a6dcb2b5f3e21592ca8dfa198dcce7bec09b020 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 18 Oct 2016 11:27:46 +0100 Subject: [PATCH 0840/1167] arm64: cpufeature: Schedule enable() calls instead of calling them via IPI The enable() call for a cpufeature/errata is called using on_each_cpu(). This issues a cross-call IPI to get the work done. Implicitly, this stashes the running PSTATE in SPSR when the CPU receives the IPI, and restores it when we return. This means an enable() call can never modify PSTATE. To allow PAN to do this, change the on_each_cpu() call to use stop_machine(). This schedules the work on each CPU which allows us to modify PSTATE. This involves changing the protype of all the enable() functions. enable_cpu_capabilities() is called during boot and enables the feature on all online CPUs. This path now uses stop_machine(). CPU features for hotplug'd CPUs are enabled by verify_local_cpu_features() which only acts on the local CPU, and can already modify the running PSTATE as it is called from secondary_start_kernel(). Reported-by: Tony Thompson Reported-by: Vladimir Murzin Signed-off-by: James Morse Cc: Suzuki K Poulose Signed-off-by: Will Deacon --- arch/arm64/include/asm/cpufeature.h | 2 +- arch/arm64/include/asm/processor.h | 6 +++--- arch/arm64/kernel/cpu_errata.c | 3 ++- arch/arm64/kernel/cpufeature.c | 10 +++++++++- arch/arm64/kernel/traps.c | 3 ++- arch/arm64/mm/fault.c | 6 ++++-- 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 758d74fedfad9..a27c3245ba218 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -94,7 +94,7 @@ struct arm64_cpu_capabilities { u16 capability; int def_scope; /* default scope */ bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope); - void (*enable)(void *); /* Called on all active CPUs */ + int (*enable)(void *); /* Called on all active CPUs */ union { struct { /* To be used for erratum handling only */ u32 midr_model; diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index df2e53d3a9695..60e34824e18c9 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -188,8 +188,8 @@ static inline void spin_lock_prefetch(const void *ptr) #endif -void cpu_enable_pan(void *__unused); -void cpu_enable_uao(void *__unused); -void cpu_enable_cache_maint_trap(void *__unused); +int cpu_enable_pan(void *__unused); +int cpu_enable_uao(void *__unused); +int cpu_enable_cache_maint_trap(void *__unused); #endif /* __ASM_PROCESSOR_H */ diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 0150394f4cabf..b75e917aac464 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -39,10 +39,11 @@ has_mismatched_cache_line_size(const struct arm64_cpu_capabilities *entry, (arm64_ftr_reg_ctrel0.sys_val & arm64_ftr_reg_ctrel0.strict_mask); } -static void cpu_enable_trap_ctr_access(void *__unused) +static int cpu_enable_trap_ctr_access(void *__unused) { /* Clear SCTLR_EL1.UCT */ config_sctlr_el1(SCTLR_EL1_UCT, 0); + return 0; } #define MIDR_RANGE(model, min, max) \ diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index d577f263cc4aa..c02504ea304b7 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -19,7 +19,9 @@ #define pr_fmt(fmt) "CPU features: " fmt #include +#include #include +#include #include #include #include @@ -941,7 +943,13 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) { for (; caps->matches; caps++) if (caps->enable && cpus_have_cap(caps->capability)) - on_each_cpu(caps->enable, NULL, true); + /* + * Use stop_machine() as it schedules the work allowing + * us to modify PSTATE, instead of on_each_cpu() which + * uses an IPI, giving us a PSTATE that disappears when + * we return. + */ + stop_machine(caps->enable, NULL, cpu_online_mask); } /* diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 7255c9d6cfb70..c9986b3e0a96f 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -428,9 +428,10 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0); } -void cpu_enable_cache_maint_trap(void *__unused) +int cpu_enable_cache_maint_trap(void *__unused) { config_sctlr_el1(SCTLR_EL1_UCI, 0); + return 0; } #define __user_cache_maint(insn, address, res) \ diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 53d9159662fe4..3e9ff9b0c78d5 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -670,9 +670,10 @@ asmlinkage int __exception do_debug_exception(unsigned long addr, NOKPROBE_SYMBOL(do_debug_exception); #ifdef CONFIG_ARM64_PAN -void cpu_enable_pan(void *__unused) +int cpu_enable_pan(void *__unused) { config_sctlr_el1(SCTLR_EL1_SPAN, 0); + return 0; } #endif /* CONFIG_ARM64_PAN */ @@ -683,8 +684,9 @@ void cpu_enable_pan(void *__unused) * We need to enable the feature at runtime (instead of adding it to * PSR_MODE_EL1h) as the feature may not be implemented by the cpu. */ -void cpu_enable_uao(void *__unused) +int cpu_enable_uao(void *__unused) { asm(SET_PSTATE_UAO(1)); + return 0; } #endif /* CONFIG_ARM64_UAO */ -- GitLab From 7209c868600bd8926e37c10b9aae83124ccc1dd8 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 18 Oct 2016 11:27:47 +0100 Subject: [PATCH 0841/1167] arm64: mm: Set PSTATE.PAN from the cpu_enable_pan() call Commit 338d4f49d6f7 ("arm64: kernel: Add support for Privileged Access Never") enabled PAN by enabling the 'SPAN' feature-bit in SCTLR_EL1. This means the PSTATE.PAN bit won't be set until the next return to the kernel from userspace. On a preemptible kernel we may schedule work that accesses userspace on a CPU before it has done this. Now that cpufeature enable() calls are scheduled via stop_machine(), we can set PSTATE.PAN from the cpu_enable_pan() call. Add WARN_ON_ONCE(in_interrupt()) to check the PSTATE value we updated is not immediately discarded. Reported-by: Tony Thompson Reported-by: Vladimir Murzin Signed-off-by: James Morse [will: fixed typo in comment] Signed-off-by: Will Deacon --- arch/arm64/mm/fault.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 3e9ff9b0c78d5..0f87883748153 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -29,7 +29,9 @@ #include #include #include +#include +#include #include #include #include @@ -672,7 +674,14 @@ NOKPROBE_SYMBOL(do_debug_exception); #ifdef CONFIG_ARM64_PAN int cpu_enable_pan(void *__unused) { + /* + * We modify PSTATE. This won't work from irq context as the PSTATE + * is discarded once we return from the exception. + */ + WARN_ON_ONCE(in_interrupt()); + config_sctlr_el1(SCTLR_EL1_SPAN, 0); + asm(SET_PSTATE_PAN(1)); return 0; } #endif /* CONFIG_ARM64_PAN */ -- GitLab From d08544127d9fb4505635e3cb6871fd50a42947bd Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 18 Oct 2016 11:27:48 +0100 Subject: [PATCH 0842/1167] arm64: suspend: Reconfigure PSTATE after resume from idle The suspend/resume path in kernel/sleep.S, as used by cpu-idle, does not save/restore PSTATE. As a result of this cpufeatures that were detected and have bits in PSTATE get lost when we resume from idle. UAO gets set appropriately on the next context switch. PAN will be re-enabled next time we return from user-space, but on a preemptible kernel we may run work accessing user space before this point. Add code to re-enable theses two features in __cpu_suspend_exit(). We re-use uao_thread_switch() passing current. Signed-off-by: James Morse Cc: Lorenzo Pieralisi Signed-off-by: Will Deacon --- arch/arm64/include/asm/exec.h | 3 +++ arch/arm64/kernel/process.c | 3 ++- arch/arm64/kernel/suspend.c | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/exec.h b/arch/arm64/include/asm/exec.h index db0563c23482d..f7865dd9d8685 100644 --- a/arch/arm64/include/asm/exec.h +++ b/arch/arm64/include/asm/exec.h @@ -18,6 +18,9 @@ #ifndef __ASM_EXEC_H #define __ASM_EXEC_H +#include + extern unsigned long arch_align_stack(unsigned long sp); +void uao_thread_switch(struct task_struct *next); #endif /* __ASM_EXEC_H */ diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 27b2f1387df40..4f186c56c5ebf 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -301,7 +302,7 @@ static void tls_thread_switch(struct task_struct *next) } /* Restore the UAO state depending on next's addr_limit */ -static void uao_thread_switch(struct task_struct *next) +void uao_thread_switch(struct task_struct *next) { if (IS_ENABLED(CONFIG_ARM64_UAO)) { if (task_thread_info(next)->addr_limit == KERNEL_DS) diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index ad734142070dc..bb0cd787a9d31 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -1,8 +1,11 @@ #include #include #include +#include #include +#include #include +#include #include #include #include @@ -49,6 +52,14 @@ void notrace __cpu_suspend_exit(void) */ set_my_cpu_offset(per_cpu_offset(cpu)); + /* + * PSTATE was not saved over suspend/resume, re-enable any detected + * features that might not have been set correctly. + */ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, + CONFIG_ARM64_PAN)); + uao_thread_switch(current); + /* * Restore HW breakpoint registers to sane values * before debug exceptions are possibly reenabled -- GitLab From de24e0a108bc48062e1c7acaa97014bce32a919f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 19 Oct 2016 15:45:07 +0200 Subject: [PATCH 0843/1167] USB: serial: cp210x: fix tiocmget error handling The current tiocmget implementation would fail to report errors up the stack and instead leaked a few bits from the stack as a mask of modem-status flags. Fixes: 39a66b8d22a3 ("[PATCH] USB: CP2101 Add support for flow control") Cc: stable Signed-off-by: Johan Hovold --- drivers/usb/serial/cp210x.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 54a4de0efdbaa..f61477bed3a8d 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -1077,7 +1077,9 @@ static int cp210x_tiocmget(struct tty_struct *tty) u8 control; int result; - cp210x_read_u8_reg(port, CP210X_GET_MDMSTS, &control); + result = cp210x_read_u8_reg(port, CP210X_GET_MDMSTS, &control); + if (result) + return result; result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) |((control & CONTROL_RTS) ? TIOCM_RTS : 0) -- GitLab From 3602ffdee9afa727320d33bda57a6957d72b1df2 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Wed, 19 Oct 2016 17:53:52 +0000 Subject: [PATCH 0844/1167] irqchip/jcore: Don't show Kconfig menu item for driver Core drivers for J-Core SoCs will be selected implicitly via CONFIG_SH_JCORE_SOC instead. Based on a corresponding change to the clocksource/timer driver requested by Daniel Lezcano. Signed-off-by: Rich Felker Cc: Marc Zyngier Cc: Jason Cooper Cc: linux-sh@vger.kernel.org Link: http://lkml.kernel.org/r/883a3d17084003e3cf21bab73ec12828fe4ff6c6.1476899495.git.dalias@libc.org Signed-off-by: Thomas Gleixner --- drivers/irqchip/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 82b0b5daf3f5b..bc0af3307bbfd 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -158,8 +158,8 @@ config PIC32_EVIC select IRQ_DOMAIN config JCORE_AIC - bool "J-Core integrated AIC" - depends on OF && (SUPERH || COMPILE_TEST) + bool "J-Core integrated AIC" if COMPILE_TEST + depends on OF select IRQ_DOMAIN help Support for the J-Core integrated AIC. -- GitLab From 6aecd8715802d23dc6a0859b50c62d2b0a99de3a Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 20 Oct 2016 14:03:33 +0800 Subject: [PATCH 0845/1167] ALSA: hda - Fix headset mic detection problem for two Dell laptops They uses the codec ALC255, and have the different pin cfg definition from the ones in the existing pin quirk table. Now adding them into the table to fix the problem. Cc: stable@vger.kernel.org Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8483fc20f6350..b582d57fe184b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5856,10 +5856,18 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x14, 0x90170110}, {0x1b, 0x02011020}, {0x21, 0x0221101f}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x1b, 0x01011020}, + {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x14, 0x90170130}, {0x1b, 0x01014020}, {0x21, 0x0221103f}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170130}, + {0x1b, 0x01011020}, + {0x21, 0x0221103f}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x14, 0x90170130}, {0x1b, 0x02011020}, -- GitLab From fd5bed48b446d5edfb319b5ecbef7154f29bd73e Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 20 Oct 2016 11:21:01 +0100 Subject: [PATCH 0846/1167] irqchip/gic: Add missing \n to CPU IF adjustment message It really looks bad without a newline. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 58e5b4e870561..d6c404b3584d5 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1279,7 +1279,7 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base) */ *base += 0xf000; cpuif_res.start += 0xf000; - pr_warn("GIC: Adjusting CPU interface base to %pa", + pr_warn("GIC: Adjusting CPU interface base to %pa\n", &cpuif_res.start); } -- GitLab From b9dce7f1ba01be340975c17bd37a46ec6054bd2b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 20 Oct 2016 11:12:57 +0100 Subject: [PATCH 0847/1167] arm64: kernel: force ET_DYN ELF type for CONFIG_RELOCATABLE=y GNU ld used to set the ELF file type to ET_DYN for PIE executables, which is the same file type used for shared libraries. However, this was changed recently, and now PIE executables are emitted as ET_EXEC instead. The distinction is only relevant for ELF loaders, and so there is little reason to care about the difference when building the kernel, which is why the change has gone unnoticed until now. However, debuggers do use the ELF binary, and expect ET_EXEC type files to appear in memory at the exact offset described in the ELF metadata. This means source level debugging is no longer possible when KASLR is in effect or when executing the stub. So add the -shared LD option when building with CONFIG_RELOCATABLE=y. This forces the ELF file type to be set to ET_DYN (which is what you get when building with binutils 2.24 and earlier anyway), and has no other ill effects. Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm64/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index ab51aed6b6c18..3635b86627245 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -15,7 +15,7 @@ CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) GZFLAGS :=-9 ifneq ($(CONFIG_RELOCATABLE),) -LDFLAGS_vmlinux += -pie -Bsymbolic +LDFLAGS_vmlinux += -pie -shared -Bsymbolic endif ifeq ($(CONFIG_ARM64_ERRATUM_843419),y) -- GitLab From ed1e7db33c3354e4f8b594738c5e793690213b43 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov <0x7f454c46@gmail.com> Date: Thu, 20 Oct 2016 00:53:08 +0300 Subject: [PATCH 0848/1167] x86/signal: Remove bogus user_64bit_mode() check from sigaction_compat_abi() The recent introduction of SA_X32/IA32 sa_flags added a check for user_64bit_mode() into sigaction_compat_abi(). user_64bit_mode() is true for native 64-bit processes and x32 processes. Due to that the function returns w/o setting the SA_X32_ABI flag for X32 processes. In consequence the kernel attempts to deliver the signal to the X32 process in native 64-bit mode causing the process to segfault. Remove the check, so the actual check for X32 mode which sets the ABI flag can be reached. There is no side effect for native 64-bit mode. [ tglx: Rewrote changelog ] Fixes: 6846351052e6 ("x86/signal: Add SA_{X32,IA32}_ABI sa_flags") Reported-by: Mikulas Patocka Tested-by: Adam Borowski Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> Cc: Dmitry Safonov Cc: Oleg Nesterov Cc: linux-mm@kvack.org Cc: Cyrill Gorcunov Cc: Pavel Emelyanov Link: http://lkml.kernel.org/r/CAJwJo6Z8ZWPqNfT6t-i8GW1MKxQrKDUagQqnZ%2B0%2B697%3DMyVeGg@mail.gmail.com Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/kernel/signal_compat.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c index 40df33753bae8..ec1f756f9dc9a 100644 --- a/arch/x86/kernel/signal_compat.c +++ b/arch/x86/kernel/signal_compat.c @@ -105,9 +105,6 @@ void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact) /* Don't let flags to be set from userspace */ act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI); - if (user_64bit_mode(current_pt_regs())) - return; - if (in_ia32_syscall()) act->sa.sa_flags |= SA_IA32_ABI; if (in_x32_syscall()) -- GitLab From c8061485a0d7569a865a3cc3c63347b0f42b3765 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 19 Oct 2016 19:28:11 +0100 Subject: [PATCH 0849/1167] sched/core, x86: Make struct thread_info arch specific again The following commit: c65eacbe290b ("sched/core: Allow putting thread_info into task_struct") ... made 'struct thread_info' a generic struct with only a single ::flags member, if CONFIG_THREAD_INFO_IN_TASK_STRUCT=y is selected. This change however seems to be quite x86 centric, since at least the generic preemption code (asm-generic/preempt.h) assumes that struct thread_info also has a preempt_count member, which apparently was not true for x86. We could add a bit more #ifdefs to solve this problem too, but it seems to be much simpler to make struct thread_info arch specific again. This also makes the conversion to THREAD_INFO_IN_TASK_STRUCT a bit easier for architectures that have a couple of arch specific stuff in their thread_info definition. The arch specific stuff _could_ be moved to thread_struct. However keeping them in thread_info makes it easier: accessing thread_info members is simple, since it is at the beginning of the task_struct, while the thread_struct is at the end. At least on s390 the offsets needed to access members of the thread_struct (with task_struct as base) are too large for various asm instructions. This is not a problem when keeping these members within thread_info. Signed-off-by: Heiko Carstens Signed-off-by: Mark Rutland Acked-by: Thomas Gleixner Cc: Andrew Morton Cc: Andy Lutomirski Cc: Linus Torvalds Cc: Peter Zijlstra Cc: keescook@chromium.org Cc: linux-arch@vger.kernel.org Link: http://lkml.kernel.org/r/1476901693-8492-2-git-send-email-mark.rutland@arm.com Signed-off-by: Ingo Molnar --- arch/x86/include/asm/thread_info.h | 9 +++++++++ include/linux/thread_info.h | 11 ----------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 2aaca53c09741..ad6f5eb07a95b 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -52,6 +52,15 @@ struct task_struct; #include #include +struct thread_info { + unsigned long flags; /* low level flags */ +}; + +#define INIT_THREAD_INFO(tsk) \ +{ \ + .flags = 0, \ +} + #define init_stack (init_thread_union.stack) #else /* !__ASSEMBLY__ */ diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 45f004e9cc598..2873baf5372a7 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -13,17 +13,6 @@ struct timespec; struct compat_timespec; -#ifdef CONFIG_THREAD_INFO_IN_TASK -struct thread_info { - unsigned long flags; /* low level flags */ -}; - -#define INIT_THREAD_INFO(tsk) \ -{ \ - .flags = 0, \ -} -#endif - #ifdef CONFIG_THREAD_INFO_IN_TASK #define current_thread_info() ((struct thread_info *)current) #endif -- GitLab From 15e2a357876910623953a7c9b071096e6d976ca9 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 3 Oct 2016 10:43:46 +0200 Subject: [PATCH 0850/1167] gpio/board.txt: point to gpiod_set_value gpiod_set_value() is preffered interface these days, so add a pointer. Also fix a missing ). Signed-off-by: Pavel Machek [Fixed some grammar and reworded] Signed-off-by: Linus Walleij --- Documentation/gpio/board.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt index 40884c4fe40c5..a0f61898d493b 100644 --- a/Documentation/gpio/board.txt +++ b/Documentation/gpio/board.txt @@ -6,7 +6,7 @@ Note that it only applies to the new descriptor-based interface. For a description of the deprecated integer-based GPIO interface please refer to gpio-legacy.txt (actually, there is no real mapping possible with the old interface; you just fetch an integer from somewhere and request the -corresponding GPIO. +corresponding GPIO). All platforms can enable the GPIO library, but if the platform strictly requires GPIO functionality to be present, it needs to select GPIOLIB from its @@ -162,6 +162,9 @@ The driver controlling "foo.0" will then be able to obtain its GPIOs as follows: Since the "led" GPIOs are mapped as active-high, this example will switch their signals to 1, i.e. enabling the LEDs. And for the "power" GPIO, which is mapped -as active-low, its actual signal will be 0 after this code. Contrary to the legacy -integer GPIO interface, the active-low property is handled during mapping and is -thus transparent to GPIO consumers. +as active-low, its actual signal will be 0 after this code. Contrary to the +legacy integer GPIO interface, the active-low property is handled during +mapping and is thus transparent to GPIO consumers. + +A set of functions such as gpiod_set_value() is available to work with +the new descriptor-oriented interface. -- GitLab From 44df08198bc98d75085bb0ff4b54bf43e0bc40c0 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 5 Oct 2016 15:08:36 +0530 Subject: [PATCH 0851/1167] gpio: mxs: Unmap region obtained by of_iomap Free memory mapping, if mxs_gpio_probe is not successful. Signed-off-by: Arvind Yadav Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index b9daa0bf32a46..ee1724806f46d 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -308,8 +308,10 @@ static int mxs_gpio_probe(struct platform_device *pdev) writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); - if (irq_base < 0) - return irq_base; + if (irq_base < 0) { + err = irq_base; + goto out_iounmap; + } port->domain = irq_domain_add_legacy(np, 32, irq_base, 0, &irq_domain_simple_ops, NULL); @@ -349,6 +351,8 @@ static int mxs_gpio_probe(struct platform_device *pdev) irq_domain_remove(port->domain); out_irqdesc_free: irq_free_descs(irq_base, 32); +out_iounmap: + iounmap(port->base); return err; } -- GitLab From d1ca19cb3bc88318a54643f7a250ec6abab51108 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2016 09:25:20 +0300 Subject: [PATCH 0852/1167] gpio: stmpe: || vs && typo && was obviously intended here. Fixes: 6936e1f88d23 ('gpio: stmpe: Write int status register only when needed') Signed-off-by: Dan Carpenter Acked-by: Patrice Chotard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-stmpe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index e7d422a6b90bd..5b0042776ec70 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -409,7 +409,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) * 801/1801/1600, bits are cleared when read. * Edge detect register is not present on 801/1600/1801 */ - if (stmpe->partnum != STMPE801 || stmpe->partnum != STMPE1600 || + if (stmpe->partnum != STMPE801 && stmpe->partnum != STMPE1600 && stmpe->partnum != STMPE1801) { stmpe_reg_write(stmpe, statmsbreg + i, status[i]); stmpe_reg_write(stmpe, -- GitLab From 0cb940927df72a514588d8286916eda4aaa4d011 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 10 Oct 2016 14:42:46 +0200 Subject: [PATCH 0853/1167] gpio: mockup: add sysfs dependency Building the gpio-mockup driver without SYSFS results in a harmless Kconfig warning: warning: (GPIO_MOCKUP) selects GPIO_SYSFS which has unmet direct dependencies (GPIOLIB && SYSFS) We can easily avoid that warning by adding a dependency on SYSFS. Fixes: 0f98dd1b27d2 ("gpio/mockup: add virtual gpio device") Signed-off-by: Arnd Bergmann Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 26ee00f6bd582..d011cb89d25ed 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -284,7 +284,7 @@ config GPIO_MM_LANTIQ config GPIO_MOCKUP tristate "GPIO Testing Driver" - depends on GPIOLIB + depends on GPIOLIB && SYSFS select GPIO_SYSFS help This enables GPIO Testing driver, which provides a way to test GPIO -- GitLab From 67bf5156edc4f58241fd7c119ae145c552adddd6 Mon Sep 17 00:00:00 2001 From: David Arcari Date: Wed, 12 Oct 2016 18:40:30 +0200 Subject: [PATCH 0854/1167] gpio / ACPI: fix returned error from acpi_dev_gpio_irq_get() acpi_dev_gpio_irq_get() currently ignores the error returned by acpi_get_gpiod_by_index() and overwrites it with -ENOENT. Problem is this error can be -EPROBE_DEFER, which just blows up some drivers when the module ordering is not correct. Cc: stable@vger.kernel.org Signed-off-by: David Arcari Signed-off-by: Benjamin Tissoires Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 58ece201b8e62..72a4b326fd0da 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -653,14 +653,17 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) { int idx, i; unsigned int irq_flags; + int ret = -ENOENT; for (i = 0, idx = 0; idx <= index; i++) { struct acpi_gpio_info info; struct gpio_desc *desc; desc = acpi_get_gpiod_by_index(adev, NULL, i, &info); - if (IS_ERR(desc)) + if (IS_ERR(desc)) { + ret = PTR_ERR(desc); break; + } if (info.gpioint && idx++ == index) { int irq = gpiod_to_irq(desc); @@ -679,7 +682,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) } } - return -ENOENT; + return ret; } EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get); -- GitLab From 758f588d6fa2b1e64b6ae4bc4e7e86331bdee479 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sun, 4 Sep 2016 19:13:57 +0200 Subject: [PATCH 0855/1167] kvm/x86: Fix unused variable warning in kvm_timer_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_CPU_FREQ is not set, int cpu is unused and gcc rightfully warns about it: arch/x86/kvm/x86.c: In function ‘kvm_timer_init’: arch/x86/kvm/x86.c:5697:6: warning: unused variable ‘cpu’ [-Wunused-variable] int cpu; ^~~ But since it is used only in the CONFIG_CPU_FREQ block, simply move it there, thus squashing the warning too. Signed-off-by: Borislav Petkov Signed-off-by: Radim Krčmář --- arch/x86/kvm/x86.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6c633de84dd73..e375235d81c9b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5733,13 +5733,13 @@ static int kvmclock_cpu_online(unsigned int cpu) static void kvm_timer_init(void) { - int cpu; - max_tsc_khz = tsc_khz; if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) { #ifdef CONFIG_CPU_FREQ struct cpufreq_policy policy; + int cpu; + memset(&policy, 0, sizeof(policy)); cpu = get_cpu(); cpufreq_get_policy(&policy, cpu); -- GitLab From 8678654e3c7ad7b0f4beb03fa89691279cba71f9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 13 Oct 2016 17:45:20 +0200 Subject: [PATCH 0856/1167] kvm: x86: memset whole irq_eoi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc 7 warns: arch/x86/kvm/ioapic.c: In function 'kvm_ioapic_reset': arch/x86/kvm/ioapic.c:597:2: warning: 'memset' used with length equal to number of elements without multiplication by element size [-Wmemset-elt-size] And it is right. Memset whole array using sizeof operator. Signed-off-by: Jiri Slaby Cc: Paolo Bonzini Cc: Radim Krčmář Cc: Thomas Gleixner Cc: Ingo Molnar Cc: H. Peter Anvin Cc: x86@kernel.org Cc: kvm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org Reviewed-by: Paolo Bonzini [Added x86 subject tag] Signed-off-by: Radim Krčmář --- arch/x86/kvm/ioapic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index c7220ba94aa77..1a22de70f7f7d 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -594,7 +594,7 @@ static void kvm_ioapic_reset(struct kvm_ioapic *ioapic) ioapic->irr = 0; ioapic->irr_delivered = 0; ioapic->id = 0; - memset(ioapic->irq_eoi, 0x00, IOAPIC_NUM_PINS); + memset(ioapic->irq_eoi, 0x00, sizeof(ioapic->irq_eoi)); rtc_irq_eoi_tracking_reset(ioapic); } -- GitLab From db4b0710fae90a4407bfa77b23db396e580b9e23 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 20 Oct 2016 12:23:16 +0100 Subject: [PATCH 0857/1167] arm64: fix show_regs fallout from KERN_CONT changes Recently in commit 4bcc595ccd80decb ("printk: reinstate KERN_CONT for printing continuation lines"), the behaviour of printk changed w.r.t. KERN_CONT. Now, KERN_CONT is mandatory to continue existing lines. Without this, prefixes are inserted, making output illegible, e.g. [ 1007.069010] pc : [] lr : [] pstate: 40000145 [ 1007.076329] sp : ffff000008d53ec0 [ 1007.079606] x29: ffff000008d53ec0 [ 1007.082797] x28: 0000000080c50018 [ 1007.086160] [ 1007.087630] x27: ffff000008e0c7f8 [ 1007.090820] x26: ffff80097631ca00 [ 1007.094183] [ 1007.095653] x25: 0000000000000001 [ 1007.098843] x24: 000000ea68b61cac [ 1007.102206] ... or when dumped with the userpace dmesg tool, which has slightly different implicit newline behaviour. e.g. [ 1007.069010] pc : [] lr : [] pstate: 40000145 [ 1007.076329] sp : ffff000008d53ec0 [ 1007.079606] x29: ffff000008d53ec0 [ 1007.082797] x28: 0000000080c50018 [ 1007.086160] [ 1007.087630] x27: ffff000008e0c7f8 [ 1007.090820] x26: ffff80097631ca00 [ 1007.094183] [ 1007.095653] x25: 0000000000000001 [ 1007.098843] x24: 000000ea68b61cac [ 1007.102206] We can't simply always use KERN_CONT for lines which may or may not be continuations. That causes line prefixes (e.g. timestamps) to be supressed, and the alignment of all but the first line will be broken. For even more fun, we can't simply insert some dummy empty-string printk calls, as GCC warns for an empty printk string, and even if we pass KERN_DEFAULT explcitly to silence the warning, the prefix gets swallowed unless there is an additional part to the string. Instead, we must manually iterate over pairs of registers, which gives us the legible output we want in either case, e.g. [ 169.771790] pc : [] lr : [] pstate: 40000145 [ 169.779109] sp : ffff000008d53ec0 [ 169.782386] x29: ffff000008d53ec0 x28: 0000000080c50018 [ 169.787650] x27: ffff000008e0c7f8 x26: ffff80097631de00 [ 169.792913] x25: 0000000000000001 x24: 00000027827b2cf4 Signed-off-by: Mark Rutland Cc: Catalin Marinas Cc: Will Deacon Signed-off-by: Will Deacon --- arch/arm64/kernel/process.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 4f186c56c5ebf..01753cd7d3f01 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -187,10 +187,19 @@ void __show_regs(struct pt_regs *regs) printk("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n", regs->pc, lr, regs->pstate); printk("sp : %016llx\n", sp); - for (i = top_reg; i >= 0; i--) { + + i = top_reg; + + while (i >= 0) { printk("x%-2d: %016llx ", i, regs->regs[i]); - if (i % 2 == 0) - printk("\n"); + i--; + + if (i % 2 == 0) { + pr_cont("x%-2d: %016llx ", i, regs->regs[i]); + i--; + } + + pr_cont("\n"); } printk("\n"); } -- GitLab From f7881bd644474a4a62d7bd1ec801176f635f59ae Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 20 Oct 2016 12:24:53 +0100 Subject: [PATCH 0858/1167] arm64: remove pr_cont abuse from mem_init All the lines printed by mem_init are independent, with each ending with a newline. While they logically form a large block, none are actually continuations of previous lines. The kernel-side printk code and the userspace demsg tool differ in their handling of KERN_CONT following a newline, and while this isn't always a problem kernel-side, it does cause difficulty for userspace. Using pr_cont causes the userspace tool to not print line prefix (e.g. timestamps) even when following a newline, mis-aligning the output and making it harder to read, e.g. [ 0.000000] Virtual kernel memory layout: [ 0.000000] modules : 0xffff000000000000 - 0xffff000008000000 ( 128 MB) vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000 (129022 GB) .text : 0xffff000008080000 - 0xffff0000088b0000 ( 8384 KB) .rodata : 0xffff0000088b0000 - 0xffff000008c50000 ( 3712 KB) .init : 0xffff000008c50000 - 0xffff000008d50000 ( 1024 KB) .data : 0xffff000008d50000 - 0xffff000008e25200 ( 853 KB) .bss : 0xffff000008e25200 - 0xffff000008e6bec0 ( 284 KB) fixed : 0xffff7dfffe7fd000 - 0xffff7dfffec00000 ( 4108 KB) PCI I/O : 0xffff7dfffee00000 - 0xffff7dffffe00000 ( 16 MB) vmemmap : 0xffff7e0000000000 - 0xffff800000000000 ( 2048 GB maximum) 0xffff7e0000000000 - 0xffff7e0026000000 ( 608 MB actual) memory : 0xffff800000000000 - 0xffff800980000000 ( 38912 MB) [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=6, Nodes=1 Fix this by using pr_notice consistently for all lines, which both the kernel and userspace are happy with. Signed-off-by: Mark Rutland Cc: Catalin Marinas Cc: James Morse Cc: Kefeng Wang Cc: Will Deacon Signed-off-by: Will Deacon --- arch/arm64/mm/init.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 21c489bdeb4ee..212c4d1e2f26d 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -421,35 +421,35 @@ void __init mem_init(void) pr_notice("Virtual kernel memory layout:\n"); #ifdef CONFIG_KASAN - pr_cont(" kasan : 0x%16lx - 0x%16lx (%6ld GB)\n", + pr_notice(" kasan : 0x%16lx - 0x%16lx (%6ld GB)\n", MLG(KASAN_SHADOW_START, KASAN_SHADOW_END)); #endif - pr_cont(" modules : 0x%16lx - 0x%16lx (%6ld MB)\n", + pr_notice(" modules : 0x%16lx - 0x%16lx (%6ld MB)\n", MLM(MODULES_VADDR, MODULES_END)); - pr_cont(" vmalloc : 0x%16lx - 0x%16lx (%6ld GB)\n", + pr_notice(" vmalloc : 0x%16lx - 0x%16lx (%6ld GB)\n", MLG(VMALLOC_START, VMALLOC_END)); - pr_cont(" .text : 0x%p" " - 0x%p" " (%6ld KB)\n", + pr_notice(" .text : 0x%p" " - 0x%p" " (%6ld KB)\n", MLK_ROUNDUP(_text, _etext)); - pr_cont(" .rodata : 0x%p" " - 0x%p" " (%6ld KB)\n", + pr_notice(" .rodata : 0x%p" " - 0x%p" " (%6ld KB)\n", MLK_ROUNDUP(__start_rodata, __init_begin)); - pr_cont(" .init : 0x%p" " - 0x%p" " (%6ld KB)\n", + pr_notice(" .init : 0x%p" " - 0x%p" " (%6ld KB)\n", MLK_ROUNDUP(__init_begin, __init_end)); - pr_cont(" .data : 0x%p" " - 0x%p" " (%6ld KB)\n", + pr_notice(" .data : 0x%p" " - 0x%p" " (%6ld KB)\n", MLK_ROUNDUP(_sdata, _edata)); - pr_cont(" .bss : 0x%p" " - 0x%p" " (%6ld KB)\n", + pr_notice(" .bss : 0x%p" " - 0x%p" " (%6ld KB)\n", MLK_ROUNDUP(__bss_start, __bss_stop)); - pr_cont(" fixed : 0x%16lx - 0x%16lx (%6ld KB)\n", + pr_notice(" fixed : 0x%16lx - 0x%16lx (%6ld KB)\n", MLK(FIXADDR_START, FIXADDR_TOP)); - pr_cont(" PCI I/O : 0x%16lx - 0x%16lx (%6ld MB)\n", + pr_notice(" PCI I/O : 0x%16lx - 0x%16lx (%6ld MB)\n", MLM(PCI_IO_START, PCI_IO_END)); #ifdef CONFIG_SPARSEMEM_VMEMMAP - pr_cont(" vmemmap : 0x%16lx - 0x%16lx (%6ld GB maximum)\n", + pr_notice(" vmemmap : 0x%16lx - 0x%16lx (%6ld GB maximum)\n", MLG(VMEMMAP_START, VMEMMAP_START + VMEMMAP_SIZE)); - pr_cont(" 0x%16lx - 0x%16lx (%6ld MB actual)\n", + pr_notice(" 0x%16lx - 0x%16lx (%6ld MB actual)\n", MLM((unsigned long)phys_to_page(memblock_start_of_DRAM()), (unsigned long)virt_to_page(high_memory))); #endif - pr_cont(" memory : 0x%16lx - 0x%16lx (%6ld MB)\n", + pr_notice(" memory : 0x%16lx - 0x%16lx (%6ld MB)\n", MLM(__phys_to_virt(memblock_start_of_DRAM()), (unsigned long)high_memory)); -- GitLab From c6fe46a79ecd79606bb96fada4515f6b23f87b62 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 18 Oct 2016 00:41:12 +0900 Subject: [PATCH 0859/1167] cpufreq: fix overflow in cpufreq_table_find_index_dl() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'best' is always less or equals to 'pos', so `best - pos' returns a negative value which is then getting casted to `unsigned int' and passed to __cpufreq_driver_target()->acpi_cpufreq_target() for policy->freq_table selection. This results in BUG: unable to handle kernel paging request at ffff881019b469f8 IP: [] acpi_cpufreq_target+0x4f/0x190 [acpi_cpufreq] PGD 267f067 PUD 0 Oops: 0000 [#1] PREEMPT SMP CPU: 6 PID: 70 Comm: kworker/6:1 Not tainted 4.9.0-rc1-next-20161017-dbg-dirty Workqueue: events dbs_work_handler task: ffff88041b808000 task.stack: ffff88041b810000 RIP: 0010:[] [] acpi_cpufreq_target+0x4f/0x190 [acpi_cpufreq] RSP: 0018:ffff88041b813c60 EFLAGS: 00010282 RAX: ffff880419b46a00 RBX: ffff88041b848400 RCX: ffff880419b20f80 RDX: 00000000001dff38 RSI: 00000000ffffffff RDI: ffff88041b848400 RBP: ffff88041b813cb0 R08: 0000000000000006 R09: 0000000000000040 R10: ffffffff8207f9e0 R11: ffffffff8173595b R12: 0000000000000000 R13: ffff88041f1dff38 R14: 0000000000262900 R15: 0000000bfffffff4 FS: 0000000000000000(0000) GS:ffff88041f000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffff881019b469f8 CR3: 000000041a2d3000 CR4: 00000000001406e0 Stack: ffff88041b813cb0 ffffffff813347f9 ffff88041b813ca0 ffffffff81334663 ffff88041f1d4bc0 ffff88041b848400 0000000000000000 0000000000000000 0000000000262900 0000000000000000 ffff88041b813d00 ffffffff813355dc Call Trace: [] ? cpufreq_freq_transition_begin+0xf1/0xfc [] ? get_cpu_idle_time+0x97/0xa6 [] __cpufreq_driver_target+0x3b6/0x44e [] cs_dbs_timer+0x11a/0x135 [] dbs_work_handler+0x39/0x62 [] process_one_work+0x280/0x4a5 [] worker_thread+0x24f/0x397 [] ? rescuer_thread+0x30b/0x30b [] ? nl80211_get_key+0x29/0x36a [] kthread+0xfc/0x104 [] ? put_lock_stats.isra.9+0xe/0x20 [] ? kthread_create_on_node+0x3f/0x3f [] ret_from_fork+0x22/0x30 Code: 56 4d 6b ff 0c 41 55 41 54 53 48 83 ec 28 48 8b 15 ad 1e 00 00 44 8b 41 08 48 8b 87 c8 00 00 00 49 89 d5 4e 03 2c c5 80 b2 78 81 <46> 8b 74 38 04 45 3b 75 00 75 11 31 c0 83 39 00 0f 84 1c 01 00 RIP [] acpi_cpufreq_target+0x4f/0x190 [acpi_cpufreq] RSP CR2: ffff881019b469f8 ---[ end trace 16d9fc7a17897d37 ]--- [ rjw: In some cases this bug may also cause incorrect frequencies to be selected by cpufreq governors. ] Fixes: 899bb6642f2a (cpufreq: skip invalid entries when searching the frequency) Link: http://marc.info/?l=linux-kernel&m=147672030714331&w=2 Reported-and-tested-by: Sedat Dilek Reported-and-tested-by: Jörg Otte Signed-off-by: Sergey Senozhatsky Acked-by: Viresh Kumar Cc: 4.8+ # 4.8+ Signed-off-by: Rafael J. Wysocki --- include/linux/cpufreq.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 5fa55fc56e18d..32dc0cbd51ca3 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -677,10 +677,10 @@ static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy, if (best == table - 1) return pos - table; - return best - pos; + return best - table; } - return best - pos; + return best - table; } /* Works only on sorted freq-tables */ -- GitLab From 19271c1a083282fbd568f3f214a6182e973626eb Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 20 Oct 2016 16:05:42 +0200 Subject: [PATCH 0860/1167] mlxsw: spectrum_router: Use correct tree index for binding By a mistake, there is tree index 0 passed to RALTB. Should be MLXSW_SP_LPM_TREE_MIN. Fixes: b45f64d16d45 ("mlxsw: spectrum_router: Use FIB notifications instead of switchdev calls") Reported-by: Yotam Gigi Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 78fc557d6dd79..1b3a2cb65837f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -1862,7 +1862,8 @@ static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp) if (err) return err; - mlxsw_reg_raltb_pack(raltb_pl, 0, MLXSW_REG_RALXX_PROTOCOL_IPV4, 0); + mlxsw_reg_raltb_pack(raltb_pl, 0, MLXSW_REG_RALXX_PROTOCOL_IPV4, + MLXSW_SP_LPM_TREE_MIN); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl); if (err) return err; -- GitLab From 37956d78b8f0c5560421f83d1a5e337ee81c685c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 20 Oct 2016 16:05:43 +0200 Subject: [PATCH 0861/1167] mlxsw: spectrum_router: Make mlxsw_sp_router_fib4_del return void and remove warn The function return value is not checked anywhere. Also, the warning causes huge slowdown when removing large number of FIB entries which were not offloaded, because of ordering issue. Ido's preparing a patchset to fix the ordering issue, but that is definitelly not net tree material. Fixes: b45f64d16d45 ("mlxsw: spectrum_router: Use FIB notifications instead of switchdev calls") Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 1b3a2cb65837f..f3d50d369bbe8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -1820,19 +1820,17 @@ static int mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp, return err; } -static int mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp, - struct fib_entry_notifier_info *fen_info) +static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp, + struct fib_entry_notifier_info *fen_info) { struct mlxsw_sp_fib_entry *fib_entry; if (mlxsw_sp->router.aborted) - return 0; + return; fib_entry = mlxsw_sp_fib_entry_find(mlxsw_sp, fen_info); - if (!fib_entry) { - dev_warn(mlxsw_sp->bus_info->dev, "Failed to find FIB4 entry being removed.\n"); - return -ENOENT; - } + if (!fib_entry) + return; if (fib_entry->ref_count == 1) { mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry); @@ -1840,7 +1838,6 @@ static int mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp, } mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry); - return 0; } static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp) -- GitLab From 7fb6a36bab6b0b158f93eb13faa1b440f8b26009 Mon Sep 17 00:00:00 2001 From: Elad Raz Date: Thu, 20 Oct 2016 16:05:44 +0200 Subject: [PATCH 0862/1167] mlxsw: switchx2: Fix ethernet port initialization When creating an ethernet port fails, we must move the port to disable, otherwise putting the port in switch partition 0 (ETH) or 1 (IB) will always fails. Fixes: 31557f0f9755 ("mlxsw: Introduce Mellanox SwitchX-2 ASIC support") Signed-off-by: Elad Raz Reviewed-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c index c0c23e2f3275a..92bda8703f875 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -1088,6 +1088,7 @@ static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port) err_port_admin_status_set: err_port_mtu_set: err_port_speed_set: + mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT); err_port_swid_set: err_port_system_port_mapping_set: port_not_usable: -- GitLab From 164c971d1cc365dc85e5cf9a9302a91c0cf7f126 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 20 Oct 2016 16:05:45 +0200 Subject: [PATCH 0863/1167] mlxsw: pci: Fix reset wait for SwitchX2 SwitchX2 firmware does not implement reset done yet. Moreover, when busy-polled for ready magic, that slows down firmware and reset takes longer than the defined timeout, causing initialization to fail. So restore the previous behaviour and just sleep in this case. Fixes: 233fa44bd67a ("mlxsw: pci: Implement reset done check") Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index e742bd4e8894a..912f71f84209d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1838,11 +1838,17 @@ static const struct mlxsw_bus mlxsw_pci_bus = { .cmd_exec = mlxsw_pci_cmd_exec, }; -static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci) +static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, + const struct pci_device_id *id) { unsigned long end; mlxsw_pci_write32(mlxsw_pci, SW_RESET, MLXSW_PCI_SW_RESET_RST_BIT); + if (id->device == PCI_DEVICE_ID_MELLANOX_SWITCHX2) { + msleep(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS); + return 0; + } + wmb(); /* reset needs to be written before we read control register */ end = jiffies + msecs_to_jiffies(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS); do { @@ -1909,7 +1915,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mlxsw_pci->pdev = pdev; pci_set_drvdata(pdev, mlxsw_pci); - err = mlxsw_pci_sw_reset(mlxsw_pci); + err = mlxsw_pci_sw_reset(mlxsw_pci, id); if (err) { dev_err(&pdev->dev, "Software reset failed\n"); goto err_sw_reset; -- GitLab From 5712bf9c5c30ade3204016147d7b04bece6952d9 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Wed, 19 Oct 2016 17:42:39 +0300 Subject: [PATCH 0864/1167] net/sched: act_mirred: Use passed lastuse argument stats_update callback is called by NIC drivers doing hardware offloading of the mirred action. Lastuse is passed as argument to specify when the stats was actually last updated and is not always the current time. Fixes: 9798e6fe4f9b ('net: act_mirred: allow statistic updates from offloaded actions') Signed-off-by: Paul Blakey Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- net/sched/act_mirred.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 667dc382df82b..6b07fba5770b2 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -207,8 +207,11 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, static void tcf_stats_update(struct tc_action *a, u64 bytes, u32 packets, u64 lastuse) { - tcf_lastuse_update(&a->tcfa_tm); + struct tcf_mirred *m = to_mirred(a); + struct tcf_t *tm = &m->tcf_tm; + _bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), bytes, packets); + tm->lastuse = lastuse; } static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, -- GitLab From 7ba5c003db59a6f738d87d92b68d4a91cdf22f60 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Thu, 20 Oct 2016 11:45:49 +1100 Subject: [PATCH 0865/1167] net/ncsi: Avoid if statements in ncsi_suspend_channel() There are several if/else statements in the state machine implemented by switch/case in ncsi_suspend_channel() to avoid duplicated code. It makes the code a bit hard to be understood. This drops if/else statements in ncsi_suspend_channel() to improve the code readability as Joel Stanley suggested. Also, it becomes easy to add more states in the state machine without affecting current code. No logical changes introduced by this. Suggested-by: Joel Stanley Signed-off-by: Gavin Shan Signed-off-by: David S. Miller --- net/ncsi/ncsi-manage.c | 78 +++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index 5e509e547c2dd..655d0d6539268 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c @@ -540,42 +540,60 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp) nd->state = ncsi_dev_state_suspend_select; /* Fall through */ case ncsi_dev_state_suspend_select: + ndp->pending_req_num = 1; + + nca.type = NCSI_PKT_CMD_SP; + nca.package = np->id; + nca.channel = NCSI_RESERVED_CHANNEL; + if (ndp->flags & NCSI_DEV_HWA) + nca.bytes[0] = 0; + else + nca.bytes[0] = 1; + + nd->state = ncsi_dev_state_suspend_dcnt; + ret = ncsi_xmit_cmd(&nca); + if (ret) + goto error; + + break; case ncsi_dev_state_suspend_dcnt: + ndp->pending_req_num = 1; + + nca.type = NCSI_PKT_CMD_DCNT; + nca.package = np->id; + nca.channel = nc->id; + + nd->state = ncsi_dev_state_suspend_dc; + ret = ncsi_xmit_cmd(&nca); + if (ret) + goto error; + + break; case ncsi_dev_state_suspend_dc: + ndp->pending_req_num = 1; + + nca.type = NCSI_PKT_CMD_DC; + nca.package = np->id; + nca.channel = nc->id; + nca.bytes[0] = 1; + + nd->state = ncsi_dev_state_suspend_deselect; + ret = ncsi_xmit_cmd(&nca); + if (ret) + goto error; + + break; case ncsi_dev_state_suspend_deselect: ndp->pending_req_num = 1; - np = ndp->active_package; - nc = ndp->active_channel; + nca.type = NCSI_PKT_CMD_DP; nca.package = np->id; - if (nd->state == ncsi_dev_state_suspend_select) { - nca.type = NCSI_PKT_CMD_SP; - nca.channel = NCSI_RESERVED_CHANNEL; - if (ndp->flags & NCSI_DEV_HWA) - nca.bytes[0] = 0; - else - nca.bytes[0] = 1; - nd->state = ncsi_dev_state_suspend_dcnt; - } else if (nd->state == ncsi_dev_state_suspend_dcnt) { - nca.type = NCSI_PKT_CMD_DCNT; - nca.channel = nc->id; - nd->state = ncsi_dev_state_suspend_dc; - } else if (nd->state == ncsi_dev_state_suspend_dc) { - nca.type = NCSI_PKT_CMD_DC; - nca.channel = nc->id; - nca.bytes[0] = 1; - nd->state = ncsi_dev_state_suspend_deselect; - } else if (nd->state == ncsi_dev_state_suspend_deselect) { - nca.type = NCSI_PKT_CMD_DP; - nca.channel = NCSI_RESERVED_CHANNEL; - nd->state = ncsi_dev_state_suspend_done; - } + nca.channel = NCSI_RESERVED_CHANNEL; + nd->state = ncsi_dev_state_suspend_done; ret = ncsi_xmit_cmd(&nca); - if (ret) { - nd->state = ncsi_dev_state_functional; - return; - } + if (ret) + goto error; break; case ncsi_dev_state_suspend_done: @@ -589,6 +607,10 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp) netdev_warn(nd->dev, "Wrong NCSI state 0x%x in suspend\n", nd->state); } + + return; +error: + nd->state = ncsi_dev_state_functional; } static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) -- GitLab From 008a424a24a904ed12c03b203f6f257bcaf12358 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Thu, 20 Oct 2016 11:45:50 +1100 Subject: [PATCH 0866/1167] net/ncsi: Fix stale link state of inactive channels on failover The issue was found on BCM5718 which has two NCSI channels in one package: C0 and C1. Both of them are connected to different LANs, means they are in link-up state and C0 is chosen as the active one until resetting BCM5718 happens as below. Resetting BCM5718 results in LSC (Link State Change) AEN packet received on C0, meaning LSC AEN is missed on C1. When LSC AEN packet received on C0 to report link-down, it fails over to C1 because C1 is in link-up state as software can see. However, C1 is in link-down state in hardware. It means the link state is out of synchronization between hardware and software, resulting in inappropriate channel (C1) selected as active one. This resolves the issue by sending separate GLS (Get Link Status) commands to all channels in the package before trying to do failover. The last link states of all channels in the package are retrieved. With it, C0 (not C1) is selected as active one as expected. Signed-off-by: Gavin Shan Signed-off-by: David S. Miller --- net/ncsi/internal.h | 1 + net/ncsi/ncsi-manage.c | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h index 13290a70fa714..eac48584cdd1a 100644 --- a/net/ncsi/internal.h +++ b/net/ncsi/internal.h @@ -246,6 +246,7 @@ enum { ncsi_dev_state_config_gls, ncsi_dev_state_config_done, ncsi_dev_state_suspend_select = 0x0401, + ncsi_dev_state_suspend_gls, ncsi_dev_state_suspend_dcnt, ncsi_dev_state_suspend_dc, ncsi_dev_state_suspend_deselect, diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index 655d0d6539268..4789f86816959 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c @@ -550,11 +550,37 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp) else nca.bytes[0] = 1; - nd->state = ncsi_dev_state_suspend_dcnt; + /* To retrieve the last link states of channels in current + * package when current active channel needs fail over to + * another one. It means we will possibly select another + * channel as next active one. The link states of channels + * are most important factor of the selection. So we need + * accurate link states. Unfortunately, the link states on + * inactive channels can't be updated with LSC AEN in time. + */ + if (ndp->flags & NCSI_DEV_RESHUFFLE) + nd->state = ncsi_dev_state_suspend_gls; + else + nd->state = ncsi_dev_state_suspend_dcnt; ret = ncsi_xmit_cmd(&nca); if (ret) goto error; + break; + case ncsi_dev_state_suspend_gls: + ndp->pending_req_num = np->channel_num; + + nca.type = NCSI_PKT_CMD_GLS; + nca.package = np->id; + + nd->state = ncsi_dev_state_suspend_dcnt; + NCSI_FOR_EACH_CHANNEL(np, nc) { + nca.channel = nc->id; + ret = ncsi_xmit_cmd(&nca); + if (ret) + goto error; + } + break; case ncsi_dev_state_suspend_dcnt: ndp->pending_req_num = 1; -- GitLab From bbc7c01e95ceef4e23e343f8cbb6edca887121a5 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Thu, 20 Oct 2016 11:45:51 +1100 Subject: [PATCH 0867/1167] net/ncsi: Choose hot channel as active one if necessary The issue was found on BCM5718 which has two NCSI channels in one package: C0 and C1. C0 is in link-up state while C1 is in link-down state. C0 is chosen as active channel until unplugging and plugging C0's cable: On unplugging C0's cable, LSC (Link State Change) AEN packet received on C0 to report link-down event. After that, C1 is chosen as active channel. LSC AEN for link-up event is lost on C0 when plugging C0's cable back. We lose the network even C0 is usable. This resolves the issue by recording the (hot) channel that was ever chosen as active one. The hot channel is chosen to be active one if none of available channels in link-up state. With this, C0 is still the active one after unplugging C0's cable. LSC AEN packet received on C0 when plugging its cable back. Signed-off-by: Gavin Shan Signed-off-by: David S. Miller --- net/ncsi/internal.h | 1 + net/ncsi/ncsi-manage.c | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h index eac48584cdd1a..1308a56f25914 100644 --- a/net/ncsi/internal.h +++ b/net/ncsi/internal.h @@ -265,6 +265,7 @@ struct ncsi_dev_priv { #endif unsigned int package_num; /* Number of packages */ struct list_head packages; /* List of packages */ + struct ncsi_channel *hot_channel; /* Channel was ever active */ struct ncsi_request requests[256]; /* Request table */ unsigned int request_id; /* Last used request ID */ #define NCSI_REQ_START_IDX 1 diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index 4789f86816959..a3bd5fa8ad093 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c @@ -645,6 +645,7 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) struct net_device *dev = nd->dev; struct ncsi_package *np = ndp->active_package; struct ncsi_channel *nc = ndp->active_channel; + struct ncsi_channel *hot_nc = NULL; struct ncsi_cmd_arg nca; unsigned char index; unsigned long flags; @@ -750,12 +751,20 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) break; case ncsi_dev_state_config_done: spin_lock_irqsave(&nc->lock, flags); - if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) + if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) { + hot_nc = nc; nc->state = NCSI_CHANNEL_ACTIVE; - else + } else { + hot_nc = NULL; nc->state = NCSI_CHANNEL_INACTIVE; + } spin_unlock_irqrestore(&nc->lock, flags); + /* Update the hot channel */ + spin_lock_irqsave(&ndp->lock, flags); + ndp->hot_channel = hot_nc; + spin_unlock_irqrestore(&ndp->lock, flags); + ncsi_start_channel_monitor(nc); ncsi_process_next_channel(ndp); break; @@ -773,10 +782,14 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp) { struct ncsi_package *np; - struct ncsi_channel *nc, *found; + struct ncsi_channel *nc, *found, *hot_nc; struct ncsi_channel_mode *ncm; unsigned long flags; + spin_lock_irqsave(&ndp->lock, flags); + hot_nc = ndp->hot_channel; + spin_unlock_irqrestore(&ndp->lock, flags); + /* The search is done once an inactive channel with up * link is found. */ @@ -794,6 +807,9 @@ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp) if (!found) found = nc; + if (nc == hot_nc) + found = nc; + ncm = &nc->modes[NCSI_MODE_LINK]; if (ncm->data[2] & 0x1) { spin_unlock_irqrestore(&nc->lock, flags); -- GitLab From 22d8aa93d7ea169a349fb2f9dee5babc68f6a683 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Thu, 20 Oct 2016 11:45:52 +1100 Subject: [PATCH 0868/1167] net/ncsi: Improve HNCDSC AEN handler This improves AEN handler for Host Network Controller Driver Status Change (HNCDSC): * The channel's lock should be hold when accessing its state. * Do failover when host driver isn't ready. * Configure channel when host driver becomes ready. Signed-off-by: Gavin Shan Signed-off-by: David S. Miller --- net/ncsi/ncsi-aen.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/net/ncsi/ncsi-aen.c b/net/ncsi/ncsi-aen.c index b41a6617d4980..6898e7229285a 100644 --- a/net/ncsi/ncsi-aen.c +++ b/net/ncsi/ncsi-aen.c @@ -141,23 +141,35 @@ static int ncsi_aen_handler_hncdsc(struct ncsi_dev_priv *ndp, return -ENODEV; /* If the channel is active one, we need reconfigure it */ + spin_lock_irqsave(&nc->lock, flags); ncm = &nc->modes[NCSI_MODE_LINK]; hncdsc = (struct ncsi_aen_hncdsc_pkt *)h; ncm->data[3] = ntohl(hncdsc->status); if (!list_empty(&nc->link) || - nc->state != NCSI_CHANNEL_ACTIVE || - (ncm->data[3] & 0x1)) + nc->state != NCSI_CHANNEL_ACTIVE) { + spin_unlock_irqrestore(&nc->lock, flags); return 0; + } - if (ndp->flags & NCSI_DEV_HWA) + spin_unlock_irqrestore(&nc->lock, flags); + if (!(ndp->flags & NCSI_DEV_HWA) && !(ncm->data[3] & 0x1)) ndp->flags |= NCSI_DEV_RESHUFFLE; /* If this channel is the active one and the link doesn't * work, we have to choose another channel to be active one. * The logic here is exactly similar to what we do when link * is down on the active channel. + * + * On the other hand, we need configure it when host driver + * state on the active channel becomes ready. */ ncsi_stop_channel_monitor(nc); + + spin_lock_irqsave(&nc->lock, flags); + nc->state = (ncm->data[3] & 0x1) ? NCSI_CHANNEL_INACTIVE : + NCSI_CHANNEL_ACTIVE; + spin_unlock_irqrestore(&nc->lock, flags); + spin_lock_irqsave(&ndp->lock, flags); list_add_tail_rcu(&nc->link, &ndp->channel_queue); spin_unlock_irqrestore(&ndp->lock, flags); -- GitLab From 8be0328e52dc2c8c6f61563c9ccc95ae4d63e9ce Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 20 Oct 2016 10:01:28 +0200 Subject: [PATCH 0869/1167] stmmac: display the descriptors if DES0 = 0 It makes sense to display the descriptors even if DES0 is zero. This helps for example in case of it is needed to dump rx write-back descriptors to get timestamp status. Signed-off-by: Giuseppe Cavallaro Cc: Alexandre TORGUE Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c index 4ec7397e7fb37..a1b17cd7886b1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c @@ -347,10 +347,9 @@ static void dwmac4_display_ring(void *head, unsigned int size, bool rx) pr_info("%s descriptor ring:\n", rx ? "RX" : "TX"); for (i = 0; i < size; i++) { - if (p->des0) - pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n", - i, (unsigned int)virt_to_phys(p), - p->des0, p->des1, p->des2, p->des3); + pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n", + i, (unsigned int)virt_to_phys(p), + p->des0, p->des1, p->des2, p->des3); p++; } } -- GitLab From 4c39135aa412d2f1381e43802523da110ca7855c Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 20 Oct 2016 18:09:18 +0300 Subject: [PATCH 0870/1167] xhci: add restart quirk for Intel Wildcatpoint PCH xHC in Wildcatpoint-LP PCH is similar to LynxPoint-LP and need the same quirks to prevent machines from spurious restart while shutting them down. Reported-by: Hasan Mahmood CC: Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index d7b0f97abbad6..314179b4824e5 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -45,6 +45,7 @@ #define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 +#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI 0x9cb1 #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f @@ -153,7 +154,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_SPURIOUS_REBOOT; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) { + (pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI)) { xhci->quirks |= XHCI_SPURIOUS_REBOOT; xhci->quirks |= XHCI_SPURIOUS_WAKEUP; } -- GitLab From 346e99736c3ce328fd42d678343b70243aca5f36 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 20 Oct 2016 18:09:19 +0300 Subject: [PATCH 0871/1167] xhci: workaround for hosts missing CAS bit If a device is unplugged and replugged during Sx system suspend some Intel xHC hosts will overwrite the CAS (Cold attach status) flag and no device connection is noticed in resume. A device in this state can be identified in resume if its link state is in polling or compliance mode, and the current connect status is 0. A device in this state needs to be warm reset. Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8 Observed on Cherryview and Apollolake as they go into compliance mode if LFPS times out during polling, and re-plugged devices are not discovered at resume. Signed-off-by: Mathias Nyman CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci-pci.c | 6 ++++++ drivers/usb/host/xhci.h | 3 +++ 3 files changed, 46 insertions(+) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 730b9fd266852..c047362b37683 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1355,6 +1355,35 @@ int xhci_bus_suspend(struct usb_hcd *hcd) return 0; } +/* + * Workaround for missing Cold Attach Status (CAS) if device re-plugged in S3. + * warm reset a USB3 device stuck in polling or compliance mode after resume. + * See Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8 + */ +static bool xhci_port_missing_cas_quirk(int port_index, + __le32 __iomem **port_array) +{ + u32 portsc; + + portsc = readl(port_array[port_index]); + + /* if any of these are set we are not stuck */ + if (portsc & (PORT_CONNECT | PORT_CAS)) + return false; + + if (((portsc & PORT_PLS_MASK) != XDEV_POLLING) && + ((portsc & PORT_PLS_MASK) != XDEV_COMP_MODE)) + return false; + + /* clear wakeup/change bits, and do a warm port reset */ + portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); + portsc |= PORT_WR; + writel(portsc, port_array[port_index]); + /* flush write */ + readl(port_array[port_index]); + return true; +} + int xhci_bus_resume(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -1392,6 +1421,14 @@ int xhci_bus_resume(struct usb_hcd *hcd) u32 temp; temp = readl(port_array[port_index]); + + /* warm reset CAS limited ports stuck in polling/compliance */ + if ((xhci->quirks & XHCI_MISSING_CAS) && + (hcd->speed >= HCD_USB3) && + xhci_port_missing_cas_quirk(port_index, port_array)) { + xhci_dbg(xhci, "reset stuck port %d\n", port_index); + continue; + } if (DEV_SUPERSPEED_ANY(temp)) temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); else diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 314179b4824e5..e96ae80d107e9 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -51,6 +51,7 @@ #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f #define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8 #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8 +#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8 static const char hcd_name[] = "xhci_hcd"; @@ -171,6 +172,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { xhci->quirks |= XHCI_SSIC_PORT_UNUSED; } + if (pdev->vendor == PCI_VENDOR_ID_INTEL && + (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI)) + xhci->quirks |= XHCI_MISSING_CAS; + if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_EJ168) { xhci->quirks |= XHCI_RESET_ON_RESUME; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index b2c1dc5dc0f30..f945380035d07 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -314,6 +314,8 @@ struct xhci_op_regs { #define XDEV_U2 (0x2 << 5) #define XDEV_U3 (0x3 << 5) #define XDEV_INACTIVE (0x6 << 5) +#define XDEV_POLLING (0x7 << 5) +#define XDEV_COMP_MODE (0xa << 5) #define XDEV_RESUME (0xf << 5) /* true: port has power (see HCC_PPC) */ #define PORT_POWER (1 << 9) @@ -1653,6 +1655,7 @@ struct xhci_hcd { #define XHCI_MTK_HOST (1 << 21) #define XHCI_SSIC_PORT_UNUSED (1 << 22) #define XHCI_NO_64BIT_SUPPORT (1 << 23) +#define XHCI_MISSING_CAS (1 << 24) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ -- GitLab From 7d3b016a6f5a0fa610dfd02b05654c08fa4ae514 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 20 Oct 2016 18:09:20 +0300 Subject: [PATCH 0872/1167] xhci: use default USB_RESUME_TIMEOUT when resuming ports. USB2 host inititated resume, and system suspend bus resume need to use the same USB_RESUME_TIMEOUT as elsewhere. This resolves a device disconnect issue at system resume seen on Intel Braswell and Apollolake, but is in no way limited to those platforms. Signed-off-by: Mathias Nyman CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index c047362b37683..0ef16900efedd 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1166,7 +1166,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_set_link_state(xhci, port_array, wIndex, XDEV_RESUME); spin_unlock_irqrestore(&xhci->lock, flags); - msleep(20); + msleep(USB_RESUME_TIMEOUT); spin_lock_irqsave(&xhci->lock, flags); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); @@ -1447,7 +1447,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) if (need_usb2_u3_exit) { spin_unlock_irqrestore(&xhci->lock, flags); - msleep(20); + msleep(USB_RESUME_TIMEOUT); spin_lock_irqsave(&xhci->lock, flags); } -- GitLab From a478b097474cd9f2268ab1beaca74ff09e652b9b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Oct 2016 17:15:41 +0200 Subject: [PATCH 0873/1167] ahci: fix nvec check commit 17a51f12 ("ahci: only try to use multi-MSI mode if there is more than 1 port") lead to a case where nvec isn't initialized before it's used. Fix this by moving the check into the n_ports conditional. Reported-and-reviewed-by Colin Ian King Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index ed311a040fed6..60e42e2ed68fa 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1436,14 +1436,14 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, "ahci: MRSM is on, fallback to single MSI\n"); pci_free_irq_vectors(pdev); } - } - /* - * -ENOSPC indicated we don't have enough vectors. Don't bother trying - * a single vectors for any other error: - */ - if (nvec < 0 && nvec != -ENOSPC) - return nvec; + /* + * -ENOSPC indicated we don't have enough vectors. Don't bother + * trying a single vectors for any other error: + */ + if (nvec < 0 && nvec != -ENOSPC) + return nvec; + } /* * If the host is not capable of supporting per-port vectors, fall -- GitLab From 7bb6615d395a7c130053728f3a64f6df6b2e1f18 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 18 Oct 2016 14:37:32 +0200 Subject: [PATCH 0874/1167] netfilter: conntrack: restart gc immediately if GC_MAX_EVICTS is reached When the maximum evictions number is reached, do not wait 5 seconds before the next run. CC: Florian Westphal Signed-off-by: Nicolas Dichtel Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index ba6a1d4212225..df2f5a3901dfc 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -983,7 +983,7 @@ static void gc_worker(struct work_struct *work) return; ratio = scanned ? expired_count * 100 / scanned : 0; - if (ratio >= 90) + if (ratio >= 90 || expired_count == GC_MAX_EVICTS) next_run = 0; gc_work->last_bucket = i; -- GitLab From 7034b566a4e7d550621c2dfafd380b77b3787cd9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 17 Oct 2016 18:05:32 +0100 Subject: [PATCH 0875/1167] netfilter: fix nf_queue handling nf_queue handling is broken since e3b37f11e6e4 ("netfilter: replace list_head with single linked list") for two reasons: 1) If the bypass flag is set on, there are no userspace listeners and we still have more hook entries to iterate over, then jump to the next hook. Otherwise accept the packet. On nf_reinject() path, the okfn() needs to be invoked. 2) We should not re-enter the same hook on packet reinjection. If the packet is accepted, we have to skip the current hook from where the packet was enqueued, otherwise the packets gets enqueued over and over again. This restores the previous list_for_each_entry_continue() behaviour happening from nf_iterate() that was dealing with these two cases. This patch introduces a new nf_queue() wrapper function so this fix becomes simpler. Fixes: e3b37f11e6e4 ("netfilter: replace list_head with single linked list") Signed-off-by: Pablo Neira Ayuso --- net/netfilter/core.c | 13 +++------- net/netfilter/nf_internals.h | 2 +- net/netfilter/nf_queue.c | 48 ++++++++++++++++++++++++------------ 3 files changed, 36 insertions(+), 27 deletions(-) diff --git a/net/netfilter/core.c b/net/netfilter/core.c index fcb5d1df11e99..004af030ef1ab 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -361,16 +361,9 @@ int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state) if (ret == 0) ret = -EPERM; } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { - int err; - - RCU_INIT_POINTER(state->hook_entries, entry); - err = nf_queue(skb, state, verdict >> NF_VERDICT_QBITS); - if (err < 0) { - if (err == -ESRCH && - (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS)) - goto next_hook; - kfree_skb(skb); - } + ret = nf_queue(skb, state, &entry, verdict); + if (ret == 1 && entry) + goto next_hook; } return ret; } diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h index e0adb59593421..9fdb655f85bc1 100644 --- a/net/netfilter/nf_internals.h +++ b/net/netfilter/nf_internals.h @@ -18,7 +18,7 @@ unsigned int nf_iterate(struct sk_buff *skb, struct nf_hook_state *state, /* nf_queue.c */ int nf_queue(struct sk_buff *skb, struct nf_hook_state *state, - unsigned int queuenum); + struct nf_hook_entry **entryp, unsigned int verdict); void nf_queue_nf_hook_drop(struct net *net, const struct nf_hook_entry *entry); int __init netfilter_queue_init(void); diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 96964a0070e11..8f08d759844a9 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -107,13 +107,8 @@ void nf_queue_nf_hook_drop(struct net *net, const struct nf_hook_entry *entry) rcu_read_unlock(); } -/* - * Any packet that leaves via this function must come back - * through nf_reinject(). - */ -int nf_queue(struct sk_buff *skb, - struct nf_hook_state *state, - unsigned int queuenum) +static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state, + unsigned int queuenum) { int status = -ENOENT; struct nf_queue_entry *entry = NULL; @@ -161,6 +156,27 @@ int nf_queue(struct sk_buff *skb, return status; } +/* Packets leaving via this function must come back through nf_reinject(). */ +int nf_queue(struct sk_buff *skb, struct nf_hook_state *state, + struct nf_hook_entry **entryp, unsigned int verdict) +{ + struct nf_hook_entry *entry = *entryp; + int ret; + + RCU_INIT_POINTER(state->hook_entries, entry); + ret = __nf_queue(skb, state, verdict >> NF_VERDICT_QBITS); + if (ret < 0) { + if (ret == -ESRCH && + (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS)) { + *entryp = rcu_dereference(entry->next); + return 1; + } + kfree_skb(skb); + } + + return 0; +} + void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) { struct nf_hook_entry *hook_entry; @@ -187,26 +203,26 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) entry->state.thresh = INT_MIN; if (verdict == NF_ACCEPT) { - next_hook: - verdict = nf_iterate(skb, &entry->state, &hook_entry); + hook_entry = rcu_dereference(hook_entry->next); + if (hook_entry) +next_hook: + verdict = nf_iterate(skb, &entry->state, &hook_entry); } switch (verdict & NF_VERDICT_MASK) { case NF_ACCEPT: case NF_STOP: +okfn: local_bh_disable(); entry->state.okfn(entry->state.net, entry->state.sk, skb); local_bh_enable(); break; case NF_QUEUE: - RCU_INIT_POINTER(entry->state.hook_entries, hook_entry); - err = nf_queue(skb, &entry->state, - verdict >> NF_VERDICT_QBITS); - if (err < 0) { - if (err == -ESRCH && - (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS)) + err = nf_queue(skb, &entry->state, &hook_entry, verdict); + if (err == 1) { + if (hook_entry) goto next_hook; - kfree_skb(skb); + goto okfn; } break; case NF_STOLEN: -- GitLab From a5efb6b6c99a3a6dc4330f51d8066f638bdea0ac Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 28 Sep 2016 16:18:47 +0200 Subject: [PATCH 0876/1167] KVM: s390: reject invalid modes for runtime instrumentation Usually a validity intercept is a programming error of the host because of invalid entries in the state description. We can get a validity intercept if the mode of the runtime instrumentation control block is wrong. As the host does not know which modes are valid, this can be used by userspace to trigger a WARN. Instead of printing a WARN let's return an error to userspace as this can only happen if userspace provides a malformed initial value (e.g. on migration). The kernel should never warn on bogus input. Instead let's log it into the s390 debug feature. While at it, let's return -EINVAL for all validity intercepts as this will trigger an error in QEMU like error: kvm run failed Invalid argument PSW=mask 0404c00180000000 addr 000000000063c226 cc 00 R00=000000000000004f R01=0000000000000004 R02=0000000000760005 R03=000000007fe0a000 R04=000000000064ba2a R05=000000049db73dd0 R06=000000000082c4b0 R07=0000000000000041 R08=0000000000000002 R09=000003e0804042a8 R10=0000000496152c42 R11=000000007fe0afb0 [...] This will avoid an endless loop of validity intercepts. Cc: stable@vger.kernel.org # v4.5+ Fixes: c6e5f166373a ("KVM: s390: implement the RI support of guest") Acked-by: Fan Zhang Reviewed-by: Pierre Morel Signed-off-by: Christian Borntraeger --- arch/s390/kvm/intercept.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index 1cab8a177d0e7..7a27eebab28ad 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -119,8 +119,13 @@ static int handle_validity(struct kvm_vcpu *vcpu) vcpu->stat.exit_validity++; trace_kvm_s390_intercept_validity(vcpu, viwhy); - WARN_ONCE(true, "kvm: unhandled validity intercept 0x%x\n", viwhy); - return -EOPNOTSUPP; + KVM_EVENT(3, "validity intercept 0x%x for pid %u (kvm 0x%pK)", viwhy, + current->pid, vcpu->kvm); + + /* do not warn on invalid runtime instrumentation mode */ + WARN_ONCE(viwhy != 0x44, "kvm: unhandled validity intercept 0x%x\n", + viwhy); + return -EINVAL; } static int handle_instruction(struct kvm_vcpu *vcpu) -- GitLab From a2ce092be34c4951e23104a0bfdec08f9577fada Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 13 Oct 2016 21:51:06 +0000 Subject: [PATCH 0877/1167] of: Add J-Core timer bindings Signed-off-by: Rich Felker Acked-by: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Cc: linux-sh@vger.kernel.org Cc: Daniel Lezcano Cc: Rob Herring Link: http://lkml.kernel.org/r/8b107c292ed8cf8eed0fa283071fc8a930098628.1476393790.git.dalias@libc.org Signed-off-by: Thomas Gleixner --- .../devicetree/bindings/timer/jcore,pit.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/jcore,pit.txt diff --git a/Documentation/devicetree/bindings/timer/jcore,pit.txt b/Documentation/devicetree/bindings/timer/jcore,pit.txt new file mode 100644 index 0000000000000..af5dd35469d73 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/jcore,pit.txt @@ -0,0 +1,24 @@ +J-Core Programmable Interval Timer and Clocksource + +Required properties: + +- compatible: Must be "jcore,pit". + +- reg: Memory region(s) for timer/clocksource registers. For SMP, + there should be one region per cpu, indexed by the sequential, + zero-based hardware cpu number. + +- interrupts: An interrupt to assign for the timer. The actual pit + core is integrated with the aic and allows the timer interrupt + assignment to be programmed by software, but this property is + required in order to reserve an interrupt number that doesn't + conflict with other devices. + + +Example: + +timer@200 { + compatible = "jcore,pit"; + reg = < 0x200 0x30 0x500 0x30 >; + interrupts = < 0x48 >; +}; -- GitLab From 9995f4f184613fb02ee73092b03545520a72b104 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 13 Oct 2016 21:51:06 +0000 Subject: [PATCH 0878/1167] clocksource: Add J-Core timer/clocksource driver At the hardware level, the J-Core PIT is integrated with the interrupt controller, but it is represented as its own device and has an independent programming interface. It provides a 12-bit countdown timer, which is not presently used, and a periodic timer. The interval length for the latter is programmable via a 32-bit throttle register whose units are determined by a bus-period register. The periodic timer is used to implement both periodic and oneshot clock event modes; in oneshot mode the interrupt handler simply disables the timer as soon as it fires. Despite its device tree node representing an interrupt for the PIT, the actual irq generated is programmable, not hard-wired. The driver is responsible for programming the PIT to generate the hardware irq number that the DT assigns to it. On SMP configurations, J-Core provides cpu-local instances of the PIT; no broadcast timer is needed. This driver supports the creation of the necessary per-cpu clock_event_device instances. A nanosecond-resolution clocksource is provided using the J-Core "RTC" registers, which give a 64-bit seconds count and 32-bit nanoseconds that wrap every second. The driver converts these to a full-range 32-bit nanoseconds count. Signed-off-by: Rich Felker Cc: Mark Rutland Cc: devicetree@vger.kernel.org Cc: linux-sh@vger.kernel.org Cc: Daniel Lezcano Cc: Rob Herring Link: http://lkml.kernel.org/r/b591ff12cc5ebf63d1edc98da26046f95a233814.1476393790.git.dalias@libc.org Signed-off-by: Thomas Gleixner --- drivers/clocksource/Kconfig | 10 ++ drivers/clocksource/Makefile | 1 + drivers/clocksource/jcore-pit.c | 249 ++++++++++++++++++++++++++++++++ include/linux/cpuhotplug.h | 1 + 4 files changed, 261 insertions(+) create mode 100644 drivers/clocksource/jcore-pit.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 2451908393593..e2c6e43cf8ca3 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -417,6 +417,16 @@ config SYS_SUPPORTS_SH_TMU config SYS_SUPPORTS_EM_STI bool +config CLKSRC_JCORE_PIT + bool "J-Core PIT timer driver" if COMPILE_TEST + depends on OF + depends on GENERIC_CLOCKEVENTS + depends on HAS_IOMEM + select CLKSRC_MMIO + help + This enables build of clocksource and clockevent driver for + the integrated PIT in the J-Core synthesizable, open source SoC. + config SH_TIMER_CMT bool "Renesas CMT timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index fd9d6df0bbc09..cf87f407f1adb 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o +obj-$(CONFIG_CLKSRC_JCORE_PIT) += jcore-pit.o obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o diff --git a/drivers/clocksource/jcore-pit.c b/drivers/clocksource/jcore-pit.c new file mode 100644 index 0000000000000..54e1665aa03c2 --- /dev/null +++ b/drivers/clocksource/jcore-pit.c @@ -0,0 +1,249 @@ +/* + * J-Core SoC PIT/clocksource driver + * + * Copyright (C) 2015-2016 Smart Energy Instruments, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PIT_IRQ_SHIFT 12 +#define PIT_PRIO_SHIFT 20 +#define PIT_ENABLE_SHIFT 26 +#define PIT_PRIO_MASK 0xf + +#define REG_PITEN 0x00 +#define REG_THROT 0x10 +#define REG_COUNT 0x14 +#define REG_BUSPD 0x18 +#define REG_SECHI 0x20 +#define REG_SECLO 0x24 +#define REG_NSEC 0x28 + +struct jcore_pit { + struct clock_event_device ced; + void __iomem *base; + unsigned long periodic_delta; + u32 enable_val; +}; + +static void __iomem *jcore_pit_base; +static struct jcore_pit __percpu *jcore_pit_percpu; + +static notrace u64 jcore_sched_clock_read(void) +{ + u32 seclo, nsec, seclo0; + __iomem void *base = jcore_pit_base; + + seclo = readl(base + REG_SECLO); + do { + seclo0 = seclo; + nsec = readl(base + REG_NSEC); + seclo = readl(base + REG_SECLO); + } while (seclo0 != seclo); + + return seclo * NSEC_PER_SEC + nsec; +} + +static cycle_t jcore_clocksource_read(struct clocksource *cs) +{ + return jcore_sched_clock_read(); +} + +static int jcore_pit_disable(struct jcore_pit *pit) +{ + writel(0, pit->base + REG_PITEN); + return 0; +} + +static int jcore_pit_set(unsigned long delta, struct jcore_pit *pit) +{ + jcore_pit_disable(pit); + writel(delta, pit->base + REG_THROT); + writel(pit->enable_val, pit->base + REG_PITEN); + return 0; +} + +static int jcore_pit_set_state_shutdown(struct clock_event_device *ced) +{ + struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced); + + return jcore_pit_disable(pit); +} + +static int jcore_pit_set_state_oneshot(struct clock_event_device *ced) +{ + struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced); + + return jcore_pit_disable(pit); +} + +static int jcore_pit_set_state_periodic(struct clock_event_device *ced) +{ + struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced); + + return jcore_pit_set(pit->periodic_delta, pit); +} + +static int jcore_pit_set_next_event(unsigned long delta, + struct clock_event_device *ced) +{ + struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced); + + return jcore_pit_set(delta, pit); +} + +static int jcore_pit_local_init(unsigned cpu) +{ + struct jcore_pit *pit = this_cpu_ptr(jcore_pit_percpu); + unsigned buspd, freq; + + pr_info("Local J-Core PIT init on cpu %u\n", cpu); + + buspd = readl(pit->base + REG_BUSPD); + freq = DIV_ROUND_CLOSEST(NSEC_PER_SEC, buspd); + pit->periodic_delta = DIV_ROUND_CLOSEST(NSEC_PER_SEC, HZ * buspd); + + clockevents_config_and_register(&pit->ced, freq, 1, ULONG_MAX); + + return 0; +} + +static irqreturn_t jcore_timer_interrupt(int irq, void *dev_id) +{ + struct jcore_pit *pit = this_cpu_ptr(dev_id); + + if (clockevent_state_oneshot(&pit->ced)) + jcore_pit_disable(pit); + + pit->ced.event_handler(&pit->ced); + + return IRQ_HANDLED; +} + +static int __init jcore_pit_init(struct device_node *node) +{ + int err; + unsigned pit_irq, cpu; + unsigned long hwirq; + u32 irqprio, enable_val; + + jcore_pit_base = of_iomap(node, 0); + if (!jcore_pit_base) { + pr_err("Error: Cannot map base address for J-Core PIT\n"); + return -ENXIO; + } + + pit_irq = irq_of_parse_and_map(node, 0); + if (!pit_irq) { + pr_err("Error: J-Core PIT has no IRQ\n"); + return -ENXIO; + } + + pr_info("Initializing J-Core PIT at %p IRQ %d\n", + jcore_pit_base, pit_irq); + + err = clocksource_mmio_init(jcore_pit_base, "jcore_pit_cs", + NSEC_PER_SEC, 400, 32, + jcore_clocksource_read); + if (err) { + pr_err("Error registering clocksource device: %d\n", err); + return err; + } + + sched_clock_register(jcore_sched_clock_read, 32, NSEC_PER_SEC); + + jcore_pit_percpu = alloc_percpu(struct jcore_pit); + if (!jcore_pit_percpu) { + pr_err("Failed to allocate memory for clock event device\n"); + return -ENOMEM; + } + + err = request_irq(pit_irq, jcore_timer_interrupt, + IRQF_TIMER | IRQF_PERCPU, + "jcore_pit", jcore_pit_percpu); + if (err) { + pr_err("pit irq request failed: %d\n", err); + free_percpu(jcore_pit_percpu); + return err; + } + + /* + * The J-Core PIT is not hard-wired to a particular IRQ, but + * integrated with the interrupt controller such that the IRQ it + * generates is programmable, as follows: + * + * The bit layout of the PIT enable register is: + * + * .....e..ppppiiiiiiii............ + * + * where the .'s indicate unrelated/unused bits, e is enable, + * p is priority, and i is hard irq number. + * + * For the PIT included in AIC1 (obsolete but still in use), + * any hard irq (trap number) can be programmed via the 8 + * iiiiiiii bits, and a priority (0-15) is programmable + * separately in the pppp bits. + * + * For the PIT included in AIC2 (current), the programming + * interface is equivalent modulo interrupt mapping. This is + * why a different compatible tag was not used. However only + * traps 64-127 (the ones actually intended to be used for + * interrupts, rather than syscalls/exceptions/etc.) can be + * programmed (the high 2 bits of i are ignored) and the + * priority pppp is <<2'd and or'd onto the irq number. This + * choice seems to have been made on the hardware engineering + * side under an assumption that preserving old AIC1 priority + * mappings was important. Future models will likely ignore + * the pppp field. + */ + hwirq = irq_get_irq_data(pit_irq)->hwirq; + irqprio = (hwirq >> 2) & PIT_PRIO_MASK; + enable_val = (1U << PIT_ENABLE_SHIFT) + | (hwirq << PIT_IRQ_SHIFT) + | (irqprio << PIT_PRIO_SHIFT); + + for_each_present_cpu(cpu) { + struct jcore_pit *pit = per_cpu_ptr(jcore_pit_percpu, cpu); + + pit->base = of_iomap(node, cpu); + if (!pit->base) { + pr_err("Unable to map PIT for cpu %u\n", cpu); + continue; + } + + pit->ced.name = "jcore_pit"; + pit->ced.features = CLOCK_EVT_FEAT_PERIODIC + | CLOCK_EVT_FEAT_ONESHOT + | CLOCK_EVT_FEAT_PERCPU; + pit->ced.cpumask = cpumask_of(cpu); + pit->ced.rating = 400; + pit->ced.irq = pit_irq; + pit->ced.set_state_shutdown = jcore_pit_set_state_shutdown; + pit->ced.set_state_periodic = jcore_pit_set_state_periodic; + pit->ced.set_state_oneshot = jcore_pit_set_state_oneshot; + pit->ced.set_next_event = jcore_pit_set_next_event; + + pit->enable_val = enable_val; + } + + cpuhp_setup_state(CPUHP_AP_JCORE_TIMER_STARTING, + "AP_JCORE_TIMER_STARTING", + jcore_pit_local_init, NULL); + + return 0; +} + +CLOCKSOURCE_OF_DECLARE(jcore_pit, "jcore,pit", jcore_pit_init); diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 9b207a8c5af3c..afe641c02dca3 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -81,6 +81,7 @@ enum cpuhp_state { CPUHP_AP_ARM_ARCH_TIMER_STARTING, CPUHP_AP_ARM_GLOBAL_TIMER_STARTING, CPUHP_AP_DUMMY_TIMER_STARTING, + CPUHP_AP_JCORE_TIMER_STARTING, CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING, CPUHP_AP_ARM_TWD_STARTING, CPUHP_AP_METAG_TIMER_STARTING, -- GitLab From 7aa8e63f0d0f2e0ae353632bca1ce75a258696c6 Mon Sep 17 00:00:00 2001 From: Jiri Bohac Date: Thu, 20 Oct 2016 12:29:26 +0200 Subject: [PATCH 0879/1167] ipv6: properly prevent temp_prefered_lft sysctl race The check for an underflow of tmp_prefered_lft is always false because tmp_prefered_lft is unsigned. The intention of the check was to guard against racing with an update of the temp_prefered_lft sysctl, potentially resulting in an underflow. As suggested by David Miller, the best way to prevent the race is by reading the sysctl variable using READ_ONCE. Signed-off-by: Jiri Bohac Reported-by: Julia Lawall Fixes: 76506a986dc3 ("IPv6: fix DESYNC_FACTOR") Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index cc7c26d05f452..060dd99220181 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1185,6 +1185,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i u32 addr_flags; unsigned long now = jiffies; long max_desync_factor; + s32 cnf_temp_preferred_lft; write_lock_bh(&idev->lock); if (ift) { @@ -1228,9 +1229,10 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i /* recalculate max_desync_factor each time and update * idev->desync_factor if it's larger */ + cnf_temp_preferred_lft = READ_ONCE(idev->cnf.temp_prefered_lft); max_desync_factor = min_t(__u32, idev->cnf.max_desync_factor, - idev->cnf.temp_prefered_lft - regen_advance); + cnf_temp_preferred_lft - regen_advance); if (unlikely(idev->desync_factor > max_desync_factor)) { if (max_desync_factor > 0) { @@ -1245,11 +1247,8 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i tmp_valid_lft = min_t(__u32, ifp->valid_lft, idev->cnf.temp_valid_lft + age); - tmp_prefered_lft = idev->cnf.temp_prefered_lft + age - + tmp_prefered_lft = cnf_temp_preferred_lft + age - idev->desync_factor; - /* guard against underflow in case of concurrent updates to cnf */ - if (unlikely(tmp_prefered_lft < 0)) - tmp_prefered_lft = 0; tmp_prefered_lft = min_t(__u32, ifp->prefered_lft, tmp_prefered_lft); tmp_plen = ifp->prefix_len; tmp_tstamp = ifp->tstamp; -- GitLab From fcd91dd449867c6bfe56a81cabba76b829fd05cd Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Thu, 20 Oct 2016 15:58:02 +0200 Subject: [PATCH 0880/1167] net: add recursion limit to GRO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, GRO can do unlimited recursion through the gro_receive handlers. This was fixed for tunneling protocols by limiting tunnel GRO to one level with encap_mark, but both VLAN and TEB still have this problem. Thus, the kernel is vulnerable to a stack overflow, if we receive a packet composed entirely of VLAN headers. This patch adds a recursion counter to the GRO layer to prevent stack overflow. When a gro_receive function hits the recursion limit, GRO is aborted for this skb and it is processed normally. This recursion counter is put in the GRO CB, but could be turned into a percpu counter if we run out of space in the CB. Thanks to Vladimír Beneš for the initial bug report. Fixes: CVE-2016-7039 Fixes: 9b174d88c257 ("net: Add Transparent Ethernet Bridging GRO support.") Fixes: 66e5133f19e9 ("vlan: Add GRO support for non hardware accelerated vlan") Signed-off-by: Sabrina Dubroca Reviewed-by: Jiri Benc Acked-by: Hannes Frederic Sowa Acked-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/geneve.c | 2 +- drivers/net/vxlan.c | 2 +- include/linux/netdevice.h | 39 ++++++++++++++++++++++++++++++++++++++- net/8021q/vlan.c | 2 +- net/core/dev.c | 1 + net/ethernet/eth.c | 2 +- net/ipv4/af_inet.c | 2 +- net/ipv4/fou.c | 4 ++-- net/ipv4/gre_offload.c | 2 +- net/ipv4/udp_offload.c | 2 +- net/ipv6/ip6_offload.c | 2 +- 11 files changed, 49 insertions(+), 11 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 3c20e87bb7619..16af1ce99233a 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -453,7 +453,7 @@ static struct sk_buff **geneve_gro_receive(struct sock *sk, skb_gro_pull(skb, gh_len); skb_gro_postpull_rcsum(skb, gh, gh_len); - pp = ptype->callbacks.gro_receive(head, skb); + pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); flush = 0; out_unlock: diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e7d16687538b8..c1639a3e95a44 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -583,7 +583,7 @@ static struct sk_buff **vxlan_gro_receive(struct sock *sk, } } - pp = eth_gro_receive(head, skb); + pp = call_gro_receive(eth_gro_receive, head, skb); flush = 0; out: diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 465e128699a14..91ee3643ccc8d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2169,7 +2169,10 @@ struct napi_gro_cb { /* Used to determine if flush_id can be ignored */ u8 is_atomic:1; - /* 5 bit hole */ + /* Number of gro_receive callbacks this packet already went through */ + u8 recursion_counter:4; + + /* 1 bit hole */ /* used to support CHECKSUM_COMPLETE for tunneling protocols */ __wsum csum; @@ -2180,6 +2183,40 @@ struct napi_gro_cb { #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb) +#define GRO_RECURSION_LIMIT 15 +static inline int gro_recursion_inc_test(struct sk_buff *skb) +{ + return ++NAPI_GRO_CB(skb)->recursion_counter == GRO_RECURSION_LIMIT; +} + +typedef struct sk_buff **(*gro_receive_t)(struct sk_buff **, struct sk_buff *); +static inline struct sk_buff **call_gro_receive(gro_receive_t cb, + struct sk_buff **head, + struct sk_buff *skb) +{ + if (unlikely(gro_recursion_inc_test(skb))) { + NAPI_GRO_CB(skb)->flush |= 1; + return NULL; + } + + return cb(head, skb); +} + +typedef struct sk_buff **(*gro_receive_sk_t)(struct sock *, struct sk_buff **, + struct sk_buff *); +static inline struct sk_buff **call_gro_receive_sk(gro_receive_sk_t cb, + struct sock *sk, + struct sk_buff **head, + struct sk_buff *skb) +{ + if (unlikely(gro_recursion_inc_test(skb))) { + NAPI_GRO_CB(skb)->flush |= 1; + return NULL; + } + + return cb(sk, head, skb); +} + struct packet_type { __be16 type; /* This is really htons(ether_type). */ struct net_device *dev; /* NULL is wildcarded here */ diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 8de138d3306bd..f2531ad66b68b 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -664,7 +664,7 @@ static struct sk_buff **vlan_gro_receive(struct sk_buff **head, skb_gro_pull(skb, sizeof(*vhdr)); skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr)); - pp = ptype->callbacks.gro_receive(head, skb); + pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); out_unlock: rcu_read_unlock(); diff --git a/net/core/dev.c b/net/core/dev.c index b09ac57f43483..dbc8713069107 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4511,6 +4511,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff NAPI_GRO_CB(skb)->flush = 0; NAPI_GRO_CB(skb)->free = 0; NAPI_GRO_CB(skb)->encap_mark = 0; + NAPI_GRO_CB(skb)->recursion_counter = 0; NAPI_GRO_CB(skb)->is_fou = 0; NAPI_GRO_CB(skb)->is_atomic = 1; NAPI_GRO_CB(skb)->gro_remcsum_start = 0; diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 66dff5e3d7728..02acfff36028b 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -439,7 +439,7 @@ struct sk_buff **eth_gro_receive(struct sk_buff **head, skb_gro_pull(skb, sizeof(*eh)); skb_gro_postpull_rcsum(skb, eh, sizeof(*eh)); - pp = ptype->callbacks.gro_receive(head, skb); + pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); out_unlock: rcu_read_unlock(); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 1effc986739e5..9648c97e541f0 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1391,7 +1391,7 @@ struct sk_buff **inet_gro_receive(struct sk_buff **head, struct sk_buff *skb) skb_gro_pull(skb, sizeof(*iph)); skb_set_transport_header(skb, skb_gro_offset(skb)); - pp = ops->callbacks.gro_receive(head, skb); + pp = call_gro_receive(ops->callbacks.gro_receive, head, skb); out_unlock: rcu_read_unlock(); diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index cf50f7e2b0124..030d1531e897a 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -249,7 +249,7 @@ static struct sk_buff **fou_gro_receive(struct sock *sk, if (!ops || !ops->callbacks.gro_receive) goto out_unlock; - pp = ops->callbacks.gro_receive(head, skb); + pp = call_gro_receive(ops->callbacks.gro_receive, head, skb); out_unlock: rcu_read_unlock(); @@ -441,7 +441,7 @@ static struct sk_buff **gue_gro_receive(struct sock *sk, if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive)) goto out_unlock; - pp = ops->callbacks.gro_receive(head, skb); + pp = call_gro_receive(ops->callbacks.gro_receive, head, skb); flush = 0; out_unlock: diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 96e0efecefa6a..d5cac99170b19 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -229,7 +229,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head, /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/ skb_gro_postpull_rcsum(skb, greh, grehlen); - pp = ptype->callbacks.gro_receive(head, skb); + pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); flush = 0; out_unlock: diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index f9333c9636076..b2be1d9757efb 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -295,7 +295,7 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb, skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */ skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr)); - pp = udp_sk(sk)->gro_receive(sk, head, skb); + pp = call_gro_receive_sk(udp_sk(sk)->gro_receive, sk, head, skb); out_unlock: rcu_read_unlock(); diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index e7bfd55899a34..1fcf61f1cbc33 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -246,7 +246,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, skb_gro_postpull_rcsum(skb, iph, nlen); - pp = ops->callbacks.gro_receive(head, skb); + pp = call_gro_receive(ops->callbacks.gro_receive, head, skb); out_unlock: rcu_read_unlock(); -- GitLab From 0d906b1e8d4002cdd59590fec630f4e75023e288 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 20 Oct 2016 17:13:53 +0200 Subject: [PATCH 0881/1167] bpf, test: fix ld_abs + vlan push/pop stress test After commit 636c2628086e ("net: skbuff: Remove errornous length validation in skb_vlan_pop()") mentioned test case stopped working, throwing a -12 (ENOMEM) return code. The issue however is not due to 636c2628086e, but rather due to a buggy test case that got uncovered from the change in behaviour in 636c2628086e. The data_size of that test case for the skb was set to 1. In the bpf_fill_ld_abs_vlan_push_pop() handler bpf insns are generated that loop with: reading skb data, pushing 68 tags, reading skb data, popping 68 tags, reading skb data, etc, in order to force a skb expansion and thus trigger that JITs recache skb->data. Problem is that initial data_size is too small. While before 636c2628086e, the test silently bailed out due to the skb->len < VLAN_ETH_HLEN check with returning 0, and now throwing an error from failing skb_ensure_writable(). Set at least minimum of ETH_HLEN as an initial length so that on first push of data, equivalent pop will succeed. Fixes: 4d9c5c53ac99 ("test_bpf: add bpf_skb_vlan_push/pop() tests") Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- lib/test_bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 94346b4d8984c..0362da0b66c35 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -4831,7 +4831,7 @@ static struct bpf_test tests[] = { { }, INTERNAL, { 0x34 }, - { { 1, 0xbef } }, + { { ETH_HLEN, 0xbef } }, .fill_helper = bpf_fill_ld_abs_vlan_push_pop, }, /* -- GitLab From 2399d6143f85b155ae84ccd94237befd36b8f6c7 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Oct 2016 09:32:19 -0700 Subject: [PATCH 0882/1167] net: dsa: bcm_sf2: Prevent GPHY shutdown for kexec'd kernels For a kernel that is being kexec'd we re-enable the integrated GPHY in order for the subsequent MDIO bus scan to succeed and properly bind to the bcm7xxx PHY driver. If we did not do that, the GPHY would be shut down by the time the MDIO driver is probing the bus, and it would fail to read the correct PHY OUI and therefore bind to an appropriate PHY driver. Later on, this would cause DSA not to be able to successfully attach to the PHY, and the interface would not be created at all. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 0427009bc9246..077a24541584e 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "bcm_sf2.h" #include "bcm_sf2_regs.h" @@ -1133,6 +1134,18 @@ static int bcm_sf2_sw_remove(struct platform_device *pdev) return 0; } +static void bcm_sf2_sw_shutdown(struct platform_device *pdev) +{ + struct bcm_sf2_priv *priv = platform_get_drvdata(pdev); + + /* For a kernel about to be kexec'd we want to keep the GPHY on for a + * successful MDIO bus scan to occur. If we did turn off the GPHY + * before (e.g: port_disable), this will also power it back on. + */ + if (priv->hw_params.num_gphy == 1) + bcm_sf2_gphy_enable_set(priv->dev->ds, kexec_in_progress); +} + #ifdef CONFIG_PM_SLEEP static int bcm_sf2_suspend(struct device *dev) { @@ -1163,6 +1176,7 @@ MODULE_DEVICE_TABLE(of, bcm_sf2_of_match); static struct platform_driver bcm_sf2_driver = { .probe = bcm_sf2_sw_probe, .remove = bcm_sf2_sw_remove, + .shutdown = bcm_sf2_sw_shutdown, .driver = { .name = "brcm-sf2", .of_match_table = bcm_sf2_of_match, -- GitLab From 286c72deabaa240b7eebbd99496ed3324d69f3c0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 20 Oct 2016 09:39:40 -0700 Subject: [PATCH 0883/1167] udp: must lock the socket in udp_disconnect() Baozeng Ding reported KASAN traces showing uses after free in udp_lib_get_port() and other related UDP functions. A CONFIG_DEBUG_PAGEALLOC=y kernel would eventually crash. I could write a reproducer with two threads doing : static int sock_fd; static void *thr1(void *arg) { for (;;) { connect(sock_fd, (const struct sockaddr *)arg, sizeof(struct sockaddr_in)); } } static void *thr2(void *arg) { struct sockaddr_in unspec; for (;;) { memset(&unspec, 0, sizeof(unspec)); connect(sock_fd, (const struct sockaddr *)&unspec, sizeof(unspec)); } } Problem is that udp_disconnect() could run without holding socket lock, and this was causing list corruptions. Signed-off-by: Eric Dumazet Reported-by: Baozeng Ding Signed-off-by: David S. Miller --- include/net/udp.h | 1 + net/ipv4/ping.c | 2 +- net/ipv4/raw.c | 2 +- net/ipv4/udp.c | 13 +++++++++++-- net/ipv6/ping.c | 2 +- net/ipv6/raw.c | 2 +- net/l2tp/l2tp_ip.c | 2 +- net/l2tp/l2tp_ip6.c | 2 +- 8 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/net/udp.h b/include/net/udp.h index ea53a87d880fa..4948790d393d7 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -258,6 +258,7 @@ void udp_flush_pending_frames(struct sock *sk); void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst); int udp_rcv(struct sk_buff *skb); int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); +int __udp_disconnect(struct sock *sk, int flags); int udp_disconnect(struct sock *sk, int flags); unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait); struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 7cf7d6e380c2c..205e2000d3950 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -994,7 +994,7 @@ struct proto ping_prot = { .init = ping_init_sock, .close = ping_close, .connect = ip4_datagram_connect, - .disconnect = udp_disconnect, + .disconnect = __udp_disconnect, .setsockopt = ip_setsockopt, .getsockopt = ip_getsockopt, .sendmsg = ping_v4_sendmsg, diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 90a85c9558724..ecbe5a7c2d6d3 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -918,7 +918,7 @@ struct proto raw_prot = { .close = raw_close, .destroy = raw_destroy, .connect = ip4_datagram_connect, - .disconnect = udp_disconnect, + .disconnect = __udp_disconnect, .ioctl = raw_ioctl, .init = raw_init, .setsockopt = raw_setsockopt, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7d96dc2d3d08f..311613e413cbe 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1345,7 +1345,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, goto try_again; } -int udp_disconnect(struct sock *sk, int flags) +int __udp_disconnect(struct sock *sk, int flags) { struct inet_sock *inet = inet_sk(sk); /* @@ -1367,6 +1367,15 @@ int udp_disconnect(struct sock *sk, int flags) sk_dst_reset(sk); return 0; } +EXPORT_SYMBOL(__udp_disconnect); + +int udp_disconnect(struct sock *sk, int flags) +{ + lock_sock(sk); + __udp_disconnect(sk, flags); + release_sock(sk); + return 0; +} EXPORT_SYMBOL(udp_disconnect); void udp_lib_unhash(struct sock *sk) @@ -2193,7 +2202,7 @@ int udp_abort(struct sock *sk, int err) sk->sk_err = err; sk->sk_error_report(sk); - udp_disconnect(sk, 0); + __udp_disconnect(sk, 0); release_sock(sk); diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 0e983b694ee80..66e2d9dfc43a8 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -180,7 +180,7 @@ struct proto pingv6_prot = { .init = ping_init_sock, .close = ping_close, .connect = ip6_datagram_connect_v6_only, - .disconnect = udp_disconnect, + .disconnect = __udp_disconnect, .setsockopt = ipv6_setsockopt, .getsockopt = ipv6_getsockopt, .sendmsg = ping_v6_sendmsg, diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 54404f08efcca..054a1d84fc5e9 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1241,7 +1241,7 @@ struct proto rawv6_prot = { .close = rawv6_close, .destroy = raw6_destroy, .connect = ip6_datagram_connect_v6_only, - .disconnect = udp_disconnect, + .disconnect = __udp_disconnect, .ioctl = rawv6_ioctl, .init = rawv6_init_sk, .setsockopt = rawv6_setsockopt, diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 42de4ccd159f6..fce25afb652ad 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -338,7 +338,7 @@ static int l2tp_ip_disconnect(struct sock *sk, int flags) if (sock_flag(sk, SOCK_ZAPPED)) return 0; - return udp_disconnect(sk, flags); + return __udp_disconnect(sk, flags); } static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr, diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index ea2ae6664cc8d..ad3468c32b53a 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -410,7 +410,7 @@ static int l2tp_ip6_disconnect(struct sock *sk, int flags) if (sock_flag(sk, SOCK_ZAPPED)) return 0; - return udp_disconnect(sk, flags); + return __udp_disconnect(sk, flags); } static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr, -- GitLab From a681574c99be23e4d20b769bf0e543239c364af5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 20 Oct 2016 10:26:48 -0700 Subject: [PATCH 0884/1167] ipv4: disable BH in set_ping_group_range() In commit 4ee3bd4a8c746 ("ipv4: disable BH when changing ip local port range") Cong added BH protection in set_local_port_range() but missed that same fix was needed in set_ping_group_range() Fixes: b8f1a55639e6 ("udp: Add function to make source port for UDP tunnels") Signed-off-by: Eric Dumazet Reported-by: Eric Salo Signed-off-by: David S. Miller --- net/ipv4/sysctl_net_ipv4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 1cb67de106fee..500ae4010bed3 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -109,10 +109,10 @@ static void set_ping_group_range(struct ctl_table *table, kgid_t low, kgid_t hig kgid_t *data = table->data; struct net *net = container_of(table->data, struct net, ipv4.ping_group_range.range); - write_seqlock(&net->ipv4.ip_local_ports.lock); + write_seqlock_bh(&net->ipv4.ip_local_ports.lock); data[0] = low; data[1] = high; - write_sequnlock(&net->ipv4.ip_local_ports.lock); + write_sequnlock_bh(&net->ipv4.ip_local_ports.lock); } /* Validate changes from /proc interface. */ -- GitLab From 593876838826914a7e4e05fbbcb728be6fbc4d89 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 18 Oct 2016 13:49:18 +0800 Subject: [PATCH 0885/1167] Revert "clocksource/drivers/timer_sun5i: Replace code by clocksource_mmio_init" struct clocksource is also used by the clk notifier callback, to unregister and re-register the clocksource with a different clock rate. clocksource_mmio_init does not pass back a pointer to the struct used, and the clk notifier callback assumes that the struct clocksource in struct sun5i_timer_clksrc is valid. This results in a kernel NULL pointer dereference when the hstimer clock is changed: Unable to handle kernel NULL pointer dereference at virtual address 00000004 [] (clocksource_unbind) from [] (clocksource_unregister+0x2c/0x44) [] (clocksource_unregister) from [] (sun5i_rate_cb_clksrc+0x34/0x3c) [] (sun5i_rate_cb_clksrc) from [] (notifier_call_chain+0x44/0x84) [] (notifier_call_chain) from [] (__srcu_notifier_call_chain+0x44/0x60) [] (__srcu_notifier_call_chain) from [] (srcu_notifier_call_chain+0x18/0x20) [] (srcu_notifier_call_chain) from [] (__clk_notify+0x70/0x7c) [] (__clk_notify) from [] (clk_propagate_rate_change+0xa4/0xc4) [] (clk_propagate_rate_change) from [] (clk_propagate_rate_change+0x6c/0xc4) Revert the commit for now. clocksource_mmio_init can be made to pass back a pointer, but the code churn and usage of an inner struct might not be worth it. Fixes: 157dfadef832 ("clocksource/drivers/timer_sun5i: Replace code by clocksource_mmio_init") Reported-by: Maxime Ripard Signed-off-by: Chen-Yu Tsai Cc: linux-sunxi@googlegroups.com Cc: Daniel Lezcano Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/20161018054918.26855-1-wens@csie.org Signed-off-by: Thomas Gleixner --- drivers/clocksource/timer-sun5i.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index c184eb84101e9..4f87f3e76d832 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -152,6 +152,13 @@ static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static cycle_t sun5i_clksrc_read(struct clocksource *clksrc) +{ + struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc); + + return ~readl(cs->timer.base + TIMER_CNTVAL_LO_REG(1)); +} + static int sun5i_rate_cb_clksrc(struct notifier_block *nb, unsigned long event, void *data) { @@ -210,8 +217,13 @@ static int __init sun5i_setup_clocksource(struct device_node *node, writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, base + TIMER_CTL_REG(1)); - ret = clocksource_mmio_init(base + TIMER_CNTVAL_LO_REG(1), node->name, - rate, 340, 32, clocksource_mmio_readl_down); + cs->clksrc.name = node->name; + cs->clksrc.rating = 340; + cs->clksrc.read = sun5i_clksrc_read; + cs->clksrc.mask = CLOCKSOURCE_MASK(32); + cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; + + ret = clocksource_register_hz(&cs->clksrc, rate); if (ret) { pr_err("Couldn't register clock source.\n"); goto err_remove_notifier; -- GitLab From 28e3d7002ba9f773662b2cf75d28cadfa29dc442 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 20 Oct 2016 18:03:36 +0300 Subject: [PATCH 0886/1167] watchdog: wdat_wdt: Ping the watchdog on resume It turns out we need to ping the watchdog hardware on resume when we re-program it. Otherwise this causes inadvertent reset to trigger right after the resume is complete. Fixes: 058dfc767008 (ACPI / watchdog: Add support for WDAT hardware watchdog) Signed-off-by: Mika Westerberg Acked-by: Guenter Roeck Signed-off-by: Rafael J. Wysocki --- drivers/watchdog/wdat_wdt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c index e473e3b237203..6d1fbda0f461c 100644 --- a/drivers/watchdog/wdat_wdt.c +++ b/drivers/watchdog/wdat_wdt.c @@ -499,6 +499,10 @@ static int wdat_wdt_resume_noirq(struct device *dev) ret = wdat_wdt_enable_reboot(wdat); if (ret) return ret; + + ret = wdat_wdt_ping(&wdat->wdd); + if (ret) + return ret; } return wdat_wdt_start(&wdat->wdd); -- GitLab From 91bbc174d45c347aa7aedb2215cc7d2013c06c1f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 25 Sep 2016 13:53:58 +0200 Subject: [PATCH 0887/1167] clk: at91: Fix a return value in case of error If 'clk_hw_register()' fails, it is likely that we expect to return an error instead of a valid pointer (which would mean success). Fix commit f5644f10dcfb ("clk: at91: Migrate to clk_hw based registration and OF APIs") Signed-off-by: Christophe JAILLET Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-programmable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 190122e64a3a5..85a449cf61e3f 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -203,7 +203,7 @@ at91_clk_register_programmable(struct regmap *regmap, ret = clk_hw_register(NULL, &prog->hw); if (ret) { kfree(prog); - hw = &prog->hw; + hw = ERR_PTR(ret); } return hw; -- GitLab From 97dcaa0fcfd24daa9a36c212c1ad1d5a97759212 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Oct 2016 18:15:16 -0700 Subject: [PATCH 0888/1167] kexec: Export kexec_in_progress to modules The bcm_sf2 driver uses kexec_in_progress to know whether it can power down an integrated PHY during shutdown, and can be built as a module. Other modules may be using this in the future, so export it. Fixes: 2399d6143f85 ("net: dsa: bcm_sf2: Prevent GPHY shutdown for kexec'd kernels") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- kernel/kexec_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index 5616755895119..786ab85a54524 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -59,6 +59,7 @@ size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data); /* Flag to indicate we are going to kexec a new kernel */ bool kexec_in_progress = false; +EXPORT_SYMBOL_GPL(kexec_in_progress); /* Location of the reserved area for the crash kernel */ -- GitLab From 1b4c59b7a1d0b9d8019254a5f2e35b2663f49a9e Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 22 Aug 2016 10:54:07 +0200 Subject: [PATCH 0889/1167] target: fix potential race window in target_sess_cmd_list_waiting() target_sess_cmd_list_waiting() might hit on a condition where the kref for the command is already 0, but the destructor has not been called yet (or is stuck in waiting for a spin lock). Rather than leaving the command on the list we should explicitly remove it to avoid race issues later on. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index e825d580ccee7..7dfefd66df938 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2535,7 +2535,9 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) * invocations before se_cmd descriptor release. */ if (ack_kref) { - kref_get(&se_cmd->cmd_kref); + if (!kref_get_unless_zero(&se_cmd->cmd_kref)) + return -EINVAL; + se_cmd->se_cmd_flags |= SCF_ACK_KREF; } @@ -2616,7 +2618,7 @@ EXPORT_SYMBOL(target_put_sess_cmd); */ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) { - struct se_cmd *se_cmd; + struct se_cmd *se_cmd, *tmp_cmd; unsigned long flags; int rc; @@ -2628,14 +2630,16 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) se_sess->sess_tearing_down = 1; list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); - list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) { + list_for_each_entry_safe(se_cmd, tmp_cmd, + &se_sess->sess_wait_list, se_cmd_list) { rc = kref_get_unless_zero(&se_cmd->cmd_kref); if (rc) { se_cmd->cmd_wait_set = 1; spin_lock(&se_cmd->t_state_lock); se_cmd->transport_state |= CMD_T_FABRIC_STOP; spin_unlock(&se_cmd->t_state_lock); - } + } else + list_del_init(&se_cmd->se_cmd_list); } spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); -- GitLab From b04bf5833e8a0d6ae4e3f7b35b30c4ab6ff7ea1b Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 22 Aug 2016 10:54:08 +0200 Subject: [PATCH 0890/1167] target/tcm_fc: print command pointer in debug message When allocating a new command we should add the pointer to the debug statements; that allows us to match this with other debug statements for handling data. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tfc_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 216e18cc9133d..36f08644250c2 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -575,7 +575,7 @@ static void ft_send_work(struct work_struct *work) TARGET_SCF_ACK_KREF)) goto err; - pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); + pr_debug("r_ctl %x target_submit_cmd %p\n", fh->fh_r_ctl, cmd); return; err: -- GitLab From 91b385b4909e040450389b11961a8ba8f8e9a35e Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 22 Aug 2016 10:54:09 +0200 Subject: [PATCH 0891/1167] target/tcm_fc: return detailed error in ft_sess_create() Not every failure is due to out-of-memory; the ACLs might not be set, too. So return a detailed error code in ft_sess_create() instead of just a NULL pointer. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tfc_sess.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 6ffbb603d9122..cc8c2614397bd 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -223,7 +223,7 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, sess = kzalloc(sizeof(*sess), GFP_KERNEL); if (!sess) - return NULL; + return ERR_PTR(-ENOMEM); kref_init(&sess->kref); /* ref for table entry */ sess->tport = tport; @@ -234,8 +234,9 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, TARGET_PROT_NORMAL, &initiatorname[0], sess, ft_sess_alloc_cb); if (IS_ERR(sess->se_sess)) { + int rc = PTR_ERR(sess->se_sess); kfree(sess); - return NULL; + sess = ERR_PTR(rc); } return sess; } -- GitLab From 8962a4d29bcb3d12164c02d207c8ff1ab8b04558 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 22 Aug 2016 10:54:10 +0200 Subject: [PATCH 0892/1167] target/tcm_fc: Update debugging statements to match libfc usage Update the debug statements to match those from libfc. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tfc_sess.c | 37 ++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index cc8c2614397bd..fd5c3de794705 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -39,6 +39,11 @@ #include "tcm_fc.h" +#define TFC_SESS_DBG(lport, fmt, args...) \ + pr_debug("host%u: rport %6.6x: " fmt, \ + (lport)->host->host_no, \ + (lport)->port_id, ##args ) + static void ft_sess_delete_all(struct ft_tport *); /* @@ -167,24 +172,29 @@ static struct ft_sess *ft_sess_get(struct fc_lport *lport, u32 port_id) struct ft_tport *tport; struct hlist_head *head; struct ft_sess *sess; + char *reason = "no session created"; rcu_read_lock(); tport = rcu_dereference(lport->prov[FC_TYPE_FCP]); - if (!tport) + if (!tport) { + reason = "not an FCP port"; goto out; + } head = &tport->hash[ft_sess_hash(port_id)]; hlist_for_each_entry_rcu(sess, head, hash) { if (sess->port_id == port_id) { kref_get(&sess->kref); rcu_read_unlock(); - pr_debug("port_id %x found %p\n", port_id, sess); + TFC_SESS_DBG(lport, "port_id %x found %p\n", + port_id, sess); return sess; } } out: rcu_read_unlock(); - pr_debug("port_id %x not found\n", port_id); + TFC_SESS_DBG(lport, "port_id %x not found, %s\n", + port_id, reason); return NULL; } @@ -195,7 +205,7 @@ static int ft_sess_alloc_cb(struct se_portal_group *se_tpg, struct ft_tport *tport = sess->tport; struct hlist_head *head = &tport->hash[ft_sess_hash(sess->port_id)]; - pr_debug("port_id %x sess %p\n", sess->port_id, sess); + TFC_SESS_DBG(tport->lport, "port_id %x sess %p\n", sess->port_id, sess); hlist_add_head_rcu(&sess->hash, head); tport->sess_count++; @@ -320,7 +330,7 @@ void ft_sess_close(struct se_session *se_sess) mutex_unlock(&ft_lport_lock); return; } - pr_debug("port_id %x\n", port_id); + TFC_SESS_DBG(sess->tport->lport, "port_id %x close session\n", port_id); ft_sess_unhash(sess); mutex_unlock(&ft_lport_lock); ft_close_sess(sess); @@ -380,8 +390,13 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, if (!(fcp_parm & FCP_SPPF_INIT_FCN)) return FC_SPP_RESP_CONF; sess = ft_sess_create(tport, rdata->ids.port_id, rdata); - if (!sess) - return FC_SPP_RESP_RES; + if (IS_ERR(sess)) { + if (PTR_ERR(sess) == -EACCES) { + spp->spp_flags &= ~FC_SPP_EST_IMG_PAIR; + return FC_SPP_RESP_CONF; + } else + return FC_SPP_RESP_RES; + } if (!sess->params) rdata->prli_count++; sess->params = fcp_parm; @@ -424,8 +439,8 @@ static int ft_prli(struct fc_rport_priv *rdata, u32 spp_len, mutex_lock(&ft_lport_lock); ret = ft_prli_locked(rdata, spp_len, rspp, spp); mutex_unlock(&ft_lport_lock); - pr_debug("port_id %x flags %x ret %x\n", - rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret); + TFC_SESS_DBG(rdata->local_port, "port_id %x flags %x ret %x\n", + rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret); return ret; } @@ -478,11 +493,11 @@ static void ft_recv(struct fc_lport *lport, struct fc_frame *fp) struct ft_sess *sess; u32 sid = fc_frame_sid(fp); - pr_debug("sid %x\n", sid); + TFC_SESS_DBG(lport, "recv sid %x\n", sid); sess = ft_sess_get(lport, sid); if (!sess) { - pr_debug("sid %x sess lookup failed\n", sid); + TFC_SESS_DBG(lport, "sid %x sess lookup failed\n", sid); /* TBD XXX - if FCP_CMND, send PRLO */ fc_frame_free(fp); return; -- GitLab From 1ba0158fa66b5b2c597a748f87be1650c9960ccc Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 22 Aug 2016 10:54:11 +0200 Subject: [PATCH 0893/1167] target/tcm_fc: use CPU affinity for responses The libfc stack assigns exchange IDs based on the CPU the request was received on, so we need to send the responses via the same CPU. Otherwise the send logic gets confuses and responses will be delayed, causing exchange timeouts on the initiator side. Signed-off-by: Hannes Reinecke Cc: stable@vger.kernel.org # 4.5+ Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tfc_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 36f08644250c2..ff5de9a96643f 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -572,7 +572,7 @@ static void ft_send_work(struct work_struct *work) if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), ntohl(fcp->fc_dl), task_attr, data_dir, - TARGET_SCF_ACK_KREF)) + TARGET_SCF_ACK_KREF | TARGET_SCF_USE_CPUID)) goto err; pr_debug("r_ctl %x target_submit_cmd %p\n", fh->fh_r_ctl, cmd); -- GitLab From 3118dac501bc0317de099db81618d589503351e1 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 6 Oct 2016 23:06:43 +0530 Subject: [PATCH 0894/1167] kernel/irq: Export irq_set_parent() The TPS65217 driver grew interrupt support which uses irq_set_parent(). While it's not yet clear why this is used in the first place, building the driver as a module fails with: ERROR: ".irq_set_parent" [drivers/mfd/tps65217.ko] undefined! The correctness of the driver change is still investigated, but for now it's less trouble to export irq_set_parent() than dealing with the build wreckage. [ tglx: Rewrote changelog and made the export GPL ] Fixes: 6556bdacf646 ("mfd: tps65217: Add support for IRQs") Signed-off-by: Sudip Mukherjee Cc: Sudip Mukherjee Cc: Marcin Niestroj Cc: Grygorii Strashko Cc: Tony Lindgren Cc: Lee Jones Link: http://lkml.kernel.org/r/1475775403-27207-1-git-send-email-sudipm.mukherjee@gmail.com Signed-off-by: Thomas Gleixner --- kernel/irq/manage.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0c5f1a5db654c..9c4d304832648 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -721,6 +721,7 @@ int irq_set_parent(int irq, int parent_irq) irq_put_desc_unlock(desc, flags); return 0; } +EXPORT_SYMBOL_GPL(irq_set_parent); #endif /* -- GitLab From 1f1cc4566bd9dd8d3cf19965a4b6392143618536 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Oct 2016 16:53:59 +0200 Subject: [PATCH 0895/1167] gpio: GPIO_GET_CHIPINFO_IOCTL: Fix line offset validation The current line offset validation is off by one. Depending on the data stored behind the descs array this can either cause undefined behavior or disclose arbitrary, potentially sensitive, memory to the issuing userspace application. Make sure that offset is within the bounds of the desc array. Cc: stable@vger.kernel.org Fixes: 521a2ad6f862 ("gpio: add userspace ABI for GPIO line information") Signed-off-by: Lars-Peter Clausen Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f0fc3a0d37c82..dac975397253d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -839,7 +839,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) return -EFAULT; - if (lineinfo.line_offset > gdev->ngpio) + if (lineinfo.line_offset >= gdev->ngpio) return -EINVAL; desc = &gdev->descs[lineinfo.line_offset]; -- GitLab From 0f4bbb233743bdfd51d47688b0bc2561f310488b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Oct 2016 16:54:00 +0200 Subject: [PATCH 0896/1167] gpio: GPIO_GET_CHIPINFO_IOCTL: Fix information leak The GPIO_GET_CHIPINFO_IOCTL handler allocates a gpiochip_info struct on the stack and then passes it to copy_to_user(). But depending on the length of the GPIO chip name and label the struct is only partially initialized. This exposes the previous, potentially sensitive, stack content to the issuing userspace application. To avoid this make sure that the struct is fully initialized. Cc: stable@vger.kernel.org Fixes: 521a2ad6f862 ("gpio: add userspace ABI for GPIO line information") Signed-off-by: Lars-Peter Clausen Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index dac975397253d..7a01969169e89 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -823,6 +823,8 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (cmd == GPIO_GET_CHIPINFO_IOCTL) { struct gpiochip_info chipinfo; + memset(&chipinfo, 0, sizeof(chipinfo)); + strncpy(chipinfo.name, dev_name(&gdev->dev), sizeof(chipinfo.name)); chipinfo.name[sizeof(chipinfo.name)-1] = '\0'; -- GitLab From e405f9fcb63602d35f7a419ededa3f952a395a72 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Oct 2016 16:54:01 +0200 Subject: [PATCH 0897/1167] gpio: GPIO_GET_LINEHANDLE_IOCTL: Validate line offset The line offset that is used as an index into the descs array is provided by userspace and might go beyond the bounds of the array. If that happens undefined behavior will occur. Make sure that the offset is within the bounds of the desc array and reject any requests that specify a value outside of it. Cc: stable@vger.kernel.org Fixes: d7c51b47ac11 ("gpio: userspace ABI for reading/writing GPIO lines") Signed-off-by: Lars-Peter Clausen Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 7a01969169e89..d287cb4e97c4b 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -444,6 +444,11 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) u32 lflags = handlereq.flags; struct gpio_desc *desc; + if (offset >= gdev->ngpio) { + ret = -EINVAL; + goto out_free_descs; + } + desc = &gdev->descs[offset]; ret = gpiod_request(desc, lh->label); if (ret) -- GitLab From d82aa4a8f2e8df9673ddb099262355da4c9b99b1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Oct 2016 16:54:04 +0200 Subject: [PATCH 0898/1167] gpio: GPIOHANDLE_GET_LINE_VALUES_IOCTL: Fix information leak The GPIOHANDLE_GET_LINE_VALUES_IOCTL handler allocates a gpiohandle_data struct on the stack and then passes it to copy_to_user(). But only the first element of the values array in the struct is set, which leaves the struct partially initialized. This exposes the previous, potentially sensitive, stack content to the issuing userspace application. To avoid this make sure that the struct is fully initialized. Cc: stable@vger.kernel.org Fixes: 61f922db7221 ("gpio: userspace ABI for reading GPIO line events") Signed-off-by: Lars-Peter Clausen Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d287cb4e97c4b..4ed26bcf054c5 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -628,6 +628,8 @@ static long lineevent_ioctl(struct file *filep, unsigned int cmd, if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { int val; + memset(&ghd, 0, sizeof(ghd)); + val = gpiod_get_value_cansleep(le->desc); if (val < 0) return val; -- GitLab From b8b0e3d303654b3bb7b31b0266c513fd6f4132ce Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Oct 2016 16:54:03 +0200 Subject: [PATCH 0899/1167] gpio: GPIO_GET_LINEEVENT_IOCTL: Validate line offset The line offset that is used as an index into the descs array is provided by userspace and might go beyond the bounds of the array. If that happens undefined behavior will occur. Make sure that the offset is within the bounds of the desc array and reject any requests that specify a value outside of it. Cc: stable@vger.kernel.org Fixes: 61f922db7221 ("gpio: userspace ABI for reading GPIO line events") Signed-off-by: Lars-Peter Clausen Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4ed26bcf054c5..db44a7da5eb44 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -733,6 +733,11 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) lflags = eventreq.handleflags; eflags = eventreq.eventflags; + if (offset >= gdev->ngpio) { + ret = -EINVAL; + goto out_free_label; + } + /* This is just wrong: we don't look for events on output lines */ if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { ret = -EINVAL; -- GitLab From 3eded5d83bf4e36ad78775c7ceb44a45480b0abd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Oct 2016 16:54:02 +0200 Subject: [PATCH 0900/1167] gpio: GPIOHANDLE_GET_LINE_VALUES_IOCTL: Fix information leak The GPIOHANDLE_GET_LINE_VALUES_IOCTL handler allocates a gpiohandle_data struct on the stack and then passes it to copy_to_user(). But depending on the number of requested line handles the struct is only partially initialized. This exposes the previous, potentially sensitive, stack content to the issuing userspace application. To avoid this make sure that the struct is fully initialized. Cc: stable@vger.kernel.org Fixes: d7c51b47ac11 ("gpio: userspace ABI for reading/writing GPIO lines") Signed-off-by: Lars-Peter Clausen Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index db44a7da5eb44..7f92f8964efdd 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -344,6 +344,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { int val; + memset(&ghd, 0, sizeof(ghd)); + /* TODO: check if descriptors are really input */ for (i = 0; i < lh->numdescs; i++) { val = gpiod_get_value_cansleep(lh->descs[i]); -- GitLab From 9799c50372b23ed774791bdb87d700f1286ee8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Thu, 6 Oct 2016 01:43:08 +0200 Subject: [PATCH 0901/1167] batman-adv: fix splat on disabling an interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As long as there is still a reference for a hard interface held, there might still be a forwarding packet relying on its attributes. Therefore avoid setting hard_iface->soft_iface to NULL when disabling a hard interface. This fixes the following, potential splat: batman_adv: bat0: Interface deactivated: eth1 batman_adv: bat0: Removing interface: eth1 cgroup: new mount options do not match the existing superblock, will be ignored batman_adv: bat0: Interface deactivated: eth3 batman_adv: bat0: Removing interface: eth3 ------------[ cut here ]------------ WARNING: CPU: 3 PID: 1986 at ./net/batman-adv/bat_iv_ogm.c:549 batadv_iv_send_outstanding_bat_ogm_packet+0x145/0x643 [batman_adv] Modules linked in: batman_adv(O-) <...> CPU: 3 PID: 1986 Comm: kworker/u8:2 Tainted: G W O 4.6.0-rc6+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140531_083030-gandalf 04/01/2014 Workqueue: bat_events batadv_iv_send_outstanding_bat_ogm_packet [batman_adv] 0000000000000000 ffff88001d93bca0 ffffffff8126c26b 0000000000000000 0000000000000000 ffff88001d93bcf0 ffffffff81051615 ffff88001f19f818 000002251d93bd68 0000000000000046 ffff88001dc04a00 ffff88001becbe48 Call Trace: [] dump_stack+0x67/0x90 [] __warn+0xc7/0xe5 [] warn_slowpath_null+0x18/0x1a [] batadv_iv_send_outstanding_bat_ogm_packet+0x145/0x643 [batman_adv] [] ? __lock_is_held+0x32/0x54 [] process_one_work+0x2a8/0x4f5 [] ? process_one_work+0x15c/0x4f5 [] worker_thread+0x1d5/0x2c0 [] ? process_scheduled_works+0x2e/0x2e [] ? process_scheduled_works+0x2e/0x2e [] kthread+0xc0/0xc8 [] ret_from_fork+0x22/0x40 [] ? __init_kthread_worker+0x55/0x55 ---[ end trace 647f9f325123dc05 ]--- What happened here is, that there was still a forw_packet (here: a BATMAN IV OGM) in the queue of eth3 with the forw_packet->if_incoming set to eth1 and the forw_packet->if_outgoing set to eth3. When eth3 is to be deactivated and removed, then this thread waits for the forw_packet queued on eth3 to finish. Because eth1 was deactivated and removed earlier and by that had forw_packet->if_incoming->soft_iface, set to NULL, the splat when trying to send/flush the OGM on eth3 occures. Fixes: c6c8fea29769 ("net: Add batman-adv meshing protocol") Signed-off-by: Linus Lüssing [sven@narfation.org: Reduced size of Oops message] Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/hard-interface.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 08ce36147c4c3..e034afbd1bb02 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -652,7 +652,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, batadv_softif_destroy_sysfs(hard_iface->soft_iface); } - hard_iface->soft_iface = NULL; batadv_hardif_put(hard_iface); out: -- GitLab From e3e847c7f15a27c80f526b2a7a8d4dd7ce0960a0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Oct 2016 16:54:05 +0200 Subject: [PATCH 0902/1167] gpio: GPIO_GET_LINEHANDLE_IOCTL: Reject invalid line flags The GPIO_GET_LINEHANDLE_IOCTL currently ignores unknown or undefined linehandle flags. From a backwards and forwards compatibility viewpoint it is highly desirable to reject unknown flags though. On one hand an application that is using newer flags and is running on an older kernel has no way to detect if the new flags were handled correctly if they are silently discarded. On the other hand an application that (accidentally) passes undefined flags will run fine on an older kernel, but may break on a newer kernel when these flags get defined. Ensure that requests that have undefined flags set are rejected with an error, rather than silently discarding the undefined flags. Cc: stable@vger.kernel.org Fixes: d7c51b47ac11 ("gpio: userspace ABI for reading/writing GPIO lines") Signed-off-by: Lars-Peter Clausen Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 7f92f8964efdd..b5b1a84259070 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -333,6 +333,13 @@ struct linehandle_state { u32 numdescs; }; +#define GPIOHANDLE_REQUEST_VALID_FLAGS \ + (GPIOHANDLE_REQUEST_INPUT | \ + GPIOHANDLE_REQUEST_OUTPUT | \ + GPIOHANDLE_REQUEST_ACTIVE_LOW | \ + GPIOHANDLE_REQUEST_OPEN_DRAIN | \ + GPIOHANDLE_REQUEST_OPEN_SOURCE) + static long linehandle_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { @@ -451,6 +458,12 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) goto out_free_descs; } + /* Return an error if a unknown flag is set */ + if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) { + ret = -EINVAL; + goto out_free_descs; + } + desc = &gdev->descs[offset]; ret = gpiod_request(desc, lh->label); if (ret) -- GitLab From ac7dbb991ee5afc0beacce3a252dcaaa249a7786 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Oct 2016 16:54:06 +0200 Subject: [PATCH 0903/1167] gpio: GPIO_GET_LINEEVENT_IOCTL: Reject invalid line and event flags The GPIO_GET_LINEEVENT_IOCTL currently ignores unknown or undefined linehandle and lineevent flags. From a backwards and forwards compatibility viewpoint it is highly desirable to reject unknown flags though. On one hand an application that is using newer flags and is running on an older kernel has no way to detect if the new flags were handled correctly if they are silently discarded. On the other hand an application that (accidentally) passes undefined flags will run fine on an older kernel, but may break on a newer kernel when these flags get defined. Ensure that requests that have undefined flags set are rejected with an error, rather than silently discarding the undefined flags. Cc: stable@vger.kernel.org Fixes: 61f922db7221 ("gpio: userspace ABI for reading GPIO line events") Signed-off-by: Lars-Peter Clausen Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b5b1a84259070..20e09b7c2de39 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -556,6 +556,10 @@ struct lineevent_state { struct mutex read_lock; }; +#define GPIOEVENT_REQUEST_VALID_FLAGS \ + (GPIOEVENT_REQUEST_RISING_EDGE | \ + GPIOEVENT_REQUEST_FALLING_EDGE) + static unsigned int lineevent_poll(struct file *filep, struct poll_table_struct *wait) { @@ -753,6 +757,13 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) goto out_free_label; } + /* Return an error if a unknown flag is set */ + if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) || + (eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS)) { + ret = -EINVAL; + goto out_free_label; + } + /* This is just wrong: we don't look for events on output lines */ if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { ret = -EINVAL; -- GitLab From 91f1551a746f62937957fa1bff4165e1b7a45337 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 18 Oct 2016 17:44:02 -0300 Subject: [PATCH 0904/1167] gpio: ts4800: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/gpio/gpio-ts4800.ko | grep alias $ After this patch: $ modinfo drivers/gpio/gpio-ts4800.ko | grep alias alias: of:N*T*Ctechnologic,ts4800-gpioC* alias: of:N*T*Ctechnologic,ts4800-gpio Signed-off-by: Javier Martinez Canillas Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ts4800.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-ts4800.c b/drivers/gpio/gpio-ts4800.c index 99256115bea55..c2a80b4cbf32c 100644 --- a/drivers/gpio/gpio-ts4800.c +++ b/drivers/gpio/gpio-ts4800.c @@ -66,6 +66,7 @@ static const struct of_device_id ts4800_gpio_of_match[] = { { .compatible = "technologic,ts4800-gpio", }, {}, }; +MODULE_DEVICE_TABLE(of, ts4800_gpio_of_match); static struct platform_driver ts4800_gpio_driver = { .driver = { -- GitLab From 6a34e0e6b49f50d2626c15ed75b76031f12bd637 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 22 Sep 2016 03:35:16 -0500 Subject: [PATCH 0905/1167] arm64: dts: Add timer erratum property for LS2080A and LS1043A Both the LS1043A and LS2080A platforms are affected by the Freescale A008585 erratum. Advertise it in their respective device trees. Signed-off-by: Scott Wood Acked-by: Marc Zyngier Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 1 + arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 220ac7057d128..97d331ec25001 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -123,6 +123,7 @@ <1 14 0xf08>, /* Physical Non-Secure PPI */ <1 11 0xf08>, /* Virtual PPI */ <1 10 0xf08>; /* Hypervisor PPI */ + fsl,erratum-a008585; }; pmu { diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi index 337da90bd7dad..7f0dc13b4087f 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi @@ -195,6 +195,7 @@ <1 14 4>, /* Physical Non-Secure PPI, active-low */ <1 11 4>, /* Virtual PPI, active-low */ <1 10 4>; /* Hypervisor PPI, active-low */ + fsl,erratum-a008585; }; pmu { -- GitLab From 126d26f66d9890a69158812a6caa248c05359daa Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 21 Oct 2016 12:56:27 +0200 Subject: [PATCH 0906/1167] USB: serial: fix potential NULL-dereference at probe Make sure we have at least one port before attempting to register a console. Currently, at least one driver binds to a "dummy" interface and requests zero ports for it. Should such an interface also lack endpoints, we get a NULL-deref during probe. Fixes: e5b1e2062e05 ("USB: serial: make minor allocation dynamic") Cc: stable # 3.11 Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index d213cf44a7e45..4a037b4a79cf3 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1078,7 +1078,8 @@ static int usb_serial_probe(struct usb_interface *interface, serial->disconnected = 0; - usb_serial_console_init(serial->port[0]->minor); + if (num_ports > 0) + usb_serial_console_init(serial->port[0]->minor); exit: module_put(type->driver.owner); return 0; -- GitLab From 02a1b8f4167eac709d269341f7c3c340984c28a6 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Fri, 21 Oct 2016 10:31:48 +0100 Subject: [PATCH 0907/1167] PCI: designware-plat: Update author email address Although I am leaving Synopsys, I would like to keep working with the linux kernel community and help in what you might find useful. For that I am sending this patch to change my contact e-mail. Signed-off-by: Joao Pinto Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-designware-plat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/host/pcie-designware-plat.c b/drivers/pci/host/pcie-designware-plat.c index 537f58a664fa2..8df6312ed3000 100644 --- a/drivers/pci/host/pcie-designware-plat.c +++ b/drivers/pci/host/pcie-designware-plat.c @@ -3,7 +3,7 @@ * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * - * Authors: Joao Pinto + * Authors: Joao Pinto * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as -- GitLab From 8651be8f14a12d24f203f283601d9b0418c389ff Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Wed, 19 Oct 2016 23:35:12 -0700 Subject: [PATCH 0908/1167] ipv6: fix a potential deadlock in do_ipv6_setsockopt() Baozeng reported this deadlock case: CPU0 CPU1 ---- ---- lock([ 165.136033] sk_lock-AF_INET6); lock([ 165.136033] rtnl_mutex); lock([ 165.136033] sk_lock-AF_INET6); lock([ 165.136033] rtnl_mutex); Similar to commit 87e9f0315952 ("ipv4: fix a potential deadlock in mcast getsockopt() path") this is due to we still have a case, ipv6_sock_mc_close(), where we acquire sk_lock before rtnl_lock. Close this deadlock with the similar solution, that is always acquire rtnl lock first. Fixes: baf606d9c9b1 ("ipv4,ipv6: grab rtnl before locking the socket") Reported-by: Baozeng Ding Tested-by: Baozeng Ding Cc: Marcelo Ricardo Leitner Signed-off-by: Cong Wang Reviewed-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- include/net/addrconf.h | 1 + net/ipv6/ipv6_sockglue.c | 3 ++- net/ipv6/mcast.c | 17 ++++++++++++----- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/net/addrconf.h b/include/net/addrconf.h index f2d0727879472..8f998afc13843 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -174,6 +174,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr); int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr); +void __ipv6_sock_mc_close(struct sock *sk); void ipv6_sock_mc_close(struct sock *sk); bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, const struct in6_addr *src_addr); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 5330262ab673c..636ec56f5f502 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -120,6 +120,7 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk, static bool setsockopt_needs_rtnl(int optname) { switch (optname) { + case IPV6_ADDRFORM: case IPV6_ADD_MEMBERSHIP: case IPV6_DROP_MEMBERSHIP: case IPV6_JOIN_ANYCAST: @@ -198,7 +199,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, } fl6_free_socklist(sk); - ipv6_sock_mc_close(sk); + __ipv6_sock_mc_close(sk); /* * Sock is moving from IPv6 to IPv4 (sk_prot), so diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 75c1fc54f1889..14a3903f1c82d 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -276,16 +276,14 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, return idev; } -void ipv6_sock_mc_close(struct sock *sk) +void __ipv6_sock_mc_close(struct sock *sk) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_mc_socklist *mc_lst; struct net *net = sock_net(sk); - if (!rcu_access_pointer(np->ipv6_mc_list)) - return; + ASSERT_RTNL(); - rtnl_lock(); while ((mc_lst = rtnl_dereference(np->ipv6_mc_list)) != NULL) { struct net_device *dev; @@ -303,8 +301,17 @@ void ipv6_sock_mc_close(struct sock *sk) atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); kfree_rcu(mc_lst, rcu); - } +} + +void ipv6_sock_mc_close(struct sock *sk) +{ + struct ipv6_pinfo *np = inet6_sk(sk); + + if (!rcu_access_pointer(np->ipv6_mc_list)) + return; + rtnl_lock(); + __ipv6_sock_mc_close(sk); rtnl_unlock(); } -- GitLab From 60e21a0ef54cd836b9eb22c7cb396989b5b11648 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 29 Sep 2016 12:37:01 +0100 Subject: [PATCH 0909/1167] arm64: KVM: Take S1 walks into account when determining S2 write faults The WnR bit in the HSR/ESR_EL2 indicates whether a data abort was generated by a read or a write instruction. For stage 2 data aborts generated by a stage 1 translation table walk (i.e. the actual page table access faults at EL2), the WnR bit therefore reports whether the instruction generating the walk was a load or a store, *not* whether the page table walker was reading or writing the entry. For page tables marked as read-only at stage 2 (e.g. due to KSM merging them with the tables from another guest), this could result in livelock, where a page table walk generated by a load instruction attempts to set the access flag in the stage 1 descriptor, but fails to trigger CoW in the host since only a read fault is reported. This patch modifies the arm64 kvm_vcpu_dabt_iswrite function to take into account stage 2 faults in stage 1 walks. Since DBM cannot be disabled at EL2 for CPUs that implement it, we assume that these faults are always causes by writes, avoiding the livelock situation at the expense of occasional, spurious CoWs. We could, in theory, do a bit better by checking the guest TCR configuration and inspecting the page table to see why the PTE faulted. However, I doubt this is measurable in practice, and the threat of livelock is real. Cc: Cc: Julien Grall Reviewed-by: Marc Zyngier Reviewed-by: Christoffer Dall Signed-off-by: Will Deacon --- arch/arm64/include/asm/kvm_emulate.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index fd9d5fd788f5f..f5ea0ba70f077 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -178,11 +178,6 @@ static inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu) return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_ISV); } -static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu) -{ - return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR); -} - static inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu) { return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SSE); @@ -203,6 +198,12 @@ static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu) return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_S1PTW); } +static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu) +{ + return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR) || + kvm_vcpu_dabt_iss1tw(vcpu); /* AF/DBM update */ +} + static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu) { return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_CM); -- GitLab From c8ea0395ff3bd5f0fd3c3aa69b383b2d1231e9fd Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 20 Oct 2016 10:17:21 +0100 Subject: [PATCH 0910/1167] arm/arm64: KVM: Map the BSS at HYP When used with a compiler that doesn't implement "asm goto" (such as the AArch64 port of GCC 4.8), jump labels generate a memory access to find out about the value of the key (instead of just patching the code). The key itself is likely to be stored in the BSS. This is perfectly fine, except that we don't map the BSS at HYP, leading to an exploding kernel at the first access. The obvious fix is simply to map the BSS there (which should have been done a long while ago, but hey...). Reported-by: Eric Auger Tested-by: Eric Auger Signed-off-by: Marc Zyngier --- arch/arm/kvm/arm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 03e9273f18765..08bb84f2ad58e 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -1312,6 +1312,13 @@ static int init_hyp_mode(void) goto out_err; } + err = create_hyp_mappings(kvm_ksym_ref(__bss_start), + kvm_ksym_ref(__bss_stop), PAGE_HYP_RO); + if (err) { + kvm_err("Cannot map bss section\n"); + goto out_err; + } + /* * Map the Hyp stack pages */ -- GitLab From a6c6ead14183ea4ec8ce7551e1f3451024b9c4db Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 19 Oct 2016 02:57:22 +0200 Subject: [PATCH 0911/1167] cpufreq: intel_pstate: Set P-state upfront in performance mode After commit a4675fbc4a7a (cpufreq: intel_pstate: Replace timers with utilization update callbacks) the cpufreq governor callbacks may not be invoked on NOHZ_FULL CPUs and, in particular, switching to the "performance" policy via sysfs may not have any effect on them. That is a problem, because it usually is desirable to squeeze the last bit of performance out of those CPUs, so work around it by setting the maximum P-state (within the limits) in intel_pstate_set_policy() upfront when the policy is CPUFREQ_POLICY_PERFORMANCE. Fixes: a4675fbc4a7a (cpufreq: intel_pstate: Replace timers with utilization update callbacks) Signed-off-by: Rafael J. Wysocki Acked-by: Srinivas Pandruvada --- drivers/cpufreq/intel_pstate.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index f535f81232584..ac7c58d20b589 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1142,10 +1142,8 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf); } -static void intel_pstate_set_min_pstate(struct cpudata *cpu) +static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) { - int pstate = cpu->pstate.min_pstate; - trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu); cpu->pstate.current_pstate = pstate; /* @@ -1157,6 +1155,20 @@ static void intel_pstate_set_min_pstate(struct cpudata *cpu) pstate_funcs.get_val(cpu, pstate)); } +static void intel_pstate_set_min_pstate(struct cpudata *cpu) +{ + intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate); +} + +static void intel_pstate_max_within_limits(struct cpudata *cpu) +{ + int min_pstate, max_pstate; + + update_turbo_state(); + intel_pstate_get_min_max(cpu, &min_pstate, &max_pstate); + intel_pstate_set_pstate(cpu, max_pstate); +} + static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) { cpu->pstate.min_pstate = pstate_funcs.get_min(); @@ -1491,7 +1503,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) pr_debug("set_policy cpuinfo.max %u policy->max %u\n", policy->cpuinfo.max_freq, policy->max); - cpu = all_cpu_data[0]; + cpu = all_cpu_data[policy->cpu]; if (cpu->pstate.max_pstate_physical > cpu->pstate.max_pstate && policy->max < policy->cpuinfo.max_freq && policy->max > cpu->pstate.max_pstate * cpu->pstate.scaling) { @@ -1535,6 +1547,15 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) limits->max_perf = round_up(limits->max_perf, FRAC_BITS); out: + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { + /* + * NOHZ_FULL CPUs need this as the governor callback may not + * be invoked on them. + */ + intel_pstate_clear_update_util_hook(policy->cpu); + intel_pstate_max_within_limits(cpu); + } + intel_pstate_set_update_util_hook(policy->cpu); intel_pstate_hwp_set_policy(policy); -- GitLab From 62623d5f918fb1c8ed86b03b9a86cc81f1cb1878 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 20 Oct 2016 13:32:55 +1100 Subject: [PATCH 0912/1167] KVM: PPC: Book3S HV: Fix build error when SMP=n Commit 5d375199ea96 ("KVM: PPC: Book3S HV: Set server for passed-through interrupts") broke the SMP=n build: arch/powerpc/kvm/book3s_hv_rm_xics.c:758:2: error: implicit declaration of function 'get_hard_smp_processor_id' That is because we lost the implicit include of asm/smp.h, so include it explicitly to get the definition for get_hard_smp_processor_id(). Fixes: 5d375199ea96 ("KVM: PPC: Book3S HV: Set server for passed-through interrupts") Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_hv_rm_xics.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c index 82ff5de8b1e7a..a0ea63ac2b521 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_xics.c +++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "book3s_xics.h" -- GitLab From 80f23935cadb1c654e81951f5a8b7ceae0acc1b4 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Thu, 6 Oct 2016 13:42:19 +0000 Subject: [PATCH 0913/1167] powerpc: Convert cmp to cmpd in idle enter sequence PowerPC's "cmp" instruction has four operands. Normally people write "cmpw" or "cmpd" for the second cmp operand 0 or 1. But, frequently people forget, and write "cmp" with just three operands. With older binutils this is silently accepted as if this was "cmpw", while often "cmpd" is wanted. With newer binutils GAS will complain about this for 64-bit code. For 32-bit code it still silently assumes "cmpw" is what is meant. In this instance the code comes directly from ISA v2.07, including the cmp, but cmpd is correct. Backport to stable so that new toolchains can build old kernels. Fixes: 948cf67c4726 ("powerpc: Add NAP mode support on Power7 in HV mode") Cc: stable@vger.kernel.org # v3.0 Reviewed-by: Vaidyanathan Srinivasan Signed-off-by: Segher Boessenkool Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/cpuidle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/cpuidle.h b/arch/powerpc/include/asm/cpuidle.h index 01b8a13f02246..3919332965af0 100644 --- a/arch/powerpc/include/asm/cpuidle.h +++ b/arch/powerpc/include/asm/cpuidle.h @@ -26,7 +26,7 @@ extern u64 pnv_first_deep_stop_state; std r0,0(r1); \ ptesync; \ ld r0,0(r1); \ -1: cmp cr0,r0,r0; \ +1: cmpd cr0,r0,r0; \ bne 1b; \ IDLE_INST; \ b . -- GitLab From f660f6066716b700148f60dba3461e65efff3123 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 10 Oct 2016 15:10:51 +0300 Subject: [PATCH 0914/1167] softirq: Display IRQ_POLL for irq-poll statistics This library was moved to the generic area and was renamed to irq-poll. Hence, update proc/softirqs output accordingly. Signed-off-by: Sagi Grimberg Reviewed-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- kernel/softirq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index 1bf81ef913755..744fa611cae06 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -58,7 +58,7 @@ static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp DEFINE_PER_CPU(struct task_struct *, ksoftirqd); const char * const softirq_to_name[NR_SOFTIRQS] = { - "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL", + "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "IRQ_POLL", "TASKLET", "SCHED", "HRTIMER", "RCU" }; -- GitLab From b4a1278c78bc939b3e29c3ad21ceaa636b0ca8c8 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Thu, 20 Oct 2016 14:40:06 -0700 Subject: [PATCH 0915/1167] badblocks: badblocks_set/clear update unacked_exist When bandblocks_set acknowledges a range or badblocks_clear a range, it's possible all badblocks are acknowledged. We should update unacked_exist if this occurs. Signed-off-by: Shaohua Li Reviewed-by: Tomasz Majchrzak Tested-by: Tomasz Majchrzak Signed-off-by: Jens Axboe --- block/badblocks.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/block/badblocks.c b/block/badblocks.c index 6610e282a03e0..6ebcef2823148 100644 --- a/block/badblocks.c +++ b/block/badblocks.c @@ -133,6 +133,26 @@ int badblocks_check(struct badblocks *bb, sector_t s, int sectors, } EXPORT_SYMBOL_GPL(badblocks_check); +static void badblocks_update_acked(struct badblocks *bb) +{ + u64 *p = bb->page; + int i; + bool unacked = false; + + if (!bb->unacked_exist) + return; + + for (i = 0; i < bb->count ; i++) { + if (!BB_ACK(p[i])) { + unacked = true; + break; + } + } + + if (!unacked) + bb->unacked_exist = 0; +} + /** * badblocks_set() - Add a range of bad blocks to the table. * @bb: the badblocks structure that holds all badblock information @@ -294,6 +314,8 @@ int badblocks_set(struct badblocks *bb, sector_t s, int sectors, bb->changed = 1; if (!acknowledged) bb->unacked_exist = 1; + else + badblocks_update_acked(bb); write_sequnlock_irqrestore(&bb->lock, flags); return rv; @@ -401,6 +423,7 @@ int badblocks_clear(struct badblocks *bb, sector_t s, int sectors) } } + badblocks_update_acked(bb); bb->changed = 1; out: write_sequnlock_irq(&bb->lock); -- GitLab From ff8560512b8d4b7ca3ef4fd69166634ac30b2525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 22 Oct 2016 05:18:04 +0300 Subject: [PATCH 0916/1167] x86/boot/smp: Don't try to poke disabled/non-existent APIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently trying to poke a disabled or non-existent APIC leads to a box that doesn't even boot. Let's not do that. No real clue if this is the right fix, but at least my P3 machine boots again. Signed-off-by: Ville Syrjälä Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Eric Biederman Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Len Brown Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Prarit Bhargava Cc: Thomas Gleixner Cc: Yinghai Lu Cc: dyoung@redhat.com Cc: kexec@lists.infradead.org Cc: stable@vger.kernel.org Fixes: 2a51fe083eba ("arch/x86: Handle non enumerated CPU after physical hotplug") Link: http://lkml.kernel.org/r/1477102684-5092-1-git-send-email-ville.syrjala@linux.intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/smpboot.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 951f093a96fe9..42f5eb7b4f6c8 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1409,15 +1409,17 @@ __init void prefill_possible_map(void) /* No boot processor was found in mptable or ACPI MADT */ if (!num_processors) { - int apicid = boot_cpu_physical_apicid; - int cpu = hard_smp_processor_id(); + if (boot_cpu_has(X86_FEATURE_APIC)) { + int apicid = boot_cpu_physical_apicid; + int cpu = hard_smp_processor_id(); - pr_warn("Boot CPU (id %d) not listed by BIOS\n", cpu); + pr_warn("Boot CPU (id %d) not listed by BIOS\n", cpu); - /* Make sure boot cpu is enumerated */ - if (apic->cpu_present_to_apicid(0) == BAD_APICID && - apic->apic_id_valid(apicid)) - generic_processor_info(apicid, boot_cpu_apic_version); + /* Make sure boot cpu is enumerated */ + if (apic->cpu_present_to_apicid(0) == BAD_APICID && + apic->apic_id_valid(apicid)) + generic_processor_info(apicid, boot_cpu_apic_version); + } if (!num_processors) num_processors = 1; -- GitLab From bcf4f311e034dc661b5e641595ef1f50af27b5bf Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 20 Sep 2016 13:43:19 +0900 Subject: [PATCH 0917/1167] ARM: uniphier: select ARCH_HAS_RESET_CONTROLLER The UniPhier reset driver (drivers/reset/reset-uniphier.c) has been merged. Select ARCH_HAS_RESET_CONTROLLER from the SoC Kconfig. Signed-off-by: Masahiro Yamada Acked-by: Philipp Zabel --- arch/arm/mach-uniphier/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-uniphier/Kconfig b/arch/arm/mach-uniphier/Kconfig index 82dddee3a469b..3930fbba30b4b 100644 --- a/arch/arm/mach-uniphier/Kconfig +++ b/arch/arm/mach-uniphier/Kconfig @@ -1,6 +1,7 @@ config ARCH_UNIPHIER bool "Socionext UniPhier SoCs" depends on ARCH_MULTI_V7 + select ARCH_HAS_RESET_CONTROLLER select ARM_AMBA select ARM_GLOBAL_TIMER select ARM_GIC -- GitLab From 75924903c51d0697b989035f6baebccb2a7367cd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 8 Oct 2016 11:25:34 +0900 Subject: [PATCH 0918/1167] arm64: uniphier: select ARCH_HAS_RESET_CONTROLLER The UniPhier reset driver (drivers/reset/reset-uniphier.c) has been merged. Select ARCH_HAS_RESET_CONTROLLER from the SoC Kconfig. Signed-off-by: Masahiro Yamada --- arch/arm64/Kconfig.platforms | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index cfbdf02ef5667..101794f5ce100 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -190,6 +190,7 @@ config ARCH_THUNDER config ARCH_UNIPHIER bool "Socionext UniPhier SoC Family" + select ARCH_HAS_RESET_CONTROLLER select PINCTRL help This enables support for Socionext UniPhier SoC family. -- GitLab From 19eb4a47224da4bc118f1e304e16b6c08ed172c9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 19 Oct 2016 17:23:49 +0900 Subject: [PATCH 0919/1167] reset: uniphier: rename MIO reset to SD reset for Pro5, PXs2, LD20 SoCs I made a mistake as for naming for this block. The MIO block is not implemented for these 3 SoCs in the first place. The current naming will be a trouble if an SoC with both MIO and SD-ctrl blocks appear in the future. This driver has just been merged in the previous merge window. Rename it before the release. Signed-off-by: Masahiro Yamada Acked-by: Philipp Zabel --- .../bindings/reset/uniphier-reset.txt | 62 +++++++++---------- drivers/reset/reset-uniphier.c | 16 ++--- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Documentation/devicetree/bindings/reset/uniphier-reset.txt b/Documentation/devicetree/bindings/reset/uniphier-reset.txt index e6bbfccd56c32..5020524cddebf 100644 --- a/Documentation/devicetree/bindings/reset/uniphier-reset.txt +++ b/Documentation/devicetree/bindings/reset/uniphier-reset.txt @@ -6,25 +6,25 @@ System reset Required properties: - compatible: should be one of the following: - "socionext,uniphier-sld3-reset" - for PH1-sLD3 SoC. - "socionext,uniphier-ld4-reset" - for PH1-LD4 SoC. - "socionext,uniphier-pro4-reset" - for PH1-Pro4 SoC. - "socionext,uniphier-sld8-reset" - for PH1-sLD8 SoC. - "socionext,uniphier-pro5-reset" - for PH1-Pro5 SoC. - "socionext,uniphier-pxs2-reset" - for ProXstream2/PH1-LD6b SoC. - "socionext,uniphier-ld11-reset" - for PH1-LD11 SoC. - "socionext,uniphier-ld20-reset" - for PH1-LD20 SoC. + "socionext,uniphier-sld3-reset" - for sLD3 SoC. + "socionext,uniphier-ld4-reset" - for LD4 SoC. + "socionext,uniphier-pro4-reset" - for Pro4 SoC. + "socionext,uniphier-sld8-reset" - for sLD8 SoC. + "socionext,uniphier-pro5-reset" - for Pro5 SoC. + "socionext,uniphier-pxs2-reset" - for PXs2/LD6b SoC. + "socionext,uniphier-ld11-reset" - for LD11 SoC. + "socionext,uniphier-ld20-reset" - for LD20 SoC. - #reset-cells: should be 1. Example: sysctrl@61840000 { - compatible = "socionext,uniphier-ld20-sysctrl", + compatible = "socionext,uniphier-ld11-sysctrl", "simple-mfd", "syscon"; reg = <0x61840000 0x4000>; reset { - compatible = "socionext,uniphier-ld20-reset"; + compatible = "socionext,uniphier-ld11-reset"; #reset-cells = <1>; }; @@ -32,30 +32,30 @@ Example: }; -Media I/O (MIO) reset ---------------------- +Media I/O (MIO) reset, SD reset +------------------------------- Required properties: - compatible: should be one of the following: - "socionext,uniphier-sld3-mio-reset" - for PH1-sLD3 SoC. - "socionext,uniphier-ld4-mio-reset" - for PH1-LD4 SoC. - "socionext,uniphier-pro4-mio-reset" - for PH1-Pro4 SoC. - "socionext,uniphier-sld8-mio-reset" - for PH1-sLD8 SoC. - "socionext,uniphier-pro5-mio-reset" - for PH1-Pro5 SoC. - "socionext,uniphier-pxs2-mio-reset" - for ProXstream2/PH1-LD6b SoC. - "socionext,uniphier-ld11-mio-reset" - for PH1-LD11 SoC. - "socionext,uniphier-ld20-mio-reset" - for PH1-LD20 SoC. + "socionext,uniphier-sld3-mio-reset" - for sLD3 SoC. + "socionext,uniphier-ld4-mio-reset" - for LD4 SoC. + "socionext,uniphier-pro4-mio-reset" - for Pro4 SoC. + "socionext,uniphier-sld8-mio-reset" - for sLD8 SoC. + "socionext,uniphier-pro5-sd-reset" - for Pro5 SoC. + "socionext,uniphier-pxs2-sd-reset" - for PXs2/LD6b SoC. + "socionext,uniphier-ld11-mio-reset" - for LD11 SoC. + "socionext,uniphier-ld20-sd-reset" - for LD20 SoC. - #reset-cells: should be 1. Example: mioctrl@59810000 { - compatible = "socionext,uniphier-ld20-mioctrl", + compatible = "socionext,uniphier-ld11-mioctrl", "simple-mfd", "syscon"; reg = <0x59810000 0x800>; reset { - compatible = "socionext,uniphier-ld20-mio-reset"; + compatible = "socionext,uniphier-ld11-mio-reset"; #reset-cells = <1>; }; @@ -68,24 +68,24 @@ Peripheral reset Required properties: - compatible: should be one of the following: - "socionext,uniphier-ld4-peri-reset" - for PH1-LD4 SoC. - "socionext,uniphier-pro4-peri-reset" - for PH1-Pro4 SoC. - "socionext,uniphier-sld8-peri-reset" - for PH1-sLD8 SoC. - "socionext,uniphier-pro5-peri-reset" - for PH1-Pro5 SoC. - "socionext,uniphier-pxs2-peri-reset" - for ProXstream2/PH1-LD6b SoC. - "socionext,uniphier-ld11-peri-reset" - for PH1-LD11 SoC. - "socionext,uniphier-ld20-peri-reset" - for PH1-LD20 SoC. + "socionext,uniphier-ld4-peri-reset" - for LD4 SoC. + "socionext,uniphier-pro4-peri-reset" - for Pro4 SoC. + "socionext,uniphier-sld8-peri-reset" - for sLD8 SoC. + "socionext,uniphier-pro5-peri-reset" - for Pro5 SoC. + "socionext,uniphier-pxs2-peri-reset" - for PXs2/LD6b SoC. + "socionext,uniphier-ld11-peri-reset" - for LD11 SoC. + "socionext,uniphier-ld20-peri-reset" - for LD20 SoC. - #reset-cells: should be 1. Example: perictrl@59820000 { - compatible = "socionext,uniphier-ld20-perictrl", + compatible = "socionext,uniphier-ld11-perictrl", "simple-mfd", "syscon"; reg = <0x59820000 0x200>; reset { - compatible = "socionext,uniphier-ld20-peri-reset"; + compatible = "socionext,uniphier-ld11-peri-reset"; #reset-cells = <1>; }; diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index 8b2558e7363e2..968c3ae4535cf 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -154,7 +154,7 @@ const struct uniphier_reset_data uniphier_sld3_mio_reset_data[] = { UNIPHIER_RESET_END, }; -const struct uniphier_reset_data uniphier_pro5_mio_reset_data[] = { +const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = { UNIPHIER_MIO_RESET_SD(0, 0), UNIPHIER_MIO_RESET_SD(1, 1), UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1), @@ -360,7 +360,7 @@ static const struct of_device_id uniphier_reset_match[] = { .compatible = "socionext,uniphier-ld20-reset", .data = uniphier_ld20_sys_reset_data, }, - /* Media I/O reset */ + /* Media I/O reset, SD reset */ { .compatible = "socionext,uniphier-sld3-mio-reset", .data = uniphier_sld3_mio_reset_data, @@ -378,20 +378,20 @@ static const struct of_device_id uniphier_reset_match[] = { .data = uniphier_sld3_mio_reset_data, }, { - .compatible = "socionext,uniphier-pro5-mio-reset", - .data = uniphier_pro5_mio_reset_data, + .compatible = "socionext,uniphier-pro5-sd-reset", + .data = uniphier_pro5_sd_reset_data, }, { - .compatible = "socionext,uniphier-pxs2-mio-reset", - .data = uniphier_pro5_mio_reset_data, + .compatible = "socionext,uniphier-pxs2-sd-reset", + .data = uniphier_pro5_sd_reset_data, }, { .compatible = "socionext,uniphier-ld11-mio-reset", .data = uniphier_sld3_mio_reset_data, }, { - .compatible = "socionext,uniphier-ld20-mio-reset", - .data = uniphier_pro5_mio_reset_data, + .compatible = "socionext,uniphier-ld20-sd-reset", + .data = uniphier_pro5_sd_reset_data, }, /* Peripheral reset */ { -- GitLab From 1bdb60ef18655596d56b9b7268ad0bf5214e00e4 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 21 Oct 2016 17:27:57 +0900 Subject: [PATCH 0920/1167] ARM: dts: uniphier: change MIO node to SD control node I made a mistake bacuse the Media I/O block is not implemented in these SoCs. Signed-off-by: Masahiro Yamada --- arch/arm/boot/dts/uniphier-pro5.dtsi | 4 ++-- arch/arm/boot/dts/uniphier-pxs2.dtsi | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/uniphier-pro5.dtsi b/arch/arm/boot/dts/uniphier-pro5.dtsi index 2c49c3614bda5..5357ea9c14b1e 100644 --- a/arch/arm/boot/dts/uniphier-pro5.dtsi +++ b/arch/arm/boot/dts/uniphier-pro5.dtsi @@ -184,11 +184,11 @@ }; &mio_clk { - compatible = "socionext,uniphier-pro5-mio-clock"; + compatible = "socionext,uniphier-pro5-sd-clock"; }; &mio_rst { - compatible = "socionext,uniphier-pro5-mio-reset"; + compatible = "socionext,uniphier-pro5-sd-reset"; }; &peri_clk { diff --git a/arch/arm/boot/dts/uniphier-pxs2.dtsi b/arch/arm/boot/dts/uniphier-pxs2.dtsi index 8789cd518933d..950f07ba03371 100644 --- a/arch/arm/boot/dts/uniphier-pxs2.dtsi +++ b/arch/arm/boot/dts/uniphier-pxs2.dtsi @@ -197,11 +197,11 @@ }; &mio_clk { - compatible = "socionext,uniphier-pxs2-mio-clock"; + compatible = "socionext,uniphier-pxs2-sd-clock"; }; &mio_rst { - compatible = "socionext,uniphier-pxs2-mio-reset"; + compatible = "socionext,uniphier-pxs2-sd-reset"; }; &peri_clk { -- GitLab From 8e68c65d111a57a4cbe41dc886bb2a1e671e0b6e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 21 Oct 2016 16:45:21 +0900 Subject: [PATCH 0921/1167] arm64: dts: uniphier: change MIO node to SD control node I made a mistake bacuse the Media I/O block is not implemented in this SoC. Signed-off-by: Masahiro Yamada --- arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi index 08fd7cf7769cf..56a1b2e92cf32 100644 --- a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi +++ b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi @@ -257,18 +257,18 @@ reg = <0x59801000 0x400>; }; - mioctrl@59810000 { - compatible = "socionext,uniphier-mioctrl", + sdctrl@59810000 { + compatible = "socionext,uniphier-ld20-sdctrl", "simple-mfd", "syscon"; reg = <0x59810000 0x800>; - mio_clk: clock { - compatible = "socionext,uniphier-ld20-mio-clock"; + sd_clk: clock { + compatible = "socionext,uniphier-ld20-sd-clock"; #clock-cells = <1>; }; - mio_rst: reset { - compatible = "socionext,uniphier-ld20-mio-reset"; + sd_rst: reset { + compatible = "socionext,uniphier-ld20-sd-reset"; #reset-cells = <1>; }; }; -- GitLab From 2a73306b6096fafd5c2ae06ded1f92bbacb39df2 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 21 Oct 2016 21:49:14 -0400 Subject: [PATCH 0922/1167] netns: revert "netns: avoid disabling irq for netns id" This reverts commit bc51dddf98c9 ("netns: avoid disabling irq for netns id") as it was found to cause problems with systems running SELinux/audit, see the mailing list thread below: * http://marc.info/?t=147694653900002&r=1&w=2 Eventually we should be able to reintroduce this code once we have rewritten the audit multicast code to queue messages much the same way we do for unicast messages. A tracking issue for this can be found below: * https://github.com/linux-audit/audit-kernel/issues/23 Reported-by: Stephen Smalley Reported-by: Elad Raz Cc: Cong Wang Signed-off-by: Paul Moore Signed-off-by: David S. Miller --- net/core/net_namespace.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 989434f36f963..f61c0e02a4130 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -215,13 +215,14 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id); */ int peernet2id_alloc(struct net *net, struct net *peer) { + unsigned long flags; bool alloc; int id; - spin_lock_bh(&net->nsid_lock); + spin_lock_irqsave(&net->nsid_lock, flags); alloc = atomic_read(&peer->count) == 0 ? false : true; id = __peernet2id_alloc(net, peer, &alloc); - spin_unlock_bh(&net->nsid_lock); + spin_unlock_irqrestore(&net->nsid_lock, flags); if (alloc && id >= 0) rtnl_net_notifyid(net, RTM_NEWNSID, id); return id; @@ -230,11 +231,12 @@ int peernet2id_alloc(struct net *net, struct net *peer) /* This function returns, if assigned, the id of a peer netns. */ int peernet2id(struct net *net, struct net *peer) { + unsigned long flags; int id; - spin_lock_bh(&net->nsid_lock); + spin_lock_irqsave(&net->nsid_lock, flags); id = __peernet2id(net, peer); - spin_unlock_bh(&net->nsid_lock); + spin_unlock_irqrestore(&net->nsid_lock, flags); return id; } EXPORT_SYMBOL(peernet2id); @@ -249,17 +251,18 @@ bool peernet_has_id(struct net *net, struct net *peer) struct net *get_net_ns_by_id(struct net *net, int id) { + unsigned long flags; struct net *peer; if (id < 0) return NULL; rcu_read_lock(); - spin_lock_bh(&net->nsid_lock); + spin_lock_irqsave(&net->nsid_lock, flags); peer = idr_find(&net->netns_ids, id); if (peer) get_net(peer); - spin_unlock_bh(&net->nsid_lock); + spin_unlock_irqrestore(&net->nsid_lock, flags); rcu_read_unlock(); return peer; @@ -422,17 +425,17 @@ static void cleanup_net(struct work_struct *work) for_each_net(tmp) { int id; - spin_lock_bh(&tmp->nsid_lock); + spin_lock_irq(&tmp->nsid_lock); id = __peernet2id(tmp, net); if (id >= 0) idr_remove(&tmp->netns_ids, id); - spin_unlock_bh(&tmp->nsid_lock); + spin_unlock_irq(&tmp->nsid_lock); if (id >= 0) rtnl_net_notifyid(tmp, RTM_DELNSID, id); } - spin_lock_bh(&net->nsid_lock); + spin_lock_irq(&net->nsid_lock); idr_destroy(&net->netns_ids); - spin_unlock_bh(&net->nsid_lock); + spin_unlock_irq(&net->nsid_lock); } rtnl_unlock(); @@ -561,6 +564,7 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh) { struct net *net = sock_net(skb->sk); struct nlattr *tb[NETNSA_MAX + 1]; + unsigned long flags; struct net *peer; int nsid, err; @@ -581,15 +585,15 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh) if (IS_ERR(peer)) return PTR_ERR(peer); - spin_lock_bh(&net->nsid_lock); + spin_lock_irqsave(&net->nsid_lock, flags); if (__peernet2id(net, peer) >= 0) { - spin_unlock_bh(&net->nsid_lock); + spin_unlock_irqrestore(&net->nsid_lock, flags); err = -EEXIST; goto out; } err = alloc_netid(net, peer, nsid); - spin_unlock_bh(&net->nsid_lock); + spin_unlock_irqrestore(&net->nsid_lock, flags); if (err >= 0) { rtnl_net_notifyid(net, RTM_NEWNSID, err); err = 0; @@ -711,10 +715,11 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) .idx = 0, .s_idx = cb->args[0], }; + unsigned long flags; - spin_lock_bh(&net->nsid_lock); + spin_lock_irqsave(&net->nsid_lock, flags); idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb); - spin_unlock_bh(&net->nsid_lock); + spin_unlock_irqrestore(&net->nsid_lock, flags); cb->args[0] = net_cb.idx; return skb->len; -- GitLab From 0ce66d4f70d3bcfb67c89f473e76e7cf0a01288f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 21 Oct 2016 14:21:55 -0700 Subject: [PATCH 0923/1167] Revert "kexec: Export kexec_in_progress to modules" This reverts commit 97dcaa0fcfd24daa9a36c212c1ad1d5a97759212. Based on the review discussion with Eric, we will come up with a different fix for the bcm_sf2 driver which does not make it rely on the kexec_in_progress value. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- kernel/kexec_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index 786ab85a54524..5616755895119 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -59,7 +59,6 @@ size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data); /* Flag to indicate we are going to kexec a new kernel */ bool kexec_in_progress = false; -EXPORT_SYMBOL_GPL(kexec_in_progress); /* Location of the reserved area for the crash kernel */ -- GitLab From 4a2947e32ea9ca2bc36d68022b7d7b1014dca18f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 21 Oct 2016 14:21:56 -0700 Subject: [PATCH 0924/1167] net: dsa: bcm_sf2: Do not rely on kexec_in_progress After discussing with Eric, it turns out that, while using kexec_in_progress is a nice optimization, which prevents us from always powering on the integrated PHY, let's just turn it on in the shutdown path. This removes a dependency on kexec_in_progress which, according to Eric should not be used by modules Fixes: 2399d6143f85 ("net: dsa: bcm_sf2: Prevent GPHY shutdown for kexec'd kernels") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 077a24541584e..e3ee27ce13dd3 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "bcm_sf2.h" #include "bcm_sf2_regs.h" @@ -1141,9 +1140,11 @@ static void bcm_sf2_sw_shutdown(struct platform_device *pdev) /* For a kernel about to be kexec'd we want to keep the GPHY on for a * successful MDIO bus scan to occur. If we did turn off the GPHY * before (e.g: port_disable), this will also power it back on. + * + * Do not rely on kexec_in_progress, just power the PHY on. */ if (priv->hw_params.num_gphy == 1) - bcm_sf2_gphy_enable_set(priv->dev->ds, kexec_in_progress); + bcm_sf2_gphy_enable_set(priv->dev->ds, true); } #ifdef CONFIG_PM_SLEEP -- GitLab From 396a30cce15d084b2b1a395aa6d515c3d559c674 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Thu, 20 Oct 2016 14:19:46 -0700 Subject: [PATCH 0925/1167] ipv4: use the right lock for ping_group_range This reverts commit a681574c99be23e4d20b769bf0e543239c364af5 ("ipv4: disable BH in set_ping_group_range()") because we never read ping_group_range in BH context (unlike local_port_range). Then, since we already have a lock for ping_group_range, those using ip_local_ports.lock for ping_group_range are clearly typos. We might consider to share a same lock for both ping_group_range and local_port_range w.r.t. space saving, but that should be for net-next. Fixes: a681574c99be ("ipv4: disable BH in set_ping_group_range()") Fixes: ba6b918ab234 ("ping: move ping_group_range out of CONFIG_SYSCTL") Cc: Eric Dumazet Cc: Eric Salo Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/ipv4/sysctl_net_ipv4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 500ae4010bed3..80bc36b25de21 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -96,11 +96,11 @@ static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low container_of(table->data, struct net, ipv4.ping_group_range.range); unsigned int seq; do { - seq = read_seqbegin(&net->ipv4.ip_local_ports.lock); + seq = read_seqbegin(&net->ipv4.ping_group_range.lock); *low = data[0]; *high = data[1]; - } while (read_seqretry(&net->ipv4.ip_local_ports.lock, seq)); + } while (read_seqretry(&net->ipv4.ping_group_range.lock, seq)); } /* Update system visible IP port range */ @@ -109,10 +109,10 @@ static void set_ping_group_range(struct ctl_table *table, kgid_t low, kgid_t hig kgid_t *data = table->data; struct net *net = container_of(table->data, struct net, ipv4.ping_group_range.range); - write_seqlock_bh(&net->ipv4.ip_local_ports.lock); + write_seqlock(&net->ipv4.ping_group_range.lock); data[0] = low; data[1] = high; - write_sequnlock_bh(&net->ipv4.ip_local_ports.lock); + write_sequnlock(&net->ipv4.ping_group_range.lock); } /* Validate changes from /proc interface. */ -- GitLab From bdc8cbd34d5d9d82c3db4df6a182b0530040062d Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Fri, 21 Oct 2016 04:43:39 -0400 Subject: [PATCH 0926/1167] qede: get_channels() need to populate max tx/rx coalesce values Recent changes in kernel ethtool implementation requires the driver callback for get_channels() has to populate the values for max tx/rx coalesce fields. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 25a9b293ee8f8..16a1a478a2bdb 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -756,6 +756,8 @@ static void qede_get_channels(struct net_device *dev, struct qede_dev *edev = netdev_priv(dev); channels->max_combined = QEDE_MAX_RSS_CNT(edev); + channels->max_rx = QEDE_MAX_RSS_CNT(edev); + channels->max_tx = QEDE_MAX_RSS_CNT(edev); channels->combined_count = QEDE_QUEUE_CNT(edev) - edev->fp_num_tx - edev->fp_num_rx; channels->tx_count = edev->fp_num_tx; -- GitLab From ba300ce35123a9ba8ea55318b0f579cc1ab3f51a Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Fri, 21 Oct 2016 04:43:40 -0400 Subject: [PATCH 0927/1167] qede: Do not allow RSS config for 100G devices RSS configuration is not supported for 100G adapters. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 16a1a478a2bdb..bf04fb9e1ae64 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -1055,6 +1055,12 @@ static int qede_set_rxfh(struct net_device *dev, const u32 *indir, struct qede_dev *edev = netdev_priv(dev); int i; + if (edev->dev_info.common.num_hwfns > 1) { + DP_INFO(edev, + "RSS configuration is not supported for 100G devices\n"); + return -EOPNOTSUPP; + } + if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; -- GitLab From 837d4eb6ed7cb0341079fac97e3037df6bef7482 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Fri, 21 Oct 2016 04:43:41 -0400 Subject: [PATCH 0928/1167] qede: Loopback implementation should ignore the normal traffic During the execution of loopback test, driver may receive the packets which are not originated by this test, loopback implementation need to skip those packets. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede.h | 1 + .../net/ethernet/qlogic/qede/qede_ethtool.c | 80 +++++++++++-------- drivers/net/ethernet/qlogic/qede/qede_main.c | 3 +- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index 28c0e9f42c9e7..d6a4a9a5eb4dc 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -348,6 +348,7 @@ bool qede_has_rx_work(struct qede_rx_queue *rxq); int qede_txq_has_work(struct qede_tx_queue *txq); void qede_recycle_rx_bd_ring(struct qede_rx_queue *rxq, struct qede_dev *edev, u8 count); +void qede_update_rx_prod(struct qede_dev *edev, struct qede_rx_queue *rxq); #define RX_RING_SIZE_POW 13 #define RX_RING_SIZE ((u16)BIT(RX_RING_SIZE_POW)) diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index bf04fb9e1ae64..7da184cfe72e0 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -1207,8 +1207,8 @@ static int qede_selftest_receive_traffic(struct qede_dev *edev) struct qede_rx_queue *rxq = NULL; struct sw_rx_data *sw_rx_data; union eth_rx_cqe *cqe; + int i, rc = 0; u8 *data_ptr; - int i; for_each_queue(i) { if (edev->fp_array[i].type & QEDE_FASTPATH_RX) { @@ -1227,46 +1227,60 @@ static int qede_selftest_receive_traffic(struct qede_dev *edev) * queue and that the loopback traffic is not IP. */ for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) { - if (qede_has_rx_work(rxq)) + if (!qede_has_rx_work(rxq)) { + usleep_range(100, 200); + continue; + } + + hw_comp_cons = le16_to_cpu(*rxq->hw_cons_ptr); + sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring); + + /* Memory barrier to prevent the CPU from doing speculative + * reads of CQE/BD before reading hw_comp_cons. If the CQE is + * read before it is written by FW, then FW writes CQE and SB, + * and then the CPU reads the hw_comp_cons, it will use an old + * CQE. + */ + rmb(); + + /* Get the CQE from the completion ring */ + cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring); + + /* Get the data from the SW ring */ + sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX; + sw_rx_data = &rxq->sw_rx_ring[sw_rx_index]; + fp_cqe = &cqe->fast_path_regular; + len = le16_to_cpu(fp_cqe->len_on_first_bd); + data_ptr = (u8 *)(page_address(sw_rx_data->data) + + fp_cqe->placement_offset + + sw_rx_data->page_offset); + if (ether_addr_equal(data_ptr, edev->ndev->dev_addr) && + ether_addr_equal(data_ptr + ETH_ALEN, + edev->ndev->dev_addr)) { + for (i = ETH_HLEN; i < len; i++) + if (data_ptr[i] != (unsigned char)(i & 0xff)) { + rc = -1; + break; + } + + qede_recycle_rx_bd_ring(rxq, edev, 1); + qed_chain_recycle_consumed(&rxq->rx_comp_ring); break; - usleep_range(100, 200); + } + + DP_INFO(edev, "Not the transmitted packet\n"); + qede_recycle_rx_bd_ring(rxq, edev, 1); + qed_chain_recycle_consumed(&rxq->rx_comp_ring); } - if (!qede_has_rx_work(rxq)) { + if (i == QEDE_SELFTEST_POLL_COUNT) { DP_NOTICE(edev, "Failed to receive the traffic\n"); return -1; } - hw_comp_cons = le16_to_cpu(*rxq->hw_cons_ptr); - sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring); - - /* Memory barrier to prevent the CPU from doing speculative reads of CQE - * / BD before reading hw_comp_cons. If the CQE is read before it is - * written by FW, then FW writes CQE and SB, and then the CPU reads the - * hw_comp_cons, it will use an old CQE. - */ - rmb(); - - /* Get the CQE from the completion ring */ - cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring); - - /* Get the data from the SW ring */ - sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX; - sw_rx_data = &rxq->sw_rx_ring[sw_rx_index]; - fp_cqe = &cqe->fast_path_regular; - len = le16_to_cpu(fp_cqe->len_on_first_bd); - data_ptr = (u8 *)(page_address(sw_rx_data->data) + - fp_cqe->placement_offset + sw_rx_data->page_offset); - for (i = ETH_HLEN; i < len; i++) - if (data_ptr[i] != (unsigned char)(i & 0xff)) { - DP_NOTICE(edev, "Loopback test failed\n"); - qede_recycle_rx_bd_ring(rxq, edev, 1); - return -1; - } - - qede_recycle_rx_bd_ring(rxq, edev, 1); + qede_update_rx_prod(edev, rxq); - return 0; + return rc; } static int qede_selftest_run_loopback(struct qede_dev *edev, u32 loopback_mode) diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 343038ca047d7..da8ef69cedd61 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -943,8 +943,7 @@ static inline int qede_realloc_rx_buffer(struct qede_dev *edev, return 0; } -static inline void qede_update_rx_prod(struct qede_dev *edev, - struct qede_rx_queue *rxq) +void qede_update_rx_prod(struct qede_dev *edev, struct qede_rx_queue *rxq) { u16 bd_prod = qed_chain_get_prod_idx(&rxq->rx_bd_ring); u16 cqe_prod = qed_chain_get_prod_idx(&rxq->rx_comp_ring); -- GitLab From 0e191827383a6503a3bc547e63c74ff093f450f5 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Fri, 21 Oct 2016 04:43:42 -0400 Subject: [PATCH 0929/1167] qed*: Reduce the memory footprint for Rx path With the current default values for Rx path i.e., 8 queues of 8Kb entries each with 4Kb size, interface will consume 256Mb for Rx. The default values causing the driver probe to fail when the system memory is low. Based on the perforamnce results, rx-ring count value of 1Kb gives the comparable performance with Rx coalesce timeout of 12 seconds. Updating the default values. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_main.c | 1 + drivers/net/ethernet/qlogic/qede/qede.h | 2 +- include/linux/qed/qed_if.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 8dc3f4670f640..c418360ba02af 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -878,6 +878,7 @@ static int qed_slowpath_start(struct qed_dev *cdev, } } + cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS; rc = qed_nic_setup(cdev); if (rc) goto err; diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index d6a4a9a5eb4dc..974689a133372 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -354,7 +354,7 @@ void qede_update_rx_prod(struct qede_dev *edev, struct qede_rx_queue *rxq); #define RX_RING_SIZE ((u16)BIT(RX_RING_SIZE_POW)) #define NUM_RX_BDS_MAX (RX_RING_SIZE - 1) #define NUM_RX_BDS_MIN 128 -#define NUM_RX_BDS_DEF NUM_RX_BDS_MAX +#define NUM_RX_BDS_DEF ((u16)BIT(10) - 1) #define TX_RING_SIZE_POW 13 #define TX_RING_SIZE ((u16)BIT(TX_RING_SIZE_POW)) diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h index f9ae903bbb844..8978a60371f43 100644 --- a/include/linux/qed/qed_if.h +++ b/include/linux/qed/qed_if.h @@ -146,6 +146,7 @@ enum qed_led_mode { #define DIRECT_REG_RD(reg_addr) readl((void __iomem *)(reg_addr)) #define QED_COALESCE_MAX 0xFF +#define QED_DEFAULT_RX_USECS 12 /* forward */ struct qed_dev; -- GitLab From ed0dd91515bbe19a19cfccca366cf163ed581cac Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Fri, 21 Oct 2016 04:43:43 -0400 Subject: [PATCH 0930/1167] qede: Reconfigure rss indirection direction table when rss count is updated Rx indirection table entries are in the range [0, (rss_count - 1)]. If user reduces the rss count, the table entries may not be in the ccorrect range. Need to reconfigure the table with new rss_count as a basis. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 7da184cfe72e0..d47bdaa1f9a86 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -822,6 +822,13 @@ static int qede_set_channels(struct net_device *dev, edev->req_queues = count; edev->req_num_tx = channels->tx_count; edev->req_num_rx = channels->rx_count; + /* Reset the indirection table if rx queue count is updated */ + if ((edev->req_queues - edev->req_num_tx) != QEDE_RSS_COUNT(edev)) { + edev->rss_params_inited &= ~QEDE_RSS_INDIR_INITED; + memset(&edev->rss_params.rss_ind_table, 0, + sizeof(edev->rss_params.rss_ind_table)); + } + if (netif_running(dev)) qede_reload(edev, NULL, NULL); -- GitLab From 15c6de2c65048d45484e396194ba2598618d4cb4 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Fri, 21 Oct 2016 04:43:44 -0400 Subject: [PATCH 0931/1167] qed: Zero-out the buffer paased to dcbx_query() API qed_dcbx_query_params() implementation populate the values to input buffer based on the dcbx mode and, the current negotiated state/params, the caller of this API need to memset the buffer to zero. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index 130da1c0490be..a4789a93b6926 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -1190,6 +1190,7 @@ int qed_dcbx_get_config_params(struct qed_hwfn *p_hwfn, if (!dcbx_info) return -ENOMEM; + memset(dcbx_info, 0, sizeof(*dcbx_info)); rc = qed_dcbx_query_params(p_hwfn, dcbx_info, QED_DCBX_OPERATIONAL_MIB); if (rc) { kfree(dcbx_info); @@ -1225,6 +1226,7 @@ static struct qed_dcbx_get *qed_dcbnl_get_dcbx(struct qed_hwfn *hwfn, if (!dcbx_info) return NULL; + memset(dcbx_info, 0, sizeof(*dcbx_info)); if (qed_dcbx_query_params(hwfn, dcbx_info, type)) { kfree(dcbx_info); return NULL; -- GitLab From fabd545c6d27ac1977fe567c43cd4c72fad04172 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Fri, 21 Oct 2016 04:43:45 -0400 Subject: [PATCH 0932/1167] qede: Fix incorrrect usage of APIs for un-mapping DMA memory Driver uses incorrect APIs to unmap DMA memory which were mapped using dma_map_single(). This patch fixes it to use appropriate APIs for un-mapping DMA memory. Signed-off-by: Manish Chopra Signed-off-by: Yuval Mintz Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 4 ++-- drivers/net/ethernet/qlogic/qede/qede_main.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index d47bdaa1f9a86..12251a1032d19 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -1199,8 +1199,8 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, } first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl); - dma_unmap_page(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), - BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE); + dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), + BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE); txq->sw_tx_cons++; txq->sw_tx_ring[idx].skb = NULL; diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index da8ef69cedd61..444b271059b22 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -313,8 +313,8 @@ static int qede_free_tx_pkt(struct qede_dev *edev, split_bd_len = BD_UNMAP_LEN(split); bds_consumed++; } - dma_unmap_page(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), - BD_UNMAP_LEN(first_bd) + split_bd_len, DMA_TO_DEVICE); + dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), + BD_UNMAP_LEN(first_bd) + split_bd_len, DMA_TO_DEVICE); /* Unmap the data of the skb frags */ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, bds_consumed++) { @@ -359,8 +359,8 @@ static void qede_free_failed_tx_pkt(struct qede_dev *edev, nbd--; } - dma_unmap_page(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), - BD_UNMAP_LEN(first_bd) + split_bd_len, DMA_TO_DEVICE); + dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), + BD_UNMAP_LEN(first_bd) + split_bd_len, DMA_TO_DEVICE); /* Unmap the data of the skb frags */ for (i = 0; i < nbd; i++) { -- GitLab From d1fe85ec7702917f2f1515b4c421d5d4792201a0 Mon Sep 17 00:00:00 2001 From: Sandhya Bankar Date: Sun, 25 Sep 2016 00:46:21 +0530 Subject: [PATCH 0933/1167] iio:chemical:atlas-ph-sensor: Fix use of 32 bit int to hold 16 bit big endian value This will result in a random value being reported on big endian architectures. (thanks to Lars-Peter Clausen for pointing out the effects of this bug) Only effects a value printed to the log, but as this reports the settings of the probe in question it may be of direct interest to users. Also, fixes the following sparse endianness warnings: drivers/iio/chemical/atlas-ph-sensor.c:215:9: warning: cast to restricted __be16 drivers/iio/chemical/atlas-ph-sensor.c:215:9: warning: cast to restricted __be16 drivers/iio/chemical/atlas-ph-sensor.c:215:9: warning: cast to restricted __be16 drivers/iio/chemical/atlas-ph-sensor.c:215:9: warning: cast to restricted __be16 drivers/iio/chemical/atlas-ph-sensor.c:215:9: warning: cast to restricted __be16 drivers/iio/chemical/atlas-ph-sensor.c:215:9: warning: cast to restricted __be16 drivers/iio/chemical/atlas-ph-sensor.c:215:9: warning: cast to restricted __be16 drivers/iio/chemical/atlas-ph-sensor.c:215:9: warning: cast to restricted __be16 Signed-off-by: Sandhya Bankar Fixes: e8dd92bfbff25 ("iio: chemical: atlas-ph-sensor: add EC feature") Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/atlas-ph-sensor.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c index bd321b305a0a0..ef761a5086304 100644 --- a/drivers/iio/chemical/atlas-ph-sensor.c +++ b/drivers/iio/chemical/atlas-ph-sensor.c @@ -213,13 +213,14 @@ static int atlas_check_ec_calibration(struct atlas_data *data) struct device *dev = &data->client->dev; int ret; unsigned int val; + __be16 rval; - ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &val, 2); + ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &rval, 2); if (ret) return ret; - dev_info(dev, "probe set to K = %d.%.2d", be16_to_cpu(val) / 100, - be16_to_cpu(val) % 100); + val = be16_to_cpu(rval); + dev_info(dev, "probe set to K = %d.%.2d", val / 100, val % 100); ret = regmap_read(data->regmap, ATLAS_REG_EC_CALIB_STATUS, &val); if (ret) -- GitLab From 64bc2d02d754f4143d65cc21c644176db12ab5c8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Oct 2016 00:13:35 +0200 Subject: [PATCH 0934/1167] iio: accel: sca3000_core: avoid potentially uninitialized variable The newly added __sca3000_get_base_freq function handles all valid modes of the SCA3000_REG_ADDR_MODE register, but gcc notices that any other value (i.e. 0x00) causes the base_freq variable to not get initialized: drivers/staging/iio/accel/sca3000_core.c: In function 'sca3000_write_raw': drivers/staging/iio/accel/sca3000_core.c:527:23: error: 'base_freq' may be used uninitialized in this function [-Werror=maybe-uninitialized] This adds explicit error handling for unexpected register values, to ensure this cannot happen. Fixes: e0f3fc9b47e6 ("iio: accel: sca3000_core: implemented IIO_CHAN_INFO_SAMP_FREQ") Signed-off-by: Arnd Bergmann Cc: Ico Doornekamp Cc: Jonathan Cameron Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/sca3000_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index d626125d7af94..564b36d4f6486 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -468,6 +468,8 @@ static inline int __sca3000_get_base_freq(struct sca3000_state *st, case SCA3000_MEAS_MODE_OP_2: *base_freq = info->option_mode_2_freq; break; + default: + ret = -EINVAL; } error_ret: return ret; -- GitLab From a6e2846cacf97d4c70c5e923325b015cfa1e9053 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Fri, 21 Oct 2016 02:09:17 -0400 Subject: [PATCH 0935/1167] bnx2x: Use the correct divisor value for PHC clock readings. Time Sync (PTP) implementation uses the divisor/shift value for converting the clock ticks to nanoseconds. Driver currently defines shift value as 1, this results in the nanoseconds value to be calculated as half the actual value. Hence the user application fails to synchronize the device clock value with the PTP master device clock. Need to use the 'shift' value of 0. Signed-off-by: Sony.Chacko Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 20fe6a8c35c16..0cee4c0283f9b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -15241,7 +15241,7 @@ static void bnx2x_init_cyclecounter(struct bnx2x *bp) memset(&bp->cyclecounter, 0, sizeof(bp->cyclecounter)); bp->cyclecounter.read = bnx2x_cyclecounter_read; bp->cyclecounter.mask = CYCLECOUNTER_MASK(64); - bp->cyclecounter.shift = 1; + bp->cyclecounter.shift = 0; bp->cyclecounter.mult = 1; } -- GitLab From b678aa578c9e400429e027269e8de2783e5e73ce Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 21 Oct 2016 18:28:25 +0900 Subject: [PATCH 0936/1167] ipv6: do not increment mac header when it's unset Otherwise we'll overflow the integer. This occurs when layer 3 tunneled packets are handed off to the IPv6 layer. Signed-off-by: Jason A. Donenfeld Signed-off-by: David S. Miller --- net/ipv6/reassembly.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 2160d5d009cb6..3815e8505ed2a 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -456,7 +456,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, skb_network_header(head)[nhoff] = skb_transport_header(head)[0]; memmove(head->head + sizeof(struct frag_hdr), head->head, (head->data - head->head) - sizeof(struct frag_hdr)); - head->mac_header += sizeof(struct frag_hdr); + if (skb_mac_header_was_set(head)) + head->mac_header += sizeof(struct frag_hdr); head->network_header += sizeof(struct frag_hdr); skb_reset_transport_header(head); -- GitLab From 235bde1ed3f0fff0f68f367ec8807b89ea151258 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 21 Oct 2016 09:34:29 -0200 Subject: [PATCH 0937/1167] net: fec: Call swap_buffer() prior to IP header alignment Commit 3ac72b7b63d5 ("net: fec: align IP header in hardware") breaks networking on mx28. There is an erratum on mx28 (ENGR121613 - ENET big endian mode not compatible with ARM little endian) that requires an additional byte-swap operation to workaround this problem. So call swap_buffer() prior to performing the IP header alignment to restore network functionality on mx28. Fixes: 3ac72b7b63d5 ("net: fec: align IP header in hardware") Reported-and-tested-by: Henri Roosen Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 48a033e64423d..5aa9d4ded214c 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1430,14 +1430,14 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) skb_put(skb, pkt_len - 4); data = skb->data; + if (!is_copybreak && need_swap) + swap_buffer(data, pkt_len); + #if !defined(CONFIG_M5272) if (fep->quirks & FEC_QUIRK_HAS_RACC) data = skb_pull_inline(skb, 2); #endif - if (!is_copybreak && need_swap) - swap_buffer(data, pkt_len); - /* Extract the enhanced buffer descriptor */ ebdp = NULL; if (fep->bufdesc_ex) -- GitLab From a4b8e71b05c27bae6bad3bdecddbc6b68a3ad8cf Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 21 Oct 2016 14:13:24 +0200 Subject: [PATCH 0938/1167] net: sctp, forbid negative length Most of getsockopt handlers in net/sctp/socket.c check len against sizeof some structure like: if (len < sizeof(int)) return -EINVAL; On the first look, the check seems to be correct. But since len is int and sizeof returns size_t, int gets promoted to unsigned size_t too. So the test returns false for negative lengths. Yes, (-1 < sizeof(long)) is false. Fix this in sctp by explicitly checking len < 0 before any getsockopt handler is called. Note that sctp_getsockopt_events already handled the negative case. Since we added the < 0 check elsewhere, this one can be removed. If not checked, this is the result: UBSAN: Undefined behaviour in ../mm/page_alloc.c:2722:19 shift exponent 52 is too large for 32-bit type 'int' CPU: 1 PID: 24535 Comm: syz-executor Not tainted 4.8.1-0-syzkaller #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.9.1-0-gb3ef39f-prebuilt.qemu-project.org 04/01/2014 0000000000000000 ffff88006d99f2a8 ffffffffb2f7bdea 0000000041b58ab3 ffffffffb4363c14 ffffffffb2f7bcde ffff88006d99f2d0 ffff88006d99f270 0000000000000000 0000000000000000 0000000000000034 ffffffffb5096422 Call Trace: [] ? __ubsan_handle_shift_out_of_bounds+0x29c/0x300 ... [] ? kmalloc_order+0x24/0x90 [] ? kmalloc_order_trace+0x24/0x220 [] ? __kmalloc+0x330/0x540 [] ? sctp_getsockopt_local_addrs+0x174/0xca0 [sctp] [] ? sctp_getsockopt+0x10d/0x1b0 [sctp] [] ? sock_common_getsockopt+0xb9/0x150 [] ? SyS_getsockopt+0x1a5/0x270 Signed-off-by: Jiri Slaby Cc: Vlad Yasevich Cc: Neil Horman Cc: "David S. Miller" Cc: linux-sctp@vger.kernel.org Cc: netdev@vger.kernel.org Acked-by: Neil Horman Signed-off-by: David S. Miller --- net/sctp/socket.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index fb02c70333078..9fbb6feb8c279 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4687,7 +4687,7 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, int __user *optlen) { - if (len <= 0) + if (len == 0) return -EINVAL; if (len > sizeof(struct sctp_event_subscribe)) len = sizeof(struct sctp_event_subscribe); @@ -6430,6 +6430,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, if (get_user(len, optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; + lock_sock(sk); switch (optname) { -- GitLab From 963d790468a2f581abf039b45edac79af5e16e55 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Wed, 20 Jul 2016 14:53:51 -0700 Subject: [PATCH 0939/1167] arm64: dts: Updated NAND DT properties for NS2 SVK This patch adds NAND DT properties for NS2 SVK to configure the bus width width and OOB sector size Signed-off-by: Prafulla Kota Signed-off-by: Ray Jui Signed-off-by: Florian Fainelli --- arch/arm64/boot/dts/broadcom/ns2-svk.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/broadcom/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/ns2-svk.dts index 2d7872a36b912..b09f3bc5c6c16 100644 --- a/arch/arm64/boot/dts/broadcom/ns2-svk.dts +++ b/arch/arm64/boot/dts/broadcom/ns2-svk.dts @@ -164,6 +164,8 @@ nand-ecc-mode = "hw"; nand-ecc-strength = <8>; nand-ecc-step-size = <512>; + nand-bus-width = <16>; + brcm,nand-oob-sector-size = <16>; #address-cells = <1>; #size-cells = <1>; }; -- GitLab From 6d8d271eee0eaa3c3ffd6db29a825e02316359d4 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 18 Oct 2016 17:44:01 -0300 Subject: [PATCH 0940/1167] gpio: ath79: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/gpio/gpio-ath79.ko | grep alias $ After this patch: $ modinfo drivers/gpio/gpio-ath79.ko | grep alias alias: of:N*T*Cqca,ar9340-gpioC* alias: of:N*T*Cqca,ar9340-gpio alias: of:N*T*Cqca,ar7100-gpioC* alias: of:N*T*Cqca,ar7100-gpio Signed-off-by: Javier Martinez Canillas Acked-by: Aban Bedel Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ath79.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index 9457e2022bf6c..dc37dbe4b46d8 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -219,6 +219,7 @@ static const struct of_device_id ath79_gpio_of_match[] = { { .compatible = "qca,ar9340-gpio" }, {}, }; +MODULE_DEVICE_TABLE(of, ath79_gpio_of_match); static int ath79_gpio_probe(struct platform_device *pdev) { -- GitLab From 07d9a380680d1c0eb51ef87ff2eab5c994949e69 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 23 Oct 2016 17:10:14 -0700 Subject: [PATCH 0941/1167] Linux 4.9-rc2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 512e47a53e9ae..93beca4312c48 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 9 SUBLEVEL = 0 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = Psychotic Stoned Sheep # *DOCUMENTATION* -- GitLab From d71cf15b865bdd45925f7b094d169aaabd705145 Mon Sep 17 00:00:00 2001 From: Liu Gang Date: Fri, 21 Oct 2016 15:31:28 +0800 Subject: [PATCH 0942/1167] gpio: mpc8xxx: Correct irq handler function From the beginning of the gpio-mpc8xxx.c, the "handle_level_irq" has being used to handle GPIO interrupts in the PowerPC/Layerscape platforms. But actually, almost all PowerPC/Layerscape platforms assert an interrupt request upon either a high-to-low change or any change on the state of the signal. So the "handle_level_irq" is not reasonable for PowerPC/Layerscape GPIO interrupt, it should be "handle_edge_irq". Otherwise the system may lost some interrupts from the PIN's state changes. Signed-off-by: Liu Gang Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 425501c395270..793518a30afe6 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -239,7 +239,7 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq, irq_hw_number_t hwirq) { irq_set_chip_data(irq, h->host_data); - irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq); + irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_edge_irq); return 0; } -- GitLab From a05b82d5149dfeef05254a11c3636a89a854520a Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Fri, 21 Oct 2016 14:53:53 +0530 Subject: [PATCH 0943/1167] cxl: Fix leaking pid refs in some error paths In some error paths in functions cxl_start_context and afu_ioctl_start_work pid references to the current & group-leader tasks can leak after they are taken. This patch fixes these error paths to release these pid references before exiting the error path. Fixes: 7b8ad495d592 ("cxl: Fix DSI misses when the context owning task exits") Cc: stable@vger.kernel.org # v4.5+ Reviewed-by: Andrew Donnellan Reported-by: Frederic Barrat Signed-off-by: Vaibhav Jain Acked-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/cxl/api.c | 2 ++ drivers/misc/cxl/file.c | 22 +++++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index af23d7dfe7520..2e5233b609711 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -247,7 +247,9 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed, cxl_ctx_get(); if ((rc = cxl_ops->attach_process(ctx, kernel, wed, 0))) { + put_pid(ctx->glpid); put_pid(ctx->pid); + ctx->glpid = ctx->pid = NULL; cxl_adapter_context_put(ctx->afu->adapter); cxl_ctx_put(); goto out; diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index d0b421f49b397..77080cc5fa0aa 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -193,6 +193,16 @@ static long afu_ioctl_start_work(struct cxl_context *ctx, ctx->mmio_err_ff = !!(work.flags & CXL_START_WORK_ERR_FF); + /* + * Increment the mapped context count for adapter. This also checks + * if adapter_context_lock is taken. + */ + rc = cxl_adapter_context_get(ctx->afu->adapter); + if (rc) { + afu_release_irqs(ctx, ctx); + goto out; + } + /* * We grab the PID here and not in the file open to allow for the case * where a process (master, some daemon, etc) has opened the chardev on @@ -205,15 +215,6 @@ static long afu_ioctl_start_work(struct cxl_context *ctx, ctx->pid = get_task_pid(current, PIDTYPE_PID); ctx->glpid = get_task_pid(current->group_leader, PIDTYPE_PID); - /* - * Increment the mapped context count for adapter. This also checks - * if adapter_context_lock is taken. - */ - rc = cxl_adapter_context_get(ctx->afu->adapter); - if (rc) { - afu_release_irqs(ctx, ctx); - goto out; - } trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr); @@ -221,6 +222,9 @@ static long afu_ioctl_start_work(struct cxl_context *ctx, amr))) { afu_release_irqs(ctx, ctx); cxl_adapter_context_put(ctx->afu->adapter); + put_pid(ctx->glpid); + put_pid(ctx->pid); + ctx->glpid = ctx->pid = NULL; goto out; } -- GitLab From c663e29f8885269c1608b5aa6057729fa9267b35 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 24 Oct 2016 14:20:25 +1100 Subject: [PATCH 0944/1167] fs: Do to trim high file position bits in iomap_page_mkwrite_actor iomap_page_mkwrite_actor() calls __block_write_begin_int() with position masked as pos & ~PAGE_MASK which is equivalent to pos & (PAGE_SIZE-1). Thus it masks off high bits of file position. However __block_write_begin_int() expects full file position on input. This does not cause any visible issues because all __block_write_begin_int() really cares about are low file position bits but still it is a bug waiting to happen. Signed-off-by: Jan Kara Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner --- fs/iomap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/iomap.c b/fs/iomap.c index a92204012e2d8..a8ee8c33ca782 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -433,8 +433,7 @@ iomap_page_mkwrite_actor(struct inode *inode, loff_t pos, loff_t length, struct page *page = data; int ret; - ret = __block_write_begin_int(page, pos & ~PAGE_MASK, length, - NULL, iomap); + ret = __block_write_begin_int(page, pos, length, NULL, iomap); if (ret) return ret; -- GitLab From 7b7381f043568224af798b1decb607dca97b4114 Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Mon, 24 Oct 2016 14:21:00 +1100 Subject: [PATCH 0945/1167] xfs: fix up inode cowblocks tracking tracepoints These calls are still using the eofblocks tracepoints. The cowblocks equivalents are already defined, we just aren't actually calling them. Signed-off-by: Brian Foster Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/xfs_icache.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 14796b744e0a1..f295049db6815 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -1656,9 +1656,9 @@ void xfs_inode_set_cowblocks_tag( xfs_inode_t *ip) { - trace_xfs_inode_set_eofblocks_tag(ip); + trace_xfs_inode_set_cowblocks_tag(ip); return __xfs_inode_set_eofblocks_tag(ip, xfs_queue_cowblocks, - trace_xfs_perag_set_eofblocks, + trace_xfs_perag_set_cowblocks, XFS_ICI_COWBLOCKS_TAG); } @@ -1666,7 +1666,7 @@ void xfs_inode_clear_cowblocks_tag( xfs_inode_t *ip) { - trace_xfs_inode_clear_eofblocks_tag(ip); + trace_xfs_inode_clear_cowblocks_tag(ip); return __xfs_inode_clear_eofblocks_tag(ip, - trace_xfs_perag_clear_eofblocks, XFS_ICI_COWBLOCKS_TAG); + trace_xfs_perag_clear_cowblocks, XFS_ICI_COWBLOCKS_TAG); } -- GitLab From c17a8ef43d6b80ed3519b828c37d18645445949f Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Mon, 24 Oct 2016 14:21:08 +1100 Subject: [PATCH 0946/1167] xfs: clear cowblocks tag when cow fork is emptied The background cowblocks scan job takes care of scanning for inodes with potentially lingering blocks in the cow fork and clearing them out. If the background scanner reclaims the cow fork blocks, however, it doesn't immediately clear the cowblocks tag from the inode. Instead, the inode remains tagged until the background scanner comes around again, discovers the inode cow fork has no blocks, clears the tag and fires the trace_xfs_inode_free_cowblocks_invalid() tracepoint to indicate that the inode may have been incorrectly tagged. This is not a major functional problem as the tag is ultimately cleared. Nonetheless, clear the tag when an inode cow fork is explicitly emptied to avoid the extra round trip through the background scanner and spurious "invalid" tracepoint. Signed-off-by: Brian Foster Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/xfs_reflink.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index cd308f119e20c..a279b4e7f5fea 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -567,10 +567,14 @@ xfs_reflink_cancel_cow_blocks( } if (++idx >= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)) - return 0; + break; xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got); } + /* clear tag if cow fork is emptied */ + if (!ifp->if_bytes) + xfs_inode_clear_cowblocks_tag(ip); + return error; } -- GitLab From eef0b282bb586259d35548851cf6a4ce847bb804 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 22 Oct 2016 10:20:55 -0200 Subject: [PATCH 0947/1167] ARM: imx: gpc: Initialize all power domains Since commit 0159ec670763dd ("PM / Domains: Verify the PM domain is present when adding a provider") the following regression is observed on imx6: imx-gpc: probe of 20dc000.gpc failed with error -22 The gpc probe fails because of_genpd_add_provider_onecell() now checks if all the domains are initialized via pm_genpd_present() function and it fails because not all the power domains are initialized. In order to fix this error, initialize all the power domains from imx_gpc_domains[], not only the imx6q_pu_domain.base one. Reported-by: Olof's autobooter Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/mach-imx/gpc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 0df062d8b2c94..d0463e9d8a087 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -430,7 +430,8 @@ static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg) if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) return 0; - pm_genpd_init(&imx6q_pu_domain.base, NULL, false); + for (i = 0; i < ARRAY_SIZE(imx_gpc_domains); i++) + pm_genpd_init(imx_gpc_domains[i], NULL, false); return of_genpd_add_provider_onecell(dev->of_node, &imx_gpc_onecell_data); -- GitLab From f9d1f7a7ad919c93dfb708aae6e19d33c5437443 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 22 Oct 2016 10:20:56 -0200 Subject: [PATCH 0948/1167] ARM: imx: gpc: Fix the imx_gpc_genpd_init() error path If of_genpd_add_provider_onecell() fails the following kernel crash is observed on a kernel built with multi_v7_defconfig: [ 1.739301] [00000040] *pgd=00000000 [ 1.739310] Internal error: Oops: 5 [#1] SMP ARM [ 1.739319] Modules linked in: [ 1.739328] CPU: 1 PID: 95 Comm: kworker/1:4 Not tainted 4.8.0-11897-g6b5e09a #1 [ 1.739331] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) [ 1.739352] Workqueue: pm genpd_power_off_work_fn [ 1.739356] task: ee63d400 task.stack: ee70a000 [ 1.739365] PC is at mutex_lock+0xc/0x4c [ 1.739374] LR is at regulator_disable+0x2c/0x60 [ 1.739379] pc : [] lr : [] psr: 60000013 [ 1.739379] sp : ee70beb0 ip : 10624dd3 fp : ee6e6280 [ 1.739382] r10: eefb0900 r9 : 00000000 r8 : c1309918 [ 1.739385] r7 : 00000000 r6 : 00000040 r5 : 00000000 r4 : 00000040 [ 1.739390] r3 : 0000004c r2 : 7fffd540 r1 : 000001e4 r0 : 00000040 Instead of returning of_genpd_add_provider_onecell() directly, we should check its return value and in the case of error we should unwind the previously taken actions, which in these case are: - Call imx6q_pm_pu_power_off() - Set imx6q_pu_domain.reg back to NULL Setting imx6q_pu_domain.reg to NULL in the error case is important as it will prevent further operations in the pu_reg regulator. This kernel crash is not observed with imx_v6_v7_defconfig because it selects GPU and VPU drivers, which are consumers of the GPC block and thus change the refcount of the pu_reg regulator. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/mach-imx/gpc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index d0463e9d8a087..b54db47f6f322 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -408,7 +408,7 @@ static struct genpd_onecell_data imx_gpc_onecell_data = { static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg) { struct clk *clk; - int i; + int i, ret; imx6q_pu_domain.reg = pu_reg; @@ -432,12 +432,20 @@ static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg) for (i = 0; i < ARRAY_SIZE(imx_gpc_domains); i++) pm_genpd_init(imx_gpc_domains[i], NULL, false); - return of_genpd_add_provider_onecell(dev->of_node, + + ret = of_genpd_add_provider_onecell(dev->of_node, &imx_gpc_onecell_data); + if (ret) + goto power_off; + + return 0; +power_off: + imx6q_pm_pu_power_off(&imx6q_pu_domain.base); clk_err: while (i--) clk_put(imx6q_pu_domain.clk[i]); + imx6q_pu_domain.reg = NULL; return -EINVAL; } -- GitLab From 47ece7fef4e4206cdcee7c28ac3bca3ede0a1908 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 19 Oct 2016 13:42:55 +0200 Subject: [PATCH 0949/1167] s390/dumpstack: use pr_cont within show_stack and die Use pr_cont instead of printk calls also within show_stack and die in order to avoid extra line breaks. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/dumpstack.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c index 34345c0a3c468..55d4fe174fd97 100644 --- a/arch/s390/kernel/dumpstack.c +++ b/arch/s390/kernel/dumpstack.c @@ -119,14 +119,14 @@ void show_stack(struct task_struct *task, unsigned long *sp) else stack = (unsigned long *)task->thread.ksp; } + printk(KERN_DEFAULT "Stack:\n"); for (i = 0; i < 20; i++) { if (((addr_t) stack & (THREAD_SIZE-1)) == 0) break; - if ((i * sizeof(long) % 32) == 0) - printk("%s ", i == 0 ? "" : "\n"); - printk("%016lx ", *stack++); + if (i % 4 == 0) + printk(KERN_DEFAULT " "); + pr_cont("%016lx%c", *stack++, i % 4 == 3 ? '\n' : ' '); } - printk("\n"); show_trace(task, (unsigned long)sp); } @@ -186,14 +186,14 @@ void die(struct pt_regs *regs, const char *str) printk("%s: %04x ilc:%d [#%d] ", str, regs->int_code & 0xffff, regs->int_code >> 17, ++die_counter); #ifdef CONFIG_PREEMPT - printk("PREEMPT "); + pr_cont("PREEMPT "); #endif #ifdef CONFIG_SMP - printk("SMP "); + pr_cont("SMP "); #endif if (debug_pagealloc_enabled()) - printk("DEBUG_PAGEALLOC"); - printk("\n"); + pr_cont("DEBUG_PAGEALLOC"); + pr_cont("\n"); notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV); print_modules(); show_regs(regs); -- GitLab From 4a65429457a5d271dd3b00598b3ec75fe8b5103c Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Tue, 18 Oct 2016 17:32:18 +0200 Subject: [PATCH 0950/1167] s390/mm: fix zone calculation in arch_add_memory() Standby (hotplug) memory should be added to ZONE_MOVABLE on s390. After commit 199071f1 "s390/mm: make arch_add_memory() NUMA aware", arch_add_memory() used memblock_end_of_DRAM() to find out the end of ZONE_NORMAL and the beginning of ZONE_MOVABLE. However, commit 7f36e3e5 "memory-hotplug: add hot-added memory ranges to memblock before allocate node_data for a node." moved the call of memblock_add_node() before the call of arch_add_memory() in add_memory_resource(), and thus changed the return value of memblock_end_of_DRAM() when called in arch_add_memory(). As a result, arch_add_memory() will think that all memory blocks should be added to ZONE_NORMAL. Fix this by changing the logic in arch_add_memory() so that it will manually iterate over all zones of a given node to find out which zone a memory block should be added to. Reviewed-by: Heiko Carstens Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky --- arch/s390/mm/init.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index f56a39bd8ba68..b3e9d18f2ec62 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -151,36 +151,40 @@ void __init free_initrd_mem(unsigned long start, unsigned long end) #ifdef CONFIG_MEMORY_HOTPLUG int arch_add_memory(int nid, u64 start, u64 size, bool for_device) { - unsigned long normal_end_pfn = PFN_DOWN(memblock_end_of_DRAM()); - unsigned long dma_end_pfn = PFN_DOWN(MAX_DMA_ADDRESS); + unsigned long zone_start_pfn, zone_end_pfn, nr_pages; unsigned long start_pfn = PFN_DOWN(start); unsigned long size_pages = PFN_DOWN(size); - unsigned long nr_pages; - int rc, zone_enum; + pg_data_t *pgdat = NODE_DATA(nid); + struct zone *zone; + int rc, i; rc = vmem_add_mapping(start, size); if (rc) return rc; - while (size_pages > 0) { - if (start_pfn < dma_end_pfn) { - nr_pages = (start_pfn + size_pages > dma_end_pfn) ? - dma_end_pfn - start_pfn : size_pages; - zone_enum = ZONE_DMA; - } else if (start_pfn < normal_end_pfn) { - nr_pages = (start_pfn + size_pages > normal_end_pfn) ? - normal_end_pfn - start_pfn : size_pages; - zone_enum = ZONE_NORMAL; + for (i = 0; i < MAX_NR_ZONES; i++) { + zone = pgdat->node_zones + i; + if (zone_idx(zone) != ZONE_MOVABLE) { + /* Add range within existing zone limits, if possible */ + zone_start_pfn = zone->zone_start_pfn; + zone_end_pfn = zone->zone_start_pfn + + zone->spanned_pages; } else { - nr_pages = size_pages; - zone_enum = ZONE_MOVABLE; + /* Add remaining range to ZONE_MOVABLE */ + zone_start_pfn = start_pfn; + zone_end_pfn = start_pfn + size_pages; } - rc = __add_pages(nid, NODE_DATA(nid)->node_zones + zone_enum, - start_pfn, size_pages); + if (start_pfn < zone_start_pfn || start_pfn >= zone_end_pfn) + continue; + nr_pages = (start_pfn + size_pages > zone_end_pfn) ? + zone_end_pfn - start_pfn : size_pages; + rc = __add_pages(nid, zone, start_pfn, nr_pages); if (rc) break; start_pfn += nr_pages; size_pages -= nr_pages; + if (!size_pages) + break; } if (rc) vmem_remove_mapping(start, size); -- GitLab From 56c46222af0d09149fadec2a3ce9d4889de01cc6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 21 Oct 2016 20:03:05 +1100 Subject: [PATCH 0951/1167] powerpc/64: Re-fix race condition between going idle and entering guest Commit 8117ac6a6c2f ("powerpc/powernv: Switch off MMU before entering nap/sleep/rvwinkle mode", 2014-12-10) fixed a race condition where one thread entering a KVM guest could switch the MMU context to the guest while another thread was still in host kernel context with the MMU on. That commit moved the point where a thread entering a power-saving mode set its kvm_hstate.hwthread_state field in its PACA to KVM_HWTHREAD_IN_IDLE from a point where the MMU was on to after the MMU had been switched off. That commit also added a comment explaining that we have to switch to real mode before setting hwthread_state to avoid this race. Nevertheless, commit 4eae2c9ae54a ("powerpc/powernv: Make pnv_powersave_common more generic", 2016-07-08) subsequently moved the setting of hwthread_state back to a point where the MMU is on, thus reintroducing the race, despite the comment saying that this should not be done being included in full in the context lines of the patch that did it. This fixes the race again and adds a bigger and shoutier comment explaining the potential race condition. Fixes: 4eae2c9ae54a ("powerpc/powernv: Make pnv_powersave_common more generic") Cc: stable@vger.kernel.org # v4.8+ Signed-off-by: Paul Mackerras Reviewed-by: Shreyas B. Prabhu Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/idle_book3s.S | 32 +++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S index bd739fed26e32..0d8712a835d2c 100644 --- a/arch/powerpc/kernel/idle_book3s.S +++ b/arch/powerpc/kernel/idle_book3s.S @@ -163,12 +163,6 @@ _GLOBAL(pnv_powersave_common) std r9,_MSR(r1) std r1,PACAR1(r13) -#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE - /* Tell KVM we're entering idle */ - li r4,KVM_HWTHREAD_IN_IDLE - stb r4,HSTATE_HWTHREAD_STATE(r13) -#endif - /* * Go to real mode to do the nap, as required by the architecture. * Also, we need to be in real mode before setting hwthread_state, @@ -185,6 +179,26 @@ _GLOBAL(pnv_powersave_common) .globl pnv_enter_arch207_idle_mode pnv_enter_arch207_idle_mode: +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE + /* Tell KVM we're entering idle */ + li r4,KVM_HWTHREAD_IN_IDLE + /******************************************************/ + /* N O T E W E L L ! ! ! N O T E W E L L */ + /* The following store to HSTATE_HWTHREAD_STATE(r13) */ + /* MUST occur in real mode, i.e. with the MMU off, */ + /* and the MMU must stay off until we clear this flag */ + /* and test HSTATE_HWTHREAD_REQ(r13) in the system */ + /* reset interrupt vector in exceptions-64s.S. */ + /* The reason is that another thread can switch the */ + /* MMU to a guest context whenever this flag is set */ + /* to KVM_HWTHREAD_IN_IDLE, and if the MMU was on, */ + /* that would potentially cause this thread to start */ + /* executing instructions from guest memory in */ + /* hypervisor mode, leading to a host crash or data */ + /* corruption, or worse. */ + /******************************************************/ + stb r4,HSTATE_HWTHREAD_STATE(r13) +#endif stb r3,PACA_THREAD_IDLE_STATE(r13) cmpwi cr3,r3,PNV_THREAD_SLEEP bge cr3,2f @@ -250,6 +264,12 @@ enter_winkle: * r3 - requested stop state */ power_enter_stop: +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE + /* Tell KVM we're entering idle */ + li r4,KVM_HWTHREAD_IN_IDLE + /* DO THIS IN REAL MODE! See comment above. */ + stb r4,HSTATE_HWTHREAD_STATE(r13) +#endif /* * Check if the requested state is a deep idle state. */ -- GitLab From 09b7e37b18eecc1e347f4b1a3bc863f32801f634 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 21 Oct 2016 20:04:17 +1100 Subject: [PATCH 0952/1167] powerpc/64: Fix race condition in setting lock bit in idle/wakeup code This fixes a race condition where one thread that is entering or leaving a power-saving state can inadvertently ignore the lock bit that was set by another thread, and potentially also clear it. The core_idle_lock_held function is called when the lock bit is seen to be set. It polls the lock bit until it is clear, then does a lwarx to load the word containing the lock bit and thread idle bits so it can be updated. However, it is possible that the value loaded with the lwarx has the lock bit set, even though an immediately preceding lwz loaded a value with the lock bit clear. If this happens then we go ahead and update the word despite the lock bit being set, and when called from pnv_enter_arch207_idle_mode, we will subsequently clear the lock bit. No identifiable misbehaviour has been attributed to this race. This fixes it by checking the lock bit in the value loaded by the lwarx. If it is set then we just go back and keep on polling. Fixes: b32aadc1a8ed ("powerpc/powernv: Fix race in updating core_idle_state") Cc: stable@vger.kernel.org # v4.2+ Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/idle_book3s.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S index 0d8712a835d2c..72dac0b58061f 100644 --- a/arch/powerpc/kernel/idle_book3s.S +++ b/arch/powerpc/kernel/idle_book3s.S @@ -90,6 +90,7 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300) * Threads will spin in HMT_LOW until the lock bit is cleared. * r14 - pointer to core_idle_state * r15 - used to load contents of core_idle_state + * r9 - used as a temporary variable */ core_idle_lock_held: @@ -99,6 +100,8 @@ core_idle_lock_held: bne 3b HMT_MEDIUM lwarx r15,0,r14 + andi. r9,r15,PNV_CORE_IDLE_LOCK_BIT + bne core_idle_lock_held blr /* -- GitLab From 44d524218c65e1f2e6d945b09165562852298015 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 17 Oct 2016 18:51:27 -0700 Subject: [PATCH 0953/1167] ARM: dts: vf610: fix IRQ flag of global timer The global timer IRQ (PPI[0], PPI 11 in device tree terms) is a rising edge interrupt. The ARM Cortex-A5 MPCore TRM in Chapter 10.1.2. Interrupt types and sources says: "Interrupt is rising-edge sensitive." The bits seem to be read-only, hence this missconfiguration had no negative effect. However, with commit 992345a58e0c ("irqchip/gic: WARN if setting the interrupt type for a PPI fails") warnings such as this get printed: GIC: PPI11 is secure or misconfigured With this change the new configuration matches the default configuration and no warning is printed anymore. Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo --- arch/arm/boot/dts/vf500.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/vf500.dtsi b/arch/arm/boot/dts/vf500.dtsi index a3824e61bd72c..d7fdb2a7d97b6 100644 --- a/arch/arm/boot/dts/vf500.dtsi +++ b/arch/arm/boot/dts/vf500.dtsi @@ -70,7 +70,7 @@ global_timer: timer@40002200 { compatible = "arm,cortex-a9-global-timer"; reg = <0x40002200 0x20>; - interrupts = ; + interrupts = ; interrupt-parent = <&intc>; clocks = <&clks VF610_CLK_PLATFORM_BUS>; }; -- GitLab From eeaed4bb5a35591470b545590bb2f26dbe7653a2 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Mon, 24 Oct 2016 00:31:30 -0400 Subject: [PATCH 0954/1167] ACPI/PCI/IRQ: assign ISA IRQ directly during early boot stages We do not want to store the SCI penalty in the acpi_isa_irq_penalty[] table because acpi_isa_irq_penalty[] only holds ISA IRQ penalties and there's no guarantee that the SCI is an ISA IRQ. We add in the SCI penalty as a special case in acpi_irq_get_penalty(). But if we called acpi_penalize_isa_irq() or acpi_irq_penalty_update() for an SCI that happened to be an ISA IRQ, they stored the SCI penalty (part of the acpi_irq_get_penalty() return value) in acpi_isa_irq_penalty[]. Subsequent calls to acpi_irq_get_penalty() returned a penalty that included *two* SCI penalties. Fixes: 103544d86976 (ACPI,PCI,IRQ: reduce resource requirements) Signed-off-by: Sinan Kaya Acked-by: Bjorn Helgaas Tested-by: Jonathan Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pci_link.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index c983bf733ad37..6229b022a5d40 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -849,7 +849,7 @@ static int __init acpi_irq_penalty_update(char *str, int used) continue; if (used) - new_penalty = acpi_irq_get_penalty(irq) + + new_penalty = acpi_isa_irq_penalty[irq] + PIRQ_PENALTY_ISA_USED; else new_penalty = 0; @@ -871,7 +871,7 @@ static int __init acpi_irq_penalty_update(char *str, int used) void acpi_penalize_isa_irq(int irq, int active) { if ((irq >= 0) && (irq < ARRAY_SIZE(acpi_isa_irq_penalty))) - acpi_isa_irq_penalty[irq] = acpi_irq_get_penalty(irq) + + acpi_isa_irq_penalty[irq] += (active ? PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING); } -- GitLab From f1caa61df2a3dc4c58316295c5dc5edba4c68d85 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Mon, 24 Oct 2016 00:31:31 -0400 Subject: [PATCH 0955/1167] ACPI/PCI: pci_link: penalize SCI correctly Ondrej reported that IRQs stopped working in v4.7 on several platforms. A typical scenario, from Ondrej's VT82C694X/694X, is: ACPI: Using PIC for interrupt routing ACPI: PCI Interrupt Link [LNKA] (IRQs 1 3 4 5 6 7 10 *11 12 14 15) ACPI: No IRQ available for PCI Interrupt Link [LNKA] 8139too 0000:00:0f.0: PCI INT A: no GSI We're using PIC routing, so acpi_irq_balance == 0, and LNKA is already active at IRQ 11. In that case, acpi_pci_link_allocate() only tries to use the active IRQ (IRQ 11) which also happens to be the SCI. We should penalize the SCI by PIRQ_PENALTY_PCI_USING, but irq_get_trigger_type(11) returns something other than IRQ_TYPE_LEVEL_LOW, so we penalize it by PIRQ_PENALTY_ISA_ALWAYS instead, which makes acpi_pci_link_allocate() assume the IRQ isn't available and give up. Add acpi_penalize_sci_irq() so platforms can tell us the SCI IRQ, trigger, and polarity directly and we don't have to depend on irq_get_trigger_type(). Fixes: 103544d86976 (ACPI,PCI,IRQ: reduce resource requirements) Link: http://lkml.kernel.org/r/201609251512.05657.linux@rainbow-software.org Reported-by: Ondrej Zary Acked-by: Bjorn Helgaas Signed-off-by: Sinan Kaya Tested-by: Jonathan Liu Signed-off-by: Rafael J. Wysocki --- arch/x86/kernel/acpi/boot.c | 1 + drivers/acpi/pci_link.c | 30 +++++++++++++++--------------- include/linux/acpi.h | 1 + 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 8a5abaa7d4533..931ced8ca3451 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -454,6 +454,7 @@ static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger, polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK; mp_override_legacy_irq(bus_irq, polarity, trigger, gsi); + acpi_penalize_sci_irq(bus_irq, trigger, polarity); /* * stash over-ride to indicate we've been here diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 6229b022a5d40..74bf96efae959 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -87,6 +87,7 @@ struct acpi_pci_link { static LIST_HEAD(acpi_link_list); static DEFINE_MUTEX(acpi_link_lock); +static int sci_irq = -1, sci_penalty; /* -------------------------------------------------------------------------- PCI Link Device Management @@ -496,25 +497,13 @@ static int acpi_irq_get_penalty(int irq) { int penalty = 0; - /* - * Penalize IRQ used by ACPI SCI. If ACPI SCI pin attributes conflict - * with PCI IRQ attributes, mark ACPI SCI as ISA_ALWAYS so it won't be - * use for PCI IRQs. - */ - if (irq == acpi_gbl_FADT.sci_interrupt) { - u32 type = irq_get_trigger_type(irq) & IRQ_TYPE_SENSE_MASK; - - if (type != IRQ_TYPE_LEVEL_LOW) - penalty += PIRQ_PENALTY_ISA_ALWAYS; - else - penalty += PIRQ_PENALTY_PCI_USING; - } + if (irq == sci_irq) + penalty += sci_penalty; if (irq < ACPI_MAX_ISA_IRQS) return penalty + acpi_isa_irq_penalty[irq]; - penalty += acpi_irq_pci_sharing_penalty(irq); - return penalty; + return penalty + acpi_irq_pci_sharing_penalty(irq); } int __init acpi_irq_penalty_init(void) @@ -881,6 +870,17 @@ bool acpi_isa_irq_available(int irq) acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS); } +void acpi_penalize_sci_irq(int irq, int trigger, int polarity) +{ + sci_irq = irq; + + if (trigger == ACPI_MADT_TRIGGER_LEVEL && + polarity == ACPI_MADT_POLARITY_ACTIVE_LOW) + sci_penalty = PIRQ_PENALTY_PCI_USING; + else + sci_penalty = PIRQ_PENALTY_ISA_ALWAYS; +} + /* * Over-ride default table to reserve additional IRQs for use by ISA * e.g. acpi_irq_isa=5 diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ddbeda6dbdc87..689a8b9b9c8fd 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -326,6 +326,7 @@ struct pci_dev; int acpi_pci_irq_enable (struct pci_dev *dev); void acpi_penalize_isa_irq(int irq, int active); bool acpi_isa_irq_available(int irq); +void acpi_penalize_sci_irq(int irq, int trigger, int polarity); void acpi_pci_irq_disable (struct pci_dev *dev); extern int ec_read(u8 addr, u8 *val); -- GitLab From 98756f5319c64c883caa910dce702d9edefe7810 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Mon, 24 Oct 2016 00:31:32 -0400 Subject: [PATCH 0956/1167] ACPI/PCI: pci_link: Include PIRQ_PENALTY_PCI_USING for ISA IRQs Commit 103544d86976 ("ACPI,PCI,IRQ: reduce resource requirements") replaced the addition of PIRQ_PENALTY_PCI_USING in acpi_pci_link_allocate() with an addition in acpi_irq_pci_sharing_penalty(), but f7eca374f000 ("ACPI,PCI,IRQ: separate ISA penalty calculation") removed the use of acpi_irq_pci_sharing_penalty() for ISA IRQs. Therefore, PIRQ_PENALTY_PCI_USING is missing from ISA IRQs used by interrupt links. Include that penalty by adding it in the acpi_pci_link_allocate() path. Fixes: f7eca374f000 (ACPI,PCI,IRQ: separate ISA penalty calculation) Signed-off-by: Sinan Kaya Acked-by: Bjorn Helgaas Tested-by: Jonathan Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pci_link.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 74bf96efae959..bc3d914dfc3e3 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -608,6 +608,10 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) acpi_device_bid(link->device)); return -ENODEV; } else { + if (link->irq.active < ACPI_MAX_ISA_IRQS) + acpi_isa_irq_penalty[link->irq.active] += + PIRQ_PENALTY_PCI_USING; + printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n", acpi_device_name(link->device), acpi_device_bid(link->device), link->irq.active); -- GitLab From ed19ece135a6908244e22e4ab395165999a4d3ab Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 29 Sep 2016 18:07:07 +0800 Subject: [PATCH 0957/1167] usb: ohci-at91: Set RemoteWakeupConnected bit explicitly. The reset value of RWC is 0, set RemoteWakeupConnected bit explicitly before calling ohci_run, it also fixes the issue that the mass storage stick connected wasn't suspended when the system suspend. Signed-off-by: Wenyou Yang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 5b5880c0ae191..b38a228134df1 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -221,6 +221,12 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, ohci->num_ports = board->ports; at91_start_hc(pdev); + /* + * The RemoteWakeupConnected bit has to be set explicitly + * before calling ohci_run. The reset value of this bit is 0. + */ + ohci->hc_control = OHCI_CTRL_RWC; + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval == 0) { device_wakeup_enable(hcd->self.controller); @@ -677,9 +683,6 @@ ohci_hcd_at91_drv_suspend(struct device *dev) * REVISIT: some boards will be able to turn VBUS off... */ if (!ohci_at91->wakeup) { - ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); - ohci->hc_control &= OHCI_CTRL_RWC; - ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); ohci->rh_state = OHCI_RH_HALTED; /* flush the writes */ -- GitLab From 1e4b4348753ba555ea93470ea8af821425d9c826 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 17 Oct 2016 20:11:59 +0900 Subject: [PATCH 0958/1167] usb: ehci-platform: increase EHCI_MAX_RSTS to 4 Socionext LD11 SoC (arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi) needs to handle 4 reset lines for EHCI. Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 876dca4fc2162..a268d9e8d6cfb 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -39,7 +39,7 @@ #define DRIVER_DESC "EHCI generic platform driver" #define EHCI_MAX_CLKS 4 -#define EHCI_MAX_RSTS 3 +#define EHCI_MAX_RSTS 4 #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv) struct ehci_platform_priv { -- GitLab From d8e5f0eca1e88215e45aca27115ea747e6164da1 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 19 Oct 2016 12:03:39 -0500 Subject: [PATCH 0959/1167] usb: musb: Fix hardirq-safe hardirq-unsafe lock order error If we configure musb with 2430 glue as a peripheral, and then rmmod omap2430 module, we'll get the following error: [ INFO: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected ] ... rmmod/413 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire: (&phy->mutex){+.+.+.}, at: [] phy_power_off+0x1c/0xb8 [ 204.678710] and this task is already holding: (&(&musb->lock)->rlock){-.-...}, at: [] musb_gadget_stop+0x24/0xec [musb_hdrc] which would create a new lock dependency: (&(&musb->lock)->rlock){-.-...} -> (&phy->mutex){+.+.+.} ... This is because some glue layers expect musb_platform_enable/disable to be called with spinlock held, and 2430 glue layer has USB PHY on the I2C bus using a mutex. We could fix the glue layers to take the spinlock, but we still have a problem of musb_plaform_enable/disable being called in an unbalanced manner. So that would still lead into USB PHY enable/disable related problems for omap2430 glue layer. While it makes sense to only enable USB PHY when needed from PM point of view, in this case we just can't do it yet without breaking things. So let's just revert phy_enable/disable related changes instead and reconsider this after we have fixed musb_platform_enable/disable to be balanced. Fixes: a83e17d0f73b ("usb: musb: Improve PM runtime and phy handling for 2430 glue layer") Reviewed-by: Laurent Pinchart Signed-off-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/omap2430.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 1ab6973d4f619..cc1225485509c 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -287,6 +287,7 @@ static int omap2430_musb_init(struct musb *musb) } musb->isr = omap2430_musb_interrupt; phy_init(musb->phy); + phy_power_on(musb->phy); l = musb_readl(musb->mregs, OTG_INTERFSEL); @@ -323,8 +324,6 @@ static void omap2430_musb_enable(struct musb *musb) struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); struct omap_musb_board_data *data = pdata->board_data; - if (!WARN_ON(!musb->phy)) - phy_power_on(musb->phy); switch (glue->status) { @@ -361,9 +360,6 @@ static void omap2430_musb_disable(struct musb *musb) struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); - if (!WARN_ON(!musb->phy)) - phy_power_off(musb->phy); - if (glue->status != MUSB_UNKNOWN) omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DISCONNECT); @@ -375,6 +371,7 @@ static int omap2430_musb_exit(struct musb *musb) struct omap2430_glue *glue = dev_get_drvdata(dev->parent); omap2430_low_level_exit(musb); + phy_power_off(musb->phy); phy_exit(musb->phy); musb->phy = NULL; cancel_work_sync(&glue->omap_musb_mailbox_work); -- GitLab From cacaaf80c3a6f6036d290f353c4c1db237b42647 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 19 Oct 2016 12:03:40 -0500 Subject: [PATCH 0960/1167] usb: musb: Call pm_runtime from musb_gadget_queue If we're booting pandaboard using NFSroot over built-in g_ether, we can get the following after booting once and doing a warm reset: g_ether gadget: ecm_open g_ether gadget: notify connect true ... WARNING: CPU: 0 PID: 1 at drivers/bus/omap_l3_noc.c:147 l3_interrupt_handler+0x220/0x34c 44000000.ocp:L3 Custom Error: MASTER MPU TARGET L4CFG (Read): Data Access in User mode du ring Functional access ... Fix the issue by calling pm_runtime functions from musb_gadget_queue. Note that in the long run we should be able to queue the pending transfers if pm_runtime is not active, and flush the queue from pm_runtime_resume. Reported-by: Laurent Pinchart Tested-by: Laurent Pinchart Signed-off-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_gadget.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index bff4869a57cd1..4042ea017985d 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1255,6 +1255,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, map_dma_buffer(request, musb, musb_ep); + pm_runtime_get_sync(musb->controller); spin_lock_irqsave(&musb->lock, lockflags); /* don't queue if the ep is down */ @@ -1275,6 +1276,9 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, unlock: spin_unlock_irqrestore(&musb->lock, lockflags); + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); + return status; } -- GitLab From ed6d6f8f42d7302f6f9b6245f34927ec20d26c12 Mon Sep 17 00:00:00 2001 From: Bryan Paluch Date: Mon, 17 Oct 2016 08:54:46 -0400 Subject: [PATCH 0961/1167] usb: increase ohci watchdog delay to 275 msec Increase ohci watchout delay to 275 ms. Previous delay was 250 ms with 20 ms of slack, after removing slack time some ohci controllers don't respond in time. Logs from systems with controllers that have the issue would show "HcDoneHead not written back; disabled" Signed-off-by: Bryan Paluch Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 1700908b84ef8..86612ac3fda22 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -72,7 +72,7 @@ static const char hcd_name [] = "ohci_hcd"; #define STATECHANGE_DELAY msecs_to_jiffies(300) -#define IO_WATCHDOG_DELAY msecs_to_jiffies(250) +#define IO_WATCHDOG_DELAY msecs_to_jiffies(275) #include "ohci.h" #include "pci-quirks.h" -- GitLab From 806487a8fc8f385af75ed261e9ab658fc845e633 Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 18 Oct 2016 17:07:19 +0100 Subject: [PATCH 0962/1167] ACPI / APEI: Fix incorrect return value of ghes_proc() Although ghes_proc() tests for errors while reading the error status, it always return success (0). Fix this by propagating the return value. Fixes: d334a49113a4a33 (ACPI, APEI, Generic Hardware Error Source memory error support) Signed-of-by: Punit Agrawal Tested-by: Tyler Baicar Reviewed-by: Borislav Petkov [ rjw: Subject ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/ghes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index f0a029e68d3e2..0d099a24f776a 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -662,7 +662,7 @@ static int ghes_proc(struct ghes *ghes) ghes_do_proc(ghes, ghes->estatus); out: ghes_clear_estatus(ghes); - return 0; + return rc; } static void ghes_add_timer(struct ghes *ghes) -- GitLab From b76032396d7958f006bccf5fb2535beb5526837c Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 20 Oct 2016 13:19:19 +0900 Subject: [PATCH 0963/1167] usb: renesas_usbhs: add wait after initialization for R-Car Gen3 Since the controller on R-Car Gen3 doesn't have any status registers to detect initialization (LPSTS.SUSPM = 1) and the initialization needs up to 45 usec, this patch adds wait after the initialization. Otherwise, writing other registers (e.g. INTENB0) will fail. Fixes: de18757e272d ("usb: renesas_usbhs: add R-Car Gen3 power control") Cc: # v4.6+ Cc: Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/rcar3.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index 1d70add926f0f..d544b331c9f2c 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -9,6 +9,7 @@ * */ +#include #include #include "common.h" #include "rcar3.h" @@ -35,10 +36,13 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG); - if (enable) + if (enable) { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); - else + /* The controller on R-Car Gen3 needs to wait up to 45 usec */ + udelay(45); + } else { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0); + } return 0; } -- GitLab From 1adb469b9b76276d7e5ea36a20a24c47d6618a0b Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 21 Oct 2016 16:24:09 +0100 Subject: [PATCH 0964/1167] PM / suspend: Fix missing KERN_CONT for suspend message Commit 4bcc595ccd80 (printk: reinstate KERN_CONT for printing continuation lines) exposed a missing KERN_CONT from one of the messages shown on entering suspend. With v4.9-rc1, the 'done.' shown after syncing the filesystems no longer appears as a continuation but a new message with its own timestamp. [ 9.259566] PM: Syncing filesystems ... [ 9.264119] done. Fix this by adding the KERN_CONT log level for the 'done.' part of the message seen after syncing filesystems. While we are at it, convert these suspend printks to pr_info and pr_cont, respectively. Signed-off-by: Jon Hunter Signed-off-by: Rafael J. Wysocki --- kernel/power/suspend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 1e7f5da648d99..6ccb08f57fcb4 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -498,9 +498,9 @@ static int enter_state(suspend_state_t state) #ifndef CONFIG_SUSPEND_SKIP_SYNC trace_suspend_resume(TPS("sync_filesystems"), 0, true); - printk(KERN_INFO "PM: Syncing filesystems ... "); + pr_info("PM: Syncing filesystems ... "); sys_sync(); - printk("done.\n"); + pr_cont("done.\n"); trace_suspend_resume(TPS("sync_filesystems"), 0, false); #endif -- GitLab From 4edd601c5a9c5094daa714e65063e623826f3bcc Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 24 Oct 2016 10:32:12 -0200 Subject: [PATCH 0965/1167] ARM: imx: mach-imx6q: Fix the PHY ID mask for AR8031 AR8031 and AR8035 have the same PHY ID mask of 0xffffffef. So fix it and make it match with the PHY ID mask definition at drivers/net/phy/at803x.c. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/mach-imx/mach-imx6q.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 97fd25105e2c0..45801b27ee5ce 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -173,7 +173,7 @@ static void __init imx6q_enet_phy_init(void) ksz9021rn_phy_fixup); phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK, ksz9031rn_phy_fixup); - phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff, + phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffef, ar8031_phy_fixup); phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef, ar8035_phy_fixup); -- GitLab From cf55902b9c306ed259eb57ff111a0c152620f4a6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Oct 2016 15:55:08 +0300 Subject: [PATCH 0966/1167] staging: android: ion: Fix error handling in ion_query_heaps() If the copy_to_user() fails we should unlock and return directly without updating "cnt". Also the return value should be -EFAULT instead of the number of bytes remaining. Fixes: 02b23803c6af ("staging: android: ion: Add ioctl to query available heaps") Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 396ded52ab702..209a8f7ef02bd 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1187,8 +1187,10 @@ int ion_query_heaps(struct ion_client *client, struct ion_heap_query *query) hdata.type = heap->type; hdata.heap_id = heap->id; - ret = copy_to_user(&buffer[cnt], - &hdata, sizeof(hdata)); + if (copy_to_user(&buffer[cnt], &hdata, sizeof(hdata))) { + ret = -EFAULT; + goto out; + } cnt++; if (cnt >= max_cnt) -- GitLab From 25633d1f5dd7ea35c77aae12c039a80e46abec01 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 16:37:20 +0000 Subject: [PATCH 0967/1167] greybus: arche-platform: Add missing of_node_put() in arche_platform_change_state() This node pointer is returned by of_find_compatible_node() with refcount incremented in this function. of_node_put() on it before exitting this function. This is detected by Coccinelle semantic patch. Signed-off-by: Wei Yongjun Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/arche-platform.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c index e36ee984485bf..34307ac3f2558 100644 --- a/drivers/staging/greybus/arche-platform.c +++ b/drivers/staging/greybus/arche-platform.c @@ -128,6 +128,7 @@ int arche_platform_change_state(enum arche_platform_state state, pdev = of_find_device_by_node(np); if (!pdev) { pr_err("arche-platform device not found\n"); + of_node_put(np); return -ENODEV; } -- GitLab From 1305f2b2f52af5986f44dfbb1a6fe58ae875aa61 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 19 Oct 2016 13:17:53 +0000 Subject: [PATCH 0968/1167] greybus: es2: fix error return code in ap_probe() Fix to return a negative error code from the es2_arpc_in_enable() error handling case instead of 0, as done elsewhere in this function. Fixes: 9d9d3777a9db ("greybus: es2: Add a new bulk in endpoint for APBridgeA RPC") Signed-off-by: Wei Yongjun Acked-by: Viresh Kumar Reviewed-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/es2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/greybus/es2.c b/drivers/staging/greybus/es2.c index 071bb1cfd3ae1..baab460eeaa38 100644 --- a/drivers/staging/greybus/es2.c +++ b/drivers/staging/greybus/es2.c @@ -1548,7 +1548,8 @@ static int ap_probe(struct usb_interface *interface, INIT_LIST_HEAD(&es2->arpcs); spin_lock_init(&es2->arpc_lock); - if (es2_arpc_in_enable(es2)) + retval = es2_arpc_in_enable(es2); + if (retval) goto error; retval = gb_hd_add(hd); -- GitLab From e866dd8aab76b6a0ee8428491e65fa5c83a6ae5a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Oct 2016 22:18:21 +0300 Subject: [PATCH 0969/1167] greybus: fix a leak on error in gb_module_create() We should release ->interfaces[0] as well. Fixes: b15d97d77017 ("greybus: core: add module abstraction") Signed-off-by: Dan Carpenter Acked-by: Viresh Kumar Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/greybus/module.c b/drivers/staging/greybus/module.c index 69f67ddbd4a36..660b4674a76f5 100644 --- a/drivers/staging/greybus/module.c +++ b/drivers/staging/greybus/module.c @@ -127,7 +127,7 @@ struct gb_module *gb_module_create(struct gb_host_device *hd, u8 module_id, return module; err_put_interfaces: - for (--i; i > 0; --i) + for (--i; i >= 0; --i) gb_interface_put(module->interfaces[i]); put_device(&module->dev); -- GitLab From 44b3c7af02ca2701b6b90ee30c9d1d9c3ae07653 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Tue, 11 Oct 2016 13:34:16 +0200 Subject: [PATCH 0970/1167] xenbus: advertise control feature flags The Xen docs specify several flags which a guest can set to advertise which values of the xenstore control/shutdown key it will recognize. This patch adds code to write all the relevant feature-flag keys. Based-on-patch-by: Paul Durrant Signed-off-by: Juergen Gross Reviewed-by: David Vrabel Reviewed-by: Paul Durrant Signed-off-by: David Vrabel --- drivers/xen/manage.c | 45 ++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index e12bd3635f832..26e5e8507f031 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -168,7 +168,9 @@ static void do_suspend(void) #endif /* CONFIG_HIBERNATE_CALLBACKS */ struct shutdown_handler { - const char *command; +#define SHUTDOWN_CMD_SIZE 11 + const char command[SHUTDOWN_CMD_SIZE]; + bool flag; void (*cb)(void); }; @@ -206,22 +208,22 @@ static void do_reboot(void) ctrl_alt_del(); } +static struct shutdown_handler shutdown_handlers[] = { + { "poweroff", true, do_poweroff }, + { "halt", false, do_poweroff }, + { "reboot", true, do_reboot }, +#ifdef CONFIG_HIBERNATE_CALLBACKS + { "suspend", true, do_suspend }, +#endif +}; + static void shutdown_handler(struct xenbus_watch *watch, const char **vec, unsigned int len) { char *str; struct xenbus_transaction xbt; int err; - static struct shutdown_handler handlers[] = { - { "poweroff", do_poweroff }, - { "halt", do_poweroff }, - { "reboot", do_reboot }, -#ifdef CONFIG_HIBERNATE_CALLBACKS - { "suspend", do_suspend }, -#endif - {NULL, NULL}, - }; - static struct shutdown_handler *handler; + int idx; if (shutting_down != SHUTDOWN_INVALID) return; @@ -238,13 +240,13 @@ static void shutdown_handler(struct xenbus_watch *watch, return; } - for (handler = &handlers[0]; handler->command; handler++) { - if (strcmp(str, handler->command) == 0) + for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) { + if (strcmp(str, shutdown_handlers[idx].command) == 0) break; } /* Only acknowledge commands which we are prepared to handle. */ - if (handler->cb) + if (idx < ARRAY_SIZE(shutdown_handlers)) xenbus_write(xbt, "control", "shutdown", ""); err = xenbus_transaction_end(xbt, 0); @@ -253,8 +255,8 @@ static void shutdown_handler(struct xenbus_watch *watch, goto again; } - if (handler->cb) { - handler->cb(); + if (idx < ARRAY_SIZE(shutdown_handlers)) { + shutdown_handlers[idx].cb(); } else { pr_info("Ignoring shutdown request: %s\n", str); shutting_down = SHUTDOWN_INVALID; @@ -310,6 +312,9 @@ static struct notifier_block xen_reboot_nb = { static int setup_shutdown_watcher(void) { int err; + int idx; +#define FEATURE_PATH_SIZE (SHUTDOWN_CMD_SIZE + sizeof("feature-")) + char node[FEATURE_PATH_SIZE]; err = register_xenbus_watch(&shutdown_watch); if (err) { @@ -326,6 +331,14 @@ static int setup_shutdown_watcher(void) } #endif + for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) { + if (!shutdown_handlers[idx].flag) + continue; + snprintf(node, FEATURE_PATH_SIZE, "feature-%s", + shutdown_handlers[idx].command); + xenbus_printf(XBT_NIL, "control", node, "%u", 1); + } + return 0; } -- GitLab From cb5f7e7c1ded5ff91b18116669c0f43c82bea3db Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 12 Oct 2016 17:20:38 +0200 Subject: [PATCH 0971/1167] x86: xen: move cpu_up functions out of ifdef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three newly introduced functions are not defined when CONFIG_XEN_PVHVM is disabled, but are still being used: arch/x86/xen/enlighten.c:141:12: warning: ‘xen_cpu_up_prepare’ used but never defined arch/x86/xen/enlighten.c:142:12: warning: ‘xen_cpu_up_online’ used but never defined arch/x86/xen/enlighten.c:143:12: warning: ‘xen_cpu_dead’ used but never defined Fixes: 4d737042d6c4 ("xen/x86: Convert to hotplug state machine") Signed-off-by: Arnd Bergmann Signed-off-by: David Vrabel --- arch/x86/xen/enlighten.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 96c2dea798a1d..a637f902f59ed 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1838,6 +1838,7 @@ static void __init init_hvm_pv_info(void) xen_domain_type = XEN_HVM_DOMAIN; } +#endif static int xen_cpu_up_prepare(unsigned int cpu) { @@ -1888,6 +1889,7 @@ static int xen_cpu_up_online(unsigned int cpu) return 0; } +#ifdef CONFIG_XEN_PVHVM #ifdef CONFIG_KEXEC_CORE static void xen_hvm_shutdown(void) { -- GitLab From e1e5b3ff41983f506c3cbcf123fe7d682f61a8f1 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 24 Oct 2016 09:03:49 -0600 Subject: [PATCH 0972/1167] xenbus: prefer list_for_each() This is more efficient than list_for_each_safe() when list modification is accompanied by breaking out of the loop. Signed-off-by: Jan Beulich Reviewed-by: Juergen Gross Signed-off-by: David Vrabel --- drivers/xen/xenbus/xenbus_dev_frontend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c index 7487971f9f788..fe60b12de9204 100644 --- a/drivers/xen/xenbus/xenbus_dev_frontend.c +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c @@ -364,7 +364,7 @@ static int xenbus_write_transaction(unsigned msg_type, static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u) { - struct watch_adapter *watch, *tmp_watch; + struct watch_adapter *watch; char *path, *token; int err, rc; LIST_HEAD(staging_q); @@ -399,7 +399,7 @@ static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u) } list_add(&watch->list, &u->watches); } else { - list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) { + list_for_each_entry(watch, &u->watches, list) { if (!strcmp(watch->token, token) && !strcmp(watch->watch.node, path)) { unregister_xenbus_watch(&watch->watch); -- GitLab From c251f15c7dbf2cb72e7b2b282020b41f4e4d3665 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 24 Oct 2016 09:05:18 -0600 Subject: [PATCH 0973/1167] xenbus: check return value of xenbus_scanf() Don't ignore errors here: Set backend state to unknown when unsuccessful. Signed-off-by: Jan Beulich Signed-off-by: David Vrabel --- drivers/xen/xenbus/xenbus_probe_frontend.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 611a231196757..6d40a972ffb24 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -335,7 +335,9 @@ static int backend_state; static void xenbus_reset_backend_state_changed(struct xenbus_watch *w, const char **v, unsigned int l) { - xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i", &backend_state); + if (xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i", + &backend_state) != 1) + backend_state = XenbusStateUnknown; printk(KERN_DEBUG "XENBUS: backend %s %s\n", v[XS_WATCH_PATH], xenbus_strstate(backend_state)); wake_up(&backend_state_wq); -- GitLab From dafa724bf582181d9a7d54f5cb4ca0bf8ef29269 Mon Sep 17 00:00:00 2001 From: "tang.junhui" Date: Fri, 21 Oct 2016 09:35:32 +0800 Subject: [PATCH 0974/1167] dm table: fix missing dm_put_target_type() in dm_table_add_target() dm_get_target_type() was previously called so any error returned from dm_table_add_target() must first call dm_put_target_type(). Otherwise the DM target module's reference count will leak and the associated kernel module will be unable to be removed. Also, leverage the fact that r is already -EINVAL and remove an extra newline. Fixes: 36a0456 ("dm table: add immutable feature") Fixes: cc6cbe1 ("dm table: add always writeable feature") Fixes: 3791e2f ("dm table: add singleton feature") Cc: stable@vger.kernel.org # 3.2+ Signed-off-by: tang.junhui Signed-off-by: Mike Snitzer --- drivers/md/dm-table.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 3e407a9cde1f1..c4b53b332607b 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -695,37 +695,32 @@ int dm_table_add_target(struct dm_table *t, const char *type, tgt->type = dm_get_target_type(type); if (!tgt->type) { - DMERR("%s: %s: unknown target type", dm_device_name(t->md), - type); + DMERR("%s: %s: unknown target type", dm_device_name(t->md), type); return -EINVAL; } if (dm_target_needs_singleton(tgt->type)) { if (t->num_targets) { - DMERR("%s: target type %s must appear alone in table", - dm_device_name(t->md), type); - return -EINVAL; + tgt->error = "singleton target type must appear alone in table"; + goto bad; } t->singleton = true; } if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) { - DMERR("%s: target type %s may not be included in read-only tables", - dm_device_name(t->md), type); - return -EINVAL; + tgt->error = "target type may not be included in a read-only table"; + goto bad; } if (t->immutable_target_type) { if (t->immutable_target_type != tgt->type) { - DMERR("%s: immutable target type %s cannot be mixed with other target types", - dm_device_name(t->md), t->immutable_target_type->name); - return -EINVAL; + tgt->error = "immutable target type cannot be mixed with other target types"; + goto bad; } } else if (dm_target_is_immutable(tgt->type)) { if (t->num_targets) { - DMERR("%s: immutable target type %s cannot be mixed with other target types", - dm_device_name(t->md), tgt->type->name); - return -EINVAL; + tgt->error = "immutable target type cannot be mixed with other target types"; + goto bad; } t->immutable_target_type = tgt->type; } @@ -740,7 +735,6 @@ int dm_table_add_target(struct dm_table *t, const char *type, */ if (!adjoin(t, tgt)) { tgt->error = "Gap in table"; - r = -EINVAL; goto bad; } -- GitLab From 91e040a79df73d371f70792f30380d4e44805250 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 20 Oct 2016 07:39:45 -0700 Subject: [PATCH 0975/1167] ARC: syscall for userspace cmpxchg assist Older ARC700 cores (ARC750 specifically) lack instructions to implement atomic r-w-w. This is problematic for userspace libraries such as NPTL which need atomic primitives. So enable them by providing kernel assist. This is costly but really the only sane soluton (othern than tight spinning using the otherwise availiable atomic exchange EX instruciton). Good thing is there are only a few of these cores running Linux out in the wild. This only works on UP systems. Reviewed-by: Colin Ian King Signed-off-by: Vineet Gupta --- arch/arc/include/asm/syscalls.h | 1 + arch/arc/include/uapi/asm/unistd.h | 9 ++++---- arch/arc/kernel/process.c | 33 ++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/arch/arc/include/asm/syscalls.h b/arch/arc/include/asm/syscalls.h index e56f9fcc55813..772b67ca56e7b 100644 --- a/arch/arc/include/asm/syscalls.h +++ b/arch/arc/include/asm/syscalls.h @@ -17,6 +17,7 @@ int sys_clone_wrapper(int, int, int, int, int); int sys_cacheflush(uint32_t, uint32_t uint32_t); int sys_arc_settls(void *); int sys_arc_gettls(void); +int sys_arc_usr_cmpxchg(int *, int, int); #include diff --git a/arch/arc/include/uapi/asm/unistd.h b/arch/arc/include/uapi/asm/unistd.h index 41fa2ec9e02c7..9a34136d84b2c 100644 --- a/arch/arc/include/uapi/asm/unistd.h +++ b/arch/arc/include/uapi/asm/unistd.h @@ -27,18 +27,19 @@ #define NR_syscalls __NR_syscalls +/* Generic syscall (fs/filesystems.c - lost in asm-generic/unistd.h */ +#define __NR_sysfs (__NR_arch_specific_syscall + 3) + /* ARC specific syscall */ #define __NR_cacheflush (__NR_arch_specific_syscall + 0) #define __NR_arc_settls (__NR_arch_specific_syscall + 1) #define __NR_arc_gettls (__NR_arch_specific_syscall + 2) +#define __NR_arc_usr_cmpxchg (__NR_arch_specific_syscall + 4) __SYSCALL(__NR_cacheflush, sys_cacheflush) __SYSCALL(__NR_arc_settls, sys_arc_settls) __SYSCALL(__NR_arc_gettls, sys_arc_gettls) - - -/* Generic syscall (fs/filesystems.c - lost in asm-generic/unistd.h */ -#define __NR_sysfs (__NR_arch_specific_syscall + 3) +__SYSCALL(__NR_arc_usr_cmpxchg, sys_arc_usr_cmpxchg) __SYSCALL(__NR_sysfs, sys_sysfs) #undef __SYSCALL diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index be1972bd2729e..59aa43cb146e7 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -41,6 +41,39 @@ SYSCALL_DEFINE0(arc_gettls) return task_thread_info(current)->thr_ptr; } +SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new) +{ + int uval; + int ret; + + /* + * This is only for old cores lacking LLOCK/SCOND, which by defintion + * can't possibly be SMP. Thus doesn't need to be SMP safe. + * And this also helps reduce the overhead for serializing in + * the UP case + */ + WARN_ON_ONCE(IS_ENABLED(CONFIG_SMP)); + + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) + return -EFAULT; + + preempt_disable(); + + ret = __get_user(uval, uaddr); + if (ret) + goto done; + + if (uval != expected) + ret = -EAGAIN; + else + ret = __put_user(new, uaddr); + +done: + preempt_enable(); + + return ret; +} + void arch_cpu_idle(void) { /* sleep, but enable all interrupts before committing */ -- GitLab From cf986d470208fbdd68b6934a86ccd81c04408484 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 13 Oct 2016 15:58:59 -0700 Subject: [PATCH 0976/1167] ARCv2: IOC: use @ioc_enable not @ioc_exist where intended if user disables IOC from debugger at startup (by clearing @ioc_enable), @ioc_exists is cleared too. This means boot prints don't capture the fact that IOC was present but disabled which could be misleading. So invert how we use @ioc_enable and @ioc_exists and make it more canonical. @ioc_exists represent whether hardware is present or not and stays same whether enabled or not. @ioc_enable is still user driven, but will be auto-disabled if IOC hardware is not present, i.e. if @ioc_exist=0. This is opposite to what we were doing before, but much clearer. This means @ioc_enable is now the "exported" toggle in rest of code such as dma mapping API. Signed-off-by: Vineet Gupta --- arch/arc/include/asm/cache.h | 2 +- arch/arc/mm/cache.c | 10 ++++++---- arch/arc/mm/dma.c | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h index fb781e34f322f..b3410ff6a62db 100644 --- a/arch/arc/include/asm/cache.h +++ b/arch/arc/include/asm/cache.h @@ -53,7 +53,7 @@ extern void arc_cache_init(void); extern char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len); extern void read_decode_cache_bcr(void); -extern int ioc_exists; +extern int ioc_enable; extern unsigned long perip_base, perip_end; #endif /* !__ASSEMBLY__ */ diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c index 97dddbefb86a9..518ff76771f36 100644 --- a/arch/arc/mm/cache.c +++ b/arch/arc/mm/cache.c @@ -22,8 +22,8 @@ #include static int l2_line_sz; -int ioc_exists; -volatile int slc_enable = 1, ioc_enable = 1; +static int ioc_exists; +int slc_enable = 1, ioc_enable = 1; unsigned long perip_base = ARC_UNCACHED_ADDR_SPACE; /* legacy value for boot */ unsigned long perip_end = 0xFFFFFFFF; /* legacy value */ @@ -113,8 +113,10 @@ static void read_decode_cache_bcr_arcv2(int cpu) } READ_BCR(ARC_REG_CLUSTER_BCR, cbcr); - if (cbcr.c && ioc_enable) + if (cbcr.c) ioc_exists = 1; + else + ioc_enable = 0; /* HS 2.0 didn't have AUX_VOL */ if (cpuinfo_arc700[cpu].core.family > 0x51) { @@ -1002,7 +1004,7 @@ void arc_cache_init(void) read_aux_reg(ARC_REG_SLC_CTRL) | SLC_CTRL_DISABLE); } - if (is_isa_arcv2() && ioc_exists) { + if (is_isa_arcv2() && ioc_enable) { /* IO coherency base - 0x8z */ write_aux_reg(ARC_REG_IO_COH_AP0_BASE, 0x80000); /* IO coherency aperture size - 512Mb: 0x8z-0xAz */ diff --git a/arch/arc/mm/dma.c b/arch/arc/mm/dma.c index 20afc65e22dc7..60aab5a7522b5 100644 --- a/arch/arc/mm/dma.c +++ b/arch/arc/mm/dma.c @@ -45,7 +45,7 @@ static void *arc_dma_alloc(struct device *dev, size_t size, * -For coherent data, Read/Write to buffers terminate early in cache * (vs. always going to memory - thus are faster) */ - if ((is_isa_arcv2() && ioc_exists) || + if ((is_isa_arcv2() && ioc_enable) || (attrs & DMA_ATTR_NON_CONSISTENT)) need_coh = 0; @@ -97,7 +97,7 @@ static void arc_dma_free(struct device *dev, size_t size, void *vaddr, int is_non_coh = 1; is_non_coh = (attrs & DMA_ATTR_NON_CONSISTENT) || - (is_isa_arcv2() && ioc_exists); + (is_isa_arcv2() && ioc_enable); if (PageHighMem(page) || !is_non_coh) iounmap((void __force __iomem *)vaddr); -- GitLab From 0a3ffab93fe52530602fe47cd74802cffdb19c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Mon, 24 Oct 2016 15:20:29 +0200 Subject: [PATCH 0977/1167] ANDROID: binder: Add strong ref checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevent using a binder_ref with only weak references where a strong reference is required. Signed-off-by: Arve Hjønnevåg Signed-off-by: Martijn Coenen Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 562af94bec357..3681759c22d72 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1002,7 +1002,7 @@ static int binder_dec_node(struct binder_node *node, int strong, int internal) static struct binder_ref *binder_get_ref(struct binder_proc *proc, - uint32_t desc) + u32 desc, bool need_strong_ref) { struct rb_node *n = proc->refs_by_desc.rb_node; struct binder_ref *ref; @@ -1010,12 +1010,16 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc, while (n) { ref = rb_entry(n, struct binder_ref, rb_node_desc); - if (desc < ref->desc) + if (desc < ref->desc) { n = n->rb_left; - else if (desc > ref->desc) + } else if (desc > ref->desc) { n = n->rb_right; - else + } else if (need_strong_ref && !ref->strong) { + binder_user_error("tried to use weak ref as strong ref\n"); + return NULL; + } else { return ref; + } } return NULL; } @@ -1285,7 +1289,10 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { - struct binder_ref *ref = binder_get_ref(proc, fp->handle); + struct binder_ref *ref; + + ref = binder_get_ref(proc, fp->handle, + fp->type == BINDER_TYPE_HANDLE); if (ref == NULL) { pr_err("transaction release %d bad handle %d\n", @@ -1380,7 +1387,7 @@ static void binder_transaction(struct binder_proc *proc, if (tr->target.handle) { struct binder_ref *ref; - ref = binder_get_ref(proc, tr->target.handle); + ref = binder_get_ref(proc, tr->target.handle, true); if (ref == NULL) { binder_user_error("%d:%d got transaction to invalid handle\n", proc->pid, thread->pid); @@ -1589,7 +1596,10 @@ static void binder_transaction(struct binder_proc *proc, } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { - struct binder_ref *ref = binder_get_ref(proc, fp->handle); + struct binder_ref *ref; + + ref = binder_get_ref(proc, fp->handle, + fp->type == BINDER_TYPE_HANDLE); if (ref == NULL) { binder_user_error("%d:%d got transaction with invalid handle, %d\n", @@ -1800,7 +1810,9 @@ static int binder_thread_write(struct binder_proc *proc, ref->desc); } } else - ref = binder_get_ref(proc, target); + ref = binder_get_ref(proc, target, + cmd == BC_ACQUIRE || + cmd == BC_RELEASE); if (ref == NULL) { binder_user_error("%d:%d refcount change on invalid ref %d\n", proc->pid, thread->pid, target); @@ -1996,7 +2008,7 @@ static int binder_thread_write(struct binder_proc *proc, if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - ref = binder_get_ref(proc, target); + ref = binder_get_ref(proc, target, false); if (ref == NULL) { binder_user_error("%d:%d %s invalid ref %d\n", proc->pid, thread->pid, -- GitLab From 4afb604e2d14d429ac9e1fd84b952602853b2df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Mon, 24 Oct 2016 15:20:30 +0200 Subject: [PATCH 0978/1167] ANDROID: binder: Clear binder and cookie when setting handle in flat binder struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevents leaking pointers between processes Signed-off-by: Arve Hjønnevåg Signed-off-by: Martijn Coenen Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 3681759c22d72..3c71b982bf2a3 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1584,7 +1584,9 @@ static void binder_transaction(struct binder_proc *proc, fp->type = BINDER_TYPE_HANDLE; else fp->type = BINDER_TYPE_WEAK_HANDLE; + fp->binder = 0; fp->handle = ref->desc; + fp->cookie = 0; binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo); @@ -1634,7 +1636,9 @@ static void binder_transaction(struct binder_proc *proc, return_error = BR_FAILED_REPLY; goto err_binder_get_ref_for_node_failed; } + fp->binder = 0; fp->handle = new_ref->desc; + fp->cookie = 0; binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); trace_binder_transaction_ref_to_ref(t, ref, new_ref); @@ -1688,6 +1692,7 @@ static void binder_transaction(struct binder_proc *proc, binder_debug(BINDER_DEBUG_TRANSACTION, " fd %d -> %d\n", fp->handle, target_fd); /* TODO: fput? */ + fp->binder = 0; fp->handle = target_fd; } break; -- GitLab From 43605e293eb13c07acb546c14f407a271837af17 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Wed, 19 Oct 2016 01:34:48 +0300 Subject: [PATCH 0979/1167] mei: txe: don't clean an unprocessed interrupt cause. SEC registers are not accessible when the TXE device is in low power state, hence the SEC interrupt cannot be processed if device is not awake. In some rare cases entrance to low power state (aliveness off) and input ready bits can be signaled at the same time, resulting in communication stall as input ready won't be signaled again after waking up. To resolve this IPC_HHIER_SEC bit in HHISR_REG should not be cleaned if the interrupt is not processed. Cc: stable@vger.kernel.org Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-txe.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c index e6e5e55a12ed4..60415a2bfcbd4 100644 --- a/drivers/misc/mei/hw-txe.c +++ b/drivers/misc/mei/hw-txe.c @@ -981,11 +981,13 @@ static bool mei_txe_check_and_ack_intrs(struct mei_device *dev, bool do_ack) hisr = mei_txe_br_reg_read(hw, HISR_REG); aliveness = mei_txe_aliveness_get(dev); - if (hhisr & IPC_HHIER_SEC && aliveness) + if (hhisr & IPC_HHIER_SEC && aliveness) { ipc_isr = mei_txe_sec_reg_read_silent(hw, SEC_IPC_HOST_INT_STATUS_REG); - else + } else { ipc_isr = 0; + hhisr &= ~IPC_HHIER_SEC; + } generated = generated || (hisr & HISR_INT_STS_MSK) || -- GitLab From d62a9025aee446994a706c711e45c6a655d9d348 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Fri, 21 Oct 2016 07:33:57 +0300 Subject: [PATCH 0980/1167] orangefs: user file_inode() where it is due Replace wrong use of file->f_path.dentry->d_inode with file_inode(file). In case orangefs ever finds itself as an overelayfs layer, it would want to get its own inode and not overlayfs's inode. DISCLAIMER: I did not test this patch because I do not know how to setup an orangefs mount Signed-off-by: Amir Goldstein Signed-off-by: Mike Marshall --- fs/orangefs/file.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c index 66ea0cc37b189..02cc6139ec907 100644 --- a/fs/orangefs/file.c +++ b/fs/orangefs/file.c @@ -621,9 +621,9 @@ static int orangefs_file_release(struct inode *inode, struct file *file) * readahead cache (if any); this forces an expensive refresh of * data for the next caller of mmap (or 'get_block' accesses) */ - if (file->f_path.dentry->d_inode && - file->f_path.dentry->d_inode->i_mapping && - mapping_nrpages(&file->f_path.dentry->d_inode->i_data)) { + if (file_inode(file) && + file_inode(file)->i_mapping && + mapping_nrpages(&file_inode(file)->i_data)) { if (orangefs_features & ORANGEFS_FEATURE_READAHEAD) { gossip_debug(GOSSIP_INODE_DEBUG, "calling flush_racache on %pU\n", @@ -632,7 +632,7 @@ static int orangefs_file_release(struct inode *inode, struct file *file) gossip_debug(GOSSIP_INODE_DEBUG, "flush_racache finished\n"); } - truncate_inode_pages(file->f_path.dentry->d_inode->i_mapping, + truncate_inode_pages(file_inode(file)->i_mapping, 0); } return 0; @@ -648,7 +648,7 @@ static int orangefs_fsync(struct file *file, { int ret = -EINVAL; struct orangefs_inode_s *orangefs_inode = - ORANGEFS_I(file->f_path.dentry->d_inode); + ORANGEFS_I(file_inode(file)); struct orangefs_kernel_op_s *new_op = NULL; /* required call */ @@ -661,7 +661,7 @@ static int orangefs_fsync(struct file *file, ret = service_operation(new_op, "orangefs_fsync", - get_interruptible_flag(file->f_path.dentry->d_inode)); + get_interruptible_flag(file_inode(file))); gossip_debug(GOSSIP_FILE_DEBUG, "orangefs_fsync got return value of %d\n", @@ -669,7 +669,7 @@ static int orangefs_fsync(struct file *file, op_release(new_op); - orangefs_flush_inode(file->f_path.dentry->d_inode); + orangefs_flush_inode(file_inode(file)); return ret; } -- GitLab From 804b1737d71253f01621d2a37a0dce6279a2d440 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 17 Oct 2016 10:14:23 +0200 Subject: [PATCH 0981/1167] orangefs: don't use d_time Instead use d_fsdata which is the same size. Hoping to get rid of d_time, which is used by very few filesystems by this time. Signed-off-by: Miklos Szeredi Reviewed-by: Martin Brandenburg Signed-off-by: Mike Marshall --- fs/orangefs/dcache.c | 5 +++-- fs/orangefs/namei.c | 8 ++++---- fs/orangefs/orangefs-kernel.h | 7 +++++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/fs/orangefs/dcache.c b/fs/orangefs/dcache.c index 1e8fe844e69fd..5355efba4bc8c 100644 --- a/fs/orangefs/dcache.c +++ b/fs/orangefs/dcache.c @@ -73,7 +73,7 @@ static int orangefs_revalidate_lookup(struct dentry *dentry) } } - dentry->d_time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000; + orangefs_set_timeout(dentry); ret = 1; out_release_op: op_release(new_op); @@ -94,8 +94,9 @@ static int orangefs_revalidate_lookup(struct dentry *dentry) static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags) { int ret; + unsigned long time = (unsigned long) dentry->d_fsdata; - if (time_before(jiffies, dentry->d_time)) + if (time_before(jiffies, time)) return 1; if (flags & LOOKUP_RCU) diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c index d15d3d2dba622..a290ff6ec7569 100644 --- a/fs/orangefs/namei.c +++ b/fs/orangefs/namei.c @@ -72,7 +72,7 @@ static int orangefs_create(struct inode *dir, d_instantiate(dentry, inode); unlock_new_inode(inode); - dentry->d_time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000; + orangefs_set_timeout(dentry); ORANGEFS_I(inode)->getattr_time = jiffies - 1; gossip_debug(GOSSIP_NAME_DEBUG, @@ -183,7 +183,7 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry, goto out; } - dentry->d_time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000; + orangefs_set_timeout(dentry); inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn); if (IS_ERR(inode)) { @@ -322,7 +322,7 @@ static int orangefs_symlink(struct inode *dir, d_instantiate(dentry, inode); unlock_new_inode(inode); - dentry->d_time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000; + orangefs_set_timeout(dentry); ORANGEFS_I(inode)->getattr_time = jiffies - 1; gossip_debug(GOSSIP_NAME_DEBUG, @@ -386,7 +386,7 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode d_instantiate(dentry, inode); unlock_new_inode(inode); - dentry->d_time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000; + orangefs_set_timeout(dentry); ORANGEFS_I(inode)->getattr_time = jiffies - 1; gossip_debug(GOSSIP_NAME_DEBUG, diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h index 0a82048f3aafa..3bf803d732c5b 100644 --- a/fs/orangefs/orangefs-kernel.h +++ b/fs/orangefs/orangefs-kernel.h @@ -580,4 +580,11 @@ static inline void orangefs_i_size_write(struct inode *inode, loff_t i_size) #endif } +static inline void orangefs_set_timeout(struct dentry *dentry) +{ + unsigned long time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000; + + dentry->d_fsdata = (void *) time; +} + #endif /* __ORANGEFSKERNEL_H */ -- GitLab From 423221d1745b53656db896bd34646d09d620c759 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 24 Oct 2016 15:13:25 -0400 Subject: [PATCH 0982/1167] nbd: fix incorrect unlock of nbd->sock_lock in sock_shutdown Commit 0eadf37afc250 ("nbd: allow block mq to deal with timeouts") changed normal usage of nbd->sock_lock to use spin_lock/spin_unlock rather than the *_irq variants, but it missed this unlock in an error path. Found by Coverity, CID 1373871. Signed-off-by: John W. Linville Cc: Josef Bacik Cc: Jens Axboe Cc: Markus Pargmann Fixes: 0eadf37afc250 ("nbd: allow block mq to deal with timeouts") Signed-off-by: Jens Axboe --- drivers/block/nbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index ba405b55329fb..19a16b2dbb917 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -164,7 +164,7 @@ static void sock_shutdown(struct nbd_device *nbd) spin_lock(&nbd->sock_lock); if (!nbd->sock) { - spin_unlock_irq(&nbd->sock_lock); + spin_unlock(&nbd->sock_lock); return; } -- GitLab From 2f1d407adab026b34a105ed27b1d4d7e910c4448 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 24 Oct 2016 23:20:25 +0200 Subject: [PATCH 0983/1167] cpufreq: intel_pstate: Always set max P-state in performance mode The only times at which intel_pstate checks the policy set for a given CPU is the initialization of that CPU and updates of its policy settings from cpufreq when intel_pstate_set_policy() is invoked. That is insufficient, however, because intel_pstate uses the same P-state selection function for all CPUs regardless of the policy setting for each of them and the P-state limits are shared between them. Thus if the policy is set to "performance" for a particular CPU, it may not behave as expected if the cpufreq settings are changed subsequently for another CPU. That can be easily demonstrated by writing "performance" to scaling_governor for all CPUs and then switching it to "powersave" for one of them in which case all of the CPUs will behave as though their scaling_governor were all "powersave" (even though the policy still appears to be "performance" for the remaining CPUs). Fix this problem by modifying intel_pstate_adjust_busy_pstate() to always set the P-state to the maximum allowed by the current limits for all CPUs whose policy is set to "performance". Note that it still is recommended to always change the policy setting in the same way for all CPUs even with this fix applied to avoid confusion. Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index ac7c58d20b589..4737520ec8230 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -179,6 +179,7 @@ struct _pid { /** * struct cpudata - Per CPU instance data storage * @cpu: CPU number for this instance data + * @policy: CPUFreq policy value * @update_util: CPUFreq utility callback information * @update_util_set: CPUFreq utility callback is set * @iowait_boost: iowait-related boost fraction @@ -201,6 +202,7 @@ struct _pid { struct cpudata { int cpu; + unsigned int policy; struct update_util_data update_util; bool update_util_set; @@ -1337,7 +1339,8 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) from = cpu->pstate.current_pstate; - target_pstate = pstate_funcs.get_target_pstate(cpu); + target_pstate = cpu->policy == CPUFREQ_POLICY_PERFORMANCE ? + cpu->pstate.turbo_pstate : pstate_funcs.get_target_pstate(cpu); intel_pstate_update_pstate(cpu, target_pstate); @@ -1504,6 +1507,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) policy->cpuinfo.max_freq, policy->max); cpu = all_cpu_data[policy->cpu]; + cpu->policy = policy->policy; + if (cpu->pstate.max_pstate_physical > cpu->pstate.max_pstate && policy->max < policy->cpuinfo.max_freq && policy->max > cpu->pstate.max_pstate * cpu->pstate.scaling) { @@ -1511,7 +1516,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) policy->max = policy->cpuinfo.max_freq; } - if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { + if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) { limits = &performance_limits; if (policy->max >= policy->cpuinfo.max_freq) { pr_debug("set performance\n"); @@ -1547,7 +1552,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) limits->max_perf = round_up(limits->max_perf, FRAC_BITS); out: - if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { + if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) { /* * NOHZ_FULL CPUs need this as the governor callback may not * be invoked on them. -- GitLab From 272ddc8b37354c3fe111ab26d25e792629148eee Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 24 Oct 2016 19:00:44 -0700 Subject: [PATCH 0984/1167] proc: don't use FOLL_FORCE for reading cmdline and environment Now that Lorenzo cleaned things up and made the FOLL_FORCE users explicit, it becomes obvious how some of them don't really need FOLL_FORCE at all. So remove FOLL_FORCE from the proc code that reads the command line and arguments from user space. The mem_rw() function actually does want FOLL_FORCE, because gdd (and possibly many other debuggers) use it as a much more convenient version of PTRACE_PEEKDATA, but we should consider making the FOLL_FORCE part conditional on actually being a ptracer. This does not actually do that, just moves adds a comment to that effect and moves the gup_flags settings next to each other. Signed-off-by: Linus Torvalds --- fs/proc/base.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 8e654468ab676..adfc5b4986f53 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -252,7 +252,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, * Inherently racy -- command line shares address space * with code and data. */ - rv = access_remote_vm(mm, arg_end - 1, &c, 1, FOLL_FORCE); + rv = access_remote_vm(mm, arg_end - 1, &c, 1, 0); if (rv <= 0) goto out_free_page; @@ -270,8 +270,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, int nr_read; _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, - FOLL_FORCE); + nr_read = access_remote_vm(mm, p, page, _count, 0); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) @@ -306,8 +305,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, bool final; _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, - FOLL_FORCE); + nr_read = access_remote_vm(mm, p, page, _count, 0); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) @@ -356,8 +354,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, bool final; _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, - FOLL_FORCE); + nr_read = access_remote_vm(mm, p, page, _count, 0); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) @@ -835,7 +832,7 @@ static ssize_t mem_rw(struct file *file, char __user *buf, unsigned long addr = *ppos; ssize_t copied; char *page; - unsigned int flags = FOLL_FORCE; + unsigned int flags; if (!mm) return 0; @@ -848,6 +845,8 @@ static ssize_t mem_rw(struct file *file, char __user *buf, if (!atomic_inc_not_zero(&mm->mm_users)) goto free; + /* Maybe we should limit FOLL_FORCE to actual ptrace users? */ + flags = FOLL_FORCE; if (write) flags |= FOLL_WRITE; @@ -971,8 +970,7 @@ static ssize_t environ_read(struct file *file, char __user *buf, max_len = min_t(size_t, PAGE_SIZE, count); this_len = min(max_len, this_len); - retval = access_remote_vm(mm, (env_start + src), - page, this_len, FOLL_FORCE); + retval = access_remote_vm(mm, (env_start + src), page, this_len, 0); if (retval <= 0) { ret = retval; -- GitLab From 0d7317598214134d73da59990b846481a9527a00 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Mon, 24 Oct 2016 10:57:25 +0100 Subject: [PATCH 0985/1167] mm: unexport __get_user_pages() This patch unexports the low-level __get_user_pages() function. Recent refactoring of the get_user_pages* functions allow flags to be passed through get_user_pages() which eliminates the need for access to this function from its one user, kvm. We can see that the two calls to get_user_pages() which replace __get_user_pages() in kvm_main.c are equivalent by examining their call stacks: get_user_page_nowait(): get_user_pages(start, 1, flags, page, NULL) __get_user_pages_locked(current, current->mm, start, 1, page, NULL, NULL, false, flags | FOLL_TOUCH) __get_user_pages(current, current->mm, start, 1, flags | FOLL_TOUCH | FOLL_GET, page, NULL, NULL) check_user_page_hwpoison(): get_user_pages(addr, 1, flags, NULL, NULL) __get_user_pages_locked(current, current->mm, addr, 1, NULL, NULL, NULL, false, flags | FOLL_TOUCH) __get_user_pages(current, current->mm, addr, 1, flags | FOLL_TOUCH, NULL, NULL, NULL) Signed-off-by: Lorenzo Stoakes Acked-by: Paolo Bonzini Acked-by: Michal Hocko Signed-off-by: Linus Torvalds --- include/linux/mm.h | 4 ---- mm/gup.c | 3 +-- mm/nommu.c | 2 +- virt/kvm/kvm_main.c | 10 ++++------ 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 3a191853faaae..a92c8d73aeafc 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1271,10 +1271,6 @@ extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void * extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, int len, unsigned int gup_flags); -long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, - unsigned long start, unsigned long nr_pages, - unsigned int foll_flags, struct page **pages, - struct vm_area_struct **vmas, int *nonblocking); long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, diff --git a/mm/gup.c b/mm/gup.c index 7aa113c2d3731..ec4f82704b6f3 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -526,7 +526,7 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags) * instead of __get_user_pages. __get_user_pages should be used only if * you need some special @gup_flags. */ -long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, +static long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas, int *nonblocking) @@ -631,7 +631,6 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, } while (nr_pages); return i; } -EXPORT_SYMBOL(__get_user_pages); bool vma_permits_fault(struct vm_area_struct *vma, unsigned int fault_flags) { diff --git a/mm/nommu.c b/mm/nommu.c index db5fd17952987..8b8faaf2a9e95 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -109,7 +109,7 @@ unsigned int kobjsize(const void *objp) return PAGE_SIZE << compound_order(page); } -long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, +static long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, unsigned int foll_flags, struct page **pages, struct vm_area_struct **vmas, int *nonblocking) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 28510e72618a0..2907b7b786545 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1346,21 +1346,19 @@ unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *w static int get_user_page_nowait(unsigned long start, int write, struct page **page) { - int flags = FOLL_TOUCH | FOLL_NOWAIT | FOLL_HWPOISON | FOLL_GET; + int flags = FOLL_NOWAIT | FOLL_HWPOISON; if (write) flags |= FOLL_WRITE; - return __get_user_pages(current, current->mm, start, 1, flags, page, - NULL, NULL); + return get_user_pages(start, 1, flags, page, NULL); } static inline int check_user_page_hwpoison(unsigned long addr) { - int rc, flags = FOLL_TOUCH | FOLL_HWPOISON | FOLL_WRITE; + int rc, flags = FOLL_HWPOISON | FOLL_WRITE; - rc = __get_user_pages(current, current->mm, addr, 1, - flags, NULL, NULL, NULL); + rc = get_user_pages(addr, 1, flags, NULL, NULL); return rc == -EHWPOISON; } -- GitLab From 407a3aee6ee2d2cb46d9ba3fc380bc29f35d020c Mon Sep 17 00:00:00 2001 From: Long Li Date: Wed, 5 Oct 2016 16:57:46 -0700 Subject: [PATCH 0986/1167] hv: do not lose pending heartbeat vmbus packets The host keeps sending heartbeat packets independent of the guest responding to them. Even though we respond to the heartbeat messages at interrupt level, we can have situations where there maybe multiple heartbeat messages pending that have not been responded to. For instance this occurs when the VM is paused and the host continues to send the heartbeat messages. Address this issue by draining and responding to all the heartbeat messages that maybe pending. Signed-off-by: Long Li Signed-off-by: K. Y. Srinivasan CC: Stable Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_util.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 4aa3cb63fd41f..bcd06306f3e89 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c @@ -314,10 +314,14 @@ static void heartbeat_onchannelcallback(void *context) u8 *hbeat_txf_buf = util_heartbeat.recv_buffer; struct icmsg_negotiate *negop = NULL; - vmbus_recvpacket(channel, hbeat_txf_buf, - PAGE_SIZE, &recvlen, &requestid); + while (1) { + + vmbus_recvpacket(channel, hbeat_txf_buf, + PAGE_SIZE, &recvlen, &requestid); + + if (!recvlen) + break; - if (recvlen > 0) { icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[ sizeof(struct vmbuspipe_hdr)]; -- GitLab From 1a3f099101b85cc93d864eb030d97e7725c72ea7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Oct 2016 12:14:51 +0200 Subject: [PATCH 0987/1167] ALSA: hda - Fix surround output pins for ASRock B150M mobo ASRock B150M Pro4/D3 mobo with ALC892 codec doesn't seem to provide proper pins for the surround outputs, hence we need to specify the pincfgs manually with a couple of other corrections. Reported-and-tested-by: Benjamin Valentin Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b582d57fe184b..2f909dd8b7b85 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6625,6 +6625,7 @@ enum { ALC891_FIXUP_HEADSET_MODE, ALC891_FIXUP_DELL_MIC_NO_PRESENCE, ALC662_FIXUP_ACER_VERITON, + ALC892_FIXUP_ASROCK_MOBO, }; static const struct hda_fixup alc662_fixups[] = { @@ -6901,6 +6902,16 @@ static const struct hda_fixup alc662_fixups[] = { { } } }, + [ALC892_FIXUP_ASROCK_MOBO] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x40f000f0 }, /* disabled */ + { 0x16, 0x40f000f0 }, /* disabled */ + { 0x18, 0x01014011 }, /* LO */ + { 0x1a, 0x01014012 }, /* LO */ + { } + } + }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { @@ -6938,6 +6949,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), + SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO), SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68), SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON), SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), -- GitLab From 991d5add50a5bb6ab8f12f2129f5c7487f6baaf6 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 10 Sep 2016 12:53:21 +0000 Subject: [PATCH 0988/1167] usb: chipidea: host: fix NULL ptr dereference during shutdown After commit b09b5224fe86 ("usb: chipidea: implement platform shutdown callback") and commit 43a404577a93 ("usb: chipidea: host: set host to be null after hcd is freed") a NULL pointer dereference is caused on i.MX23 during shutdown. So ensure that role is set to CI_ROLE_END and we finish interrupt handling before the hcd is deallocated. This avoids the NULL pointer dereference. Suggested-by: Alan Stern Signed-off-by: Stefan Wahren Fixes: b09b5224fe86 ("usb: chipidea: implement platform shutdown callback") Signed-off-by: Peter Chen --- drivers/usb/chipidea/host.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 96ae69502c86f..111b0e0b8698b 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -188,6 +188,8 @@ static void host_stop(struct ci_hdrc *ci) if (hcd) { usb_remove_hcd(hcd); + ci->role = CI_ROLE_END; + synchronize_irq(ci->irq); usb_put_hcd(hcd); if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci) && (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON)) -- GitLab From ae824f00241f495e8d55ebdc0341f3ce61a77da6 Mon Sep 17 00:00:00 2001 From: Ruqiang Ju Date: Mon, 24 Oct 2016 16:39:49 +0800 Subject: [PATCH 0989/1167] i2c: hix5hd2: allow build with ARCH_HISI This driver should be buildable with ARCH_HISI, because some of other HiSilicon SoCs also use it. Signed-off-by: Ruqiang Ju Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 6d94e2ec5b4f7..41abb20f082d7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -79,12 +79,12 @@ config I2C_AMD8111 config I2C_HIX5HD2 tristate "Hix5hd2 high-speed I2C driver" - depends on ARCH_HIX5HD2 || COMPILE_TEST + depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST help - Say Y here to include support for high-speed I2C controller in the - Hisilicon based hix5hd2 SoCs. + Say Y here to include support for the high-speed I2C controller + used in HiSilicon hix5hd2 SoCs. - This driver can also be built as a module. If so, the module + This driver can also be built as a module. If so, the module will be called i2c-hix5hd2. config I2C_I801 -- GitLab From 399c168ab5ab5e12ed55b6c91d61c24eb84c9164 Mon Sep 17 00:00:00 2001 From: David Wu Date: Sat, 22 Oct 2016 16:43:42 +0800 Subject: [PATCH 0990/1167] i2c: rk3x: Give the tuning value 0 during rk3x_i2c_v0_calc_timings We found a bug that i2c transfer sometimes failed on 3066a board with stabel-4.8, the con register would be updated by uninitialized tuning value, it made the i2c transfer failed. So give the tuning value to be zero during rk3x_i2c_v0_calc_timings. Signed-off-by: David Wu Tested-by: Andy Yan Reviewed-by: Douglas Anderson Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/busses/i2c-rk3x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 50702c7bb244b..df220666d6274 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -694,6 +694,8 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate, t_calc->div_low--; t_calc->div_high--; + /* Give the tuning value 0, that would not update con register */ + t_calc->tuning = 0; /* Maximum divider supported by hw is 0xffff */ if (t_calc->div_low > 0xffff) { t_calc->div_low = 0xffff; -- GitLab From 7fbe6ac02485504b964b283aca62b36b4313ca79 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Mon, 24 Oct 2016 08:31:27 -0500 Subject: [PATCH 0991/1167] x86/unwind: Fix empty stack dereference in guess unwinder Vince Waver reported the following bug: WARNING: CPU: 0 PID: 21338 at arch/x86/mm/fault.c:435 vmalloc_fault+0x58/0x1f0 CPU: 0 PID: 21338 Comm: perf_fuzzer Not tainted 4.8.0+ #37 Hardware name: Hewlett-Packard HP Compaq Pro 6305 SFF/1850, BIOS K06 v02.57 08/16/2013 Call Trace: ? dump_stack+0x46/0x59 ? __warn+0xd5/0xee ? vmalloc_fault+0x58/0x1f0 ? __do_page_fault+0x6d/0x48e ? perf_log_throttle+0xa4/0xf4 ? trace_page_fault+0x22/0x30 ? __unwind_start+0x28/0x42 ? perf_callchain_kernel+0x75/0xac ? get_perf_callchain+0x13a/0x1f0 ? perf_callchain+0x6a/0x6c ? perf_prepare_sample+0x71/0x2eb ? perf_event_output_forward+0x1a/0x54 ? __default_send_IPI_shortcut+0x10/0x2d ? __perf_event_overflow+0xfb/0x167 ? x86_pmu_handle_irq+0x113/0x150 ? native_read_msr+0x6/0x34 ? perf_event_nmi_handler+0x22/0x39 ? perf_ibs_nmi_handler+0x4a/0x51 ? perf_event_nmi_handler+0x22/0x39 ? nmi_handle+0x4d/0xf0 ? perf_ibs_handle_irq+0x3d1/0x3d1 ? default_do_nmi+0x3c/0xd5 ? do_nmi+0x92/0x102 ? end_repeat_nmi+0x1a/0x1e ? entry_SYSCALL_64_after_swapgs+0x12/0x4a ? entry_SYSCALL_64_after_swapgs+0x12/0x4a ? entry_SYSCALL_64_after_swapgs+0x12/0x4a ^A4---[ end trace 632723104d47d31a ]--- BUG: stack guard page was hit at ffffc90008500000 (stack is ffffc900084fc000..ffffc900084fffff) kernel stack overflow (page fault): 0000 [#1] SMP ... The NMI hit in the entry code right after setting up the stack pointer from 'cpu_current_top_of_stack', so the kernel stack was empty. The 'guess' version of __unwind_start() attempted to dereference the "top of stack" pointer, which is not actually *on* the stack. Add a check in the guess unwinder to deal with an empty stack. (The frame pointer unwinder already has such a check.) Reported-by: Vince Weaver Signed-off-by: Josh Poimboeuf Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 7c7900f89770 ("x86/unwind: Add new unwind interface and implementations") Link: http://lkml.kernel.org/r/20161024133127.e5evgeebdbohnmpb@treble Signed-off-by: Ingo Molnar --- arch/x86/kernel/unwind_guess.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/unwind_guess.c b/arch/x86/kernel/unwind_guess.c index 9298993dc8b71..2d721e533cf48 100644 --- a/arch/x86/kernel/unwind_guess.c +++ b/arch/x86/kernel/unwind_guess.c @@ -47,7 +47,14 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task, get_stack_info(first_frame, state->task, &state->stack_info, &state->stack_mask); - if (!__kernel_text_address(*first_frame)) + /* + * The caller can provide the address of the first frame directly + * (first_frame) or indirectly (regs->sp) to indicate which stack frame + * to start unwinding at. Skip ahead until we reach it. + */ + if (!unwind_done(state) && + (!on_stack(&state->stack_info, first_frame, sizeof(long)) || + !__kernel_text_address(*first_frame))) unwind_next_frame(state); } EXPORT_SYMBOL_GPL(__unwind_start); -- GitLab From a2209b742e6cf978b85d4f31a25a269c3d3b062b Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 24 Oct 2016 09:00:12 -0600 Subject: [PATCH 0992/1167] x86/build: Fix build with older GCC versions Older GCC (observed with 4.1.x) doesn't support -Wno-override-init and also doesn't ignore unknown -Wno-* options. Signed-off-by: Jan Beulich Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Valdis Kletnieks Cc: Valdis.Kletnieks@vt.edu Fixes: 5e44258d16 "x86/build: Reduce the W=1 warnings noise when compiling x86 syscall tables" Link: http://lkml.kernel.org/r/580E3E1C02000078001191C4@prv-mh.provo.novell.com Signed-off-by: Ingo Molnar --- arch/x86/entry/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/entry/Makefile b/arch/x86/entry/Makefile index 77f28ce9c6464..9976fcecd17ed 100644 --- a/arch/x86/entry/Makefile +++ b/arch/x86/entry/Makefile @@ -5,8 +5,8 @@ OBJECT_FILES_NON_STANDARD_entry_$(BITS).o := y OBJECT_FILES_NON_STANDARD_entry_64_compat.o := y -CFLAGS_syscall_64.o += -Wno-override-init -CFLAGS_syscall_32.o += -Wno-override-init +CFLAGS_syscall_64.o += $(call cc-option,-Wno-override-init,) +CFLAGS_syscall_32.o += $(call cc-option,-Wno-override-init,) obj-y := entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o obj-y += common.o -- GitLab From d320b9a5bd85f6178cc3ed8b0a1a9960f2b5bc7b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 24 Oct 2016 17:33:18 +0200 Subject: [PATCH 0993/1167] x86/quirks: Hide maybe-uninitialized warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc -Wmaybe-uninitialized detects that quirk_intel_brickland_xeon_ras_cap uses uninitialized data when CONFIG_PCI is not set: arch/x86/kernel/quirks.c: In function ‘quirk_intel_brickland_xeon_ras_cap’: arch/x86/kernel/quirks.c:641:13: error: ‘capid0’ is used uninitialized in this function [-Werror=uninitialized] However, the function is also not called in this configuration, so we can avoid the warning by moving the existing #ifdef to cover it as well. Signed-off-by: Arnd Bergmann Cc: Bjorn Helgaas Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Cc: linux-pci@vger.kernel.org Link: http://lkml.kernel.org/r/20161024153325.2752428-1-arnd@arndb.de Signed-off-by: Ingo Molnar --- arch/x86/kernel/quirks.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 51402a7e4ca6e..0bee04d41bed0 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -625,8 +625,6 @@ static void amd_disable_seq_and_redirect_scrub(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3, amd_disable_seq_and_redirect_scrub); -#endif - #if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE) #include #include @@ -657,3 +655,4 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2fc0, quirk_intel_brickland_xeon_ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, quirk_intel_brickland_xeon_ras_cap); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2083, quirk_intel_purley_xeon_ras_cap); #endif +#endif -- GitLab From 6a676fb69dcbf3310b9e462c1db66c8e7f6ead38 Mon Sep 17 00:00:00 2001 From: Ralf Ramsauer Date: Mon, 17 Oct 2016 15:59:57 +0200 Subject: [PATCH 0994/1167] i2c: mark device nodes only in case of successful instantiation Instantiated I2C device nodes are marked with OF_POPULATE. This was introduced in 4f001fd30145a6. On unloading, loaded device nodes will of course be unmarked. The problem are nodes that fail during initialisation: If a node fails, it won't be unloaded and hence not be unmarked. If a I2C driver module is unloaded and reloaded, it will skip nodes that failed before. Skip device nodes that are already populated and mark them only in case of success. Fixes: 4f001fd30145a6 ("i2c: Mark instantiated device nodes with OF_POPULATE") Signed-off-by: Ralf Ramsauer Reviewed-by: Geert Uytterhoeven Acked-by: Pantelis Antoniou [wsa: use 14-digit commit sha] Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/i2c-core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 5ab67219f71e6..1704fc84d6477 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1681,6 +1681,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, static void of_i2c_register_devices(struct i2c_adapter *adap) { struct device_node *bus, *node; + struct i2c_client *client; /* Only register child devices if the adapter has a node pointer set */ if (!adap->dev.of_node) @@ -1695,7 +1696,14 @@ static void of_i2c_register_devices(struct i2c_adapter *adap) for_each_available_child_of_node(bus, node) { if (of_node_test_and_set_flag(node, OF_POPULATED)) continue; - of_i2c_register_device(adap, node); + + client = of_i2c_register_device(adap, node); + if (IS_ERR(client)) { + dev_warn(&adap->dev, + "Failed to create I2C device for %s\n", + node->full_name); + of_node_clear_flag(node, OF_POPULATED); + } } of_node_put(bus); @@ -2299,6 +2307,7 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, if (IS_ERR(client)) { dev_err(&adap->dev, "failed to create client for '%s'\n", rd->dn->full_name); + of_node_clear_flag(rd->dn, OF_POPULATED); return notifier_from_errno(PTR_ERR(client)); } break; -- GitLab From 17791650c356b3cb220946d697d89afc1e32c315 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Mon, 17 Oct 2016 11:54:05 +1000 Subject: [PATCH 0995/1167] i2c: allow configuration of imx driver for ColdFire architecture The i2c controller used by Freescales iMX processors is the same hardware module used on Freescales ColdFire family of processors. We can use the existing i2c-imx driver on ColdFire family members. Modify the configuration to allow it to be selected when compiling for ColdFire targets. Signed-off-by: Greg Ungerer Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 41abb20f082d7..d252276feadf6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -589,10 +589,10 @@ config I2C_IMG config I2C_IMX tristate "IMX I2C interface" - depends on ARCH_MXC || ARCH_LAYERSCAPE + depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE help Say Y here if you want to use the IIC bus controller on - the Freescale i.MX/MXC or Layerscape processors. + the Freescale i.MX/MXC, Layerscape or ColdFire processors. This driver can also be built as a module. If so, the module will be called i2c-imx. -- GitLab From 3855ada848dbdbeae39fcf9eaaf6a7678315f153 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 18 Oct 2016 18:01:45 -0300 Subject: [PATCH 0996/1167] i2c: jz4780: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Signed-off-by: Javier Martinez Canillas Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-jz4780.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index b8ea62105f42c..30132c3957cdc 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -729,6 +729,7 @@ static const struct of_device_id jz4780_i2c_of_matches[] = { { .compatible = "ingenic,jz4780-i2c", }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, jz4780_i2c_of_matches); static int jz4780_i2c_probe(struct platform_device *pdev) { -- GitLab From 06e7b10a8711d10b4c4c21ab1aac3f1529a084df Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 18 Oct 2016 18:01:46 -0300 Subject: [PATCH 0997/1167] i2c: xlp9xx: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Signed-off-by: Javier Martinez Canillas Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 2a972ed7aa0df..e29ff37a43bd6 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -426,6 +426,7 @@ static const struct of_device_id xlp9xx_i2c_of_match[] = { { .compatible = "netlogic,xlp980-i2c", }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = { -- GitLab From 2cb496db3d56baa86d53022044c4d25ffe7fa038 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 18 Oct 2016 18:01:47 -0300 Subject: [PATCH 0998/1167] i2c: xlr: Fix module autoload for OF registration If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Signed-off-by: Javier Martinez Canillas Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c index 0968f59b6df58..ad17d88d85736 100644 --- a/drivers/i2c/busses/i2c-xlr.c +++ b/drivers/i2c/busses/i2c-xlr.c @@ -358,6 +358,7 @@ static const struct of_device_id xlr_i2c_dt_ids[] = { }, { } }; +MODULE_DEVICE_TABLE(of, xlr_i2c_dt_ids); static int xlr_i2c_probe(struct platform_device *pdev) { -- GitLab From 60a951af8e1656e2a17a96d64941aafe0668d750 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 18 Oct 2016 18:01:48 -0300 Subject: [PATCH 0999/1167] i2c: digicolor: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Signed-off-by: Javier Martinez Canillas Acked-by: Baruch Siach Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-digicolor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c index 9604024e0eb09..49f2084f7bb50 100644 --- a/drivers/i2c/busses/i2c-digicolor.c +++ b/drivers/i2c/busses/i2c-digicolor.c @@ -368,6 +368,7 @@ static const struct of_device_id dc_i2c_match[] = { { .compatible = "cnxt,cx92755-i2c" }, { }, }; +MODULE_DEVICE_TABLE(of, dc_i2c_match); static struct platform_driver dc_i2c_driver = { .probe = dc_i2c_probe, -- GitLab From 603616017c35f4d0fbdbcace72adf9bf949c4a65 Mon Sep 17 00:00:00 2001 From: Hoan Tran Date: Mon, 10 Oct 2016 10:13:10 -0700 Subject: [PATCH 1000/1167] i2c: xgene: Avoid dma_buffer overrun SMBus block command uses the first byte of buffer for the data length. The dma_buffer should be increased by 1 to avoid the overrun issue. Reported-by: Phil Endecott Signed-off-by: Hoan Tran Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/busses/i2c-xgene-slimpro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 263685c7a5128..05cf192ef1aca 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -105,7 +105,7 @@ struct slimpro_i2c_dev { struct mbox_chan *mbox_chan; struct mbox_client mbox_client; struct completion rd_complete; - u8 dma_buffer[I2C_SMBUS_BLOCK_MAX]; + u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* dma_buffer[0] is used for length */ u32 *resp_msg; }; -- GitLab From ba9ad2af7019956b990ad654c56da5bac1e8b71b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 11 Oct 2016 13:13:27 +0200 Subject: [PATCH 1001/1167] i2c: i801: Fix I2C Block Read on 8-Series/C220 and later Starting with the 8-Series/C220 PCH (Lynx Point), the SMBus controller includes a SPD EEPROM protection mechanism. Once the SPD Write Disable bit is set, only reads are allowed to slave addresses 0x50-0x57. However the legacy implementation of I2C Block Read since the ICH5 looks like a write, and is therefore blocked by the SPD protection mechanism. This causes the eeprom and at24 drivers to fail. So assume that I2C Block Read is implemented as an actual read on these chipsets. I tested it on my Q87 chipset and it seems to work just fine. Signed-off-by: Jean Delvare Tested-by: Jarkko Nikula [wsa: rebased to v4.9-rc2] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 08847e8b89987..eb3627f35d120 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -146,6 +146,7 @@ #define SMBHSTCFG_HST_EN 1 #define SMBHSTCFG_SMB_SMI_EN 2 #define SMBHSTCFG_I2C_EN 4 +#define SMBHSTCFG_SPD_WD 0x10 /* TCO configuration bits for TCOCTL */ #define TCOCTL_EN 0x0100 @@ -865,9 +866,16 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, block = 1; break; case I2C_SMBUS_I2C_BLOCK_DATA: - /* NB: page 240 of ICH5 datasheet shows that the R/#W - * bit should be cleared here, even when reading */ - outb_p((addr & 0x7f) << 1, SMBHSTADD(priv)); + /* + * NB: page 240 of ICH5 datasheet shows that the R/#W + * bit should be cleared here, even when reading. + * However if SPD Write Disable is set (Lynx Point and later), + * the read will fail if we don't set the R/#W bit. + */ + outb_p(((addr & 0x7f) << 1) | + ((priv->original_hstcfg & SMBHSTCFG_SPD_WD) ? + (read_write & 0x01) : 0), + SMBHSTADD(priv)); if (read_write == I2C_SMBUS_READ) { /* NB: page 240 of ICH5 datasheet also shows * that DATA1 is the cmd field when reading */ @@ -1573,6 +1581,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Disable SMBus interrupt feature if SMBus using SMI# */ priv->features &= ~FEATURE_IRQ; } + if (temp & SMBHSTCFG_SPD_WD) + dev_info(&dev->dev, "SPD Write Disable is set\n"); /* Clear special mode bits */ if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) -- GitLab From 171e23e150acfb285f1772cedf04d35694af740b Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 29 Sep 2016 16:04:59 +0300 Subject: [PATCH 1002/1167] i2c: designware: Avoid aborted transfers with fast reacting I2C slaves I2C DesignWare may abort transfer with arbitration lost if I2C slave pulls SDA down quickly after falling edge of SCL. Reason for this is unknown but after trial and error it was found this can be avoided by enabling non-zero SDA RX hold time for the receiver. By the specification SDA RX hold time extends incoming SDA low to high transition by n * ic_clk cycles but only when SCL is high. However it seems to help avoid above faulty arbitration lost error. Bits 23:16 in IC_SDA_HOLD register define the SDA RX hold time for the receiver. Be conservative and enable 1 ic_clk cycle long hold time in case boot firmware hasn't set it up. Reported-by: Jukka Laitinen Signed-off-by: Jarkko Nikula Tested-by: Jukka Laitinen Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 1fe93c43215cf..11e866d053680 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -95,6 +95,9 @@ #define DW_IC_STATUS_TFE BIT(2) #define DW_IC_STATUS_MST_ACTIVITY BIT(5) +#define DW_IC_SDA_HOLD_RX_SHIFT 16 +#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT) + #define DW_IC_ERR_TX_ABRT 0x1 #define DW_IC_TAR_10BITADDR_MASTER BIT(12) @@ -420,12 +423,20 @@ int i2c_dw_init(struct dw_i2c_dev *dev) /* Configure SDA Hold Time if required */ reg = dw_readl(dev, DW_IC_COMP_VERSION); if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { - if (dev->sda_hold_time) { - dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); - } else { + if (!dev->sda_hold_time) { /* Keep previous hold time setting if no one set it */ dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD); } + /* + * Workaround for avoiding TX arbitration lost in case I2C + * slave pulls SDA down "too quickly" after falling egde of + * SCL by enabling non-zero SDA RX hold. Specification says it + * extends incoming SDA low to high transition while SCL is + * high but it apprears to help also above issue. + */ + if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK)) + dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT; + dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); } else { dev_warn(dev->dev, "Hardware too old to adjust SDA hold time.\n"); -- GitLab From 533169d164c6b4c8571d0d48779f6ff6be593d72 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 26 Sep 2016 17:18:58 -0700 Subject: [PATCH 1003/1167] i2c: imx: defer probe if bus recovery GPIOs are not ready MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some SoC might load the GPIO driver after the I2C driver and using the I2C bus recovery mechanism via GPIOs. In this case it is crucial to defer probing if the GPIO request functions do so, otherwise the I2C driver gets loaded without recovery mechanisms enabled. Signed-off-by: Stefan Agner Acked-by: Uwe Kleine-König Acked-by: Li Yang Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/busses/i2c-imx.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 592a8f26a708d..47fc1f1acff7d 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1009,10 +1009,13 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0); rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0); - if (!gpio_is_valid(rinfo->sda_gpio) || - !gpio_is_valid(rinfo->scl_gpio) || - IS_ERR(i2c_imx->pinctrl_pins_default) || - IS_ERR(i2c_imx->pinctrl_pins_gpio)) { + if (rinfo->sda_gpio == -EPROBE_DEFER || + rinfo->scl_gpio == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (!gpio_is_valid(rinfo->sda_gpio) || + !gpio_is_valid(rinfo->scl_gpio) || + IS_ERR(i2c_imx->pinctrl_pins_default) || + IS_ERR(i2c_imx->pinctrl_pins_gpio)) { dev_dbg(&pdev->dev, "recovery information incomplete\n"); return 0; } -- GitLab From 9b50898ad96c793a8f7cde9d8f281596d752a7dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Oct 2016 15:56:35 +0200 Subject: [PATCH 1004/1167] ALSA: seq: Fix time account regression The recent rewrite of the sequencer time accounting using timespec64 in the commit [3915bf294652: ALSA: seq_timer: use monotonic times internally] introduced a bad regression. Namely, the time reported back doesn't increase but goes back and forth. The culprit was obvious: the delta is stored to the result (cur_time = delta), instead of adding the delta (cur_time += delta)! Let's fix it. Fixes: 3915bf294652 ('ALSA: seq_timer: use monotonic times internally') Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=177571 Reported-by: Yves Guillemot Cc: # v4.8+ Signed-off-by: Takashi Iwai --- sound/core/seq/seq_timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index dcc102813aefa..37d9cfbc29f9c 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -448,8 +448,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) ktime_get_ts64(&tm); tm = timespec64_sub(tm, tmr->last_update); - cur_time.tv_nsec = tm.tv_nsec; - cur_time.tv_sec = tm.tv_sec; + cur_time.tv_nsec += tm.tv_nsec; + cur_time.tv_sec += tm.tv_sec; snd_seq_sanity_real_time(&cur_time); } spin_unlock_irqrestore(&tmr->lock, flags); -- GitLab From b831275a3553c32091222ac619cfddd73a5553fb Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 24 Oct 2016 11:41:56 +0200 Subject: [PATCH 1005/1167] timers: Plug locking race vs. timer migration Linus noticed that lock_timer_base() lacks a READ_ONCE() for accessing the timer flags. As a consequence the compiler is allowed to reload the flags between the initial check for TIMER_MIGRATION and the following timer base computation and the spin lock of the base. While this has not been observed (yet), we need to make sure that it never happens. Fixes: 0eeda71bc30d ("timer: Replace timer base by a cpu index") Reported-by: Linus Torvalds Signed-off-by: Thomas Gleixner Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1610241711220.4983@nanos Cc: stable@vger.kernel.org Cc: Andrew Morton Cc: Peter Zijlstra --- kernel/time/timer.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 2d47980a1bc42..0d4b91c5a3740 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -943,7 +943,14 @@ static struct timer_base *lock_timer_base(struct timer_list *timer, { for (;;) { struct timer_base *base; - u32 tf = timer->flags; + u32 tf; + + /* + * We need to use READ_ONCE() here, otherwise the compiler + * might re-read @tf between the check for TIMER_MIGRATING + * and spin_lock(). + */ + tf = READ_ONCE(timer->flags); if (!(tf & TIMER_MIGRATING)) { base = get_timer_base(tf); -- GitLab From 4da9152a4308dcbf611cde399c695c359fc9145f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 24 Oct 2016 11:55:10 +0200 Subject: [PATCH 1006/1167] timers: Lock base for same bucket optimization Linus stumbled over the unlocked modification of the timer expiry value in mod_timer() which is an optimization for timers which stay in the same bucket - due to the bucket granularity - despite their expiry time getting updated. The optimization itself still makes sense even if we take the lock, because in case that the bucket stays the same, we avoid the pointless queue/enqueue dance. Make the check and the modification of timer->expires protected by the base lock and shuffle the remaining code around so we can keep the lock held when we actually have to requeue the timer to a different bucket. Fixes: f00c0afdfa62 ("timers: Implement optimization for same expiry time in mod_timer()") Reported-by: Linus Torvalds Signed-off-by: Thomas Gleixner Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1610241711220.4983@nanos Cc: stable@vger.kernel.org Cc: Andrew Morton Cc: Peter Zijlstra --- kernel/time/timer.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 0d4b91c5a3740..ccf913038f9f0 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -971,6 +971,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) unsigned long clk = 0, flags; int ret = 0; + BUG_ON(!timer->function); + /* * This is a common optimization triggered by the networking code - if * the timer is re-modified to have the same timeout or ends up in the @@ -979,13 +981,16 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) if (timer_pending(timer)) { if (timer->expires == expires) return 1; + /* - * Take the current timer_jiffies of base, but without holding - * the lock! + * We lock timer base and calculate the bucket index right + * here. If the timer ends up in the same bucket, then we + * just update the expiry time and avoid the whole + * dequeue/enqueue dance. */ - base = get_timer_base(timer->flags); - clk = base->clk; + base = lock_timer_base(timer, &flags); + clk = base->clk; idx = calc_wheel_index(expires, clk); /* @@ -995,14 +1000,14 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) */ if (idx == timer_get_idx(timer)) { timer->expires = expires; - return 1; + ret = 1; + goto out_unlock; } + } else { + base = lock_timer_base(timer, &flags); } timer_stats_timer_set_start_info(timer); - BUG_ON(!timer->function); - - base = lock_timer_base(timer, &flags); ret = detach_if_pending(timer, base, false); if (!ret && pending_only) @@ -1035,9 +1040,10 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) timer->expires = expires; /* * If 'idx' was calculated above and the base time did not advance - * between calculating 'idx' and taking the lock, only enqueue_timer() - * and trigger_dyntick_cpu() is required. Otherwise we need to - * (re)calculate the wheel index via internal_add_timer(). + * between calculating 'idx' and possibly switching the base, only + * enqueue_timer() and trigger_dyntick_cpu() is required. Otherwise + * we need to (re)calculate the wheel index via + * internal_add_timer(). */ if (idx != UINT_MAX && clk == base->clk) { enqueue_timer(base, timer, idx); -- GitLab From 041ad7bc758db259bb960ef795197dd14aab19a6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 22 Oct 2016 11:07:35 +0000 Subject: [PATCH 1007/1167] timers: Prevent base clock rewind when forwarding clock Ashton and Michael reported, that kernel versions 4.8 and later suffer from USB timeouts which are caused by the timer wheel rework. This is caused by a bug in the base clock forwarding mechanism, which leads to timers expiring early. The scenario which leads to this is: run_timers() while (jiffies >= base->clk) { collect_expired_timers(); base->clk++; expire_timers(); } So base->clk = jiffies + 1. Now the cpu goes idle: idle() get_next_timer_interrupt() nextevt = __next_time_interrupt(); if (time_after(nextevt, base->clk)) base->clk = jiffies; jiffies has not advanced since run_timers(), so this assignment effectively decrements base->clk by one. base->clk is the index into the timer wheel arrays. So let's assume the following state after the base->clk increment in run_timers(): jiffies = 0 base->clk = 1 A timer gets enqueued with an expiry delta of 63 ticks (which is the case with the USB timeout and HZ=250) so the resulting bucket index is: base->clk + delta = 1 + 63 = 64 The timer goes into the first wheel level. The array size is 64 so it ends up in bucket 0, which is correct as it takes 63 ticks to advance base->clk to index into bucket 0 again. If the cpu goes idle before jiffies advance, then the bug in the forwarding mechanism sets base->clk back to 0, so the next invocation of run_timers() at the next tick will index into bucket 0 and therefore expire the timer 62 ticks too early. Instead of blindly setting base->clk to jiffies we must make the forwarding conditional on jiffies > base->clk, but we cannot use jiffies for this as we might run into the following issue: if (time_after(jiffies, base->clk) { if (time_after(nextevt, base->clk)) base->clk = jiffies; jiffies can increment between the check and the assigment far enough to advance beyond nextevt. So we need to use a stable value for checking. get_next_timer_interrupt() has the basej argument which is the jiffies value snapshot taken in the calling code. So we can just that. Thanks to Ashton for bisecting and providing trace data! Fixes: a683f390b93f ("timers: Forward the wheel clock whenever possible") Reported-by: Ashton Holmes Reported-by: Michael Thayer Signed-off-by: Thomas Gleixner Cc: Michal Necasek Cc: Peter Zijlstra Cc: knut.osmundsen@oracle.com Cc: stable@vger.kernel.org Cc: stern@rowland.harvard.edu Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20161022110552.175308322@linutronix.de Signed-off-by: Thomas Gleixner --- kernel/time/timer.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index ccf913038f9f0..7c446fb5163a6 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1523,12 +1523,16 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA); base->next_expiry = nextevt; /* - * We have a fresh next event. Check whether we can forward the base: + * We have a fresh next event. Check whether we can forward the + * base. We can only do that when @basej is past base->clk + * otherwise we might rewind base->clk. */ - if (time_after(nextevt, jiffies)) - base->clk = jiffies; - else if (time_after(nextevt, base->clk)) - base->clk = nextevt; + if (time_after(basej, base->clk)) { + if (time_after(nextevt, basej)) + base->clk = basej; + else if (time_after(nextevt, base->clk)) + base->clk = nextevt; + } if (time_before_eq(nextevt, basej)) { expires = basem; -- GitLab From 6bad6bccf2d717f652d37e63cf261eaa23466009 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 22 Oct 2016 11:07:37 +0000 Subject: [PATCH 1008/1167] timers: Prevent base clock corruption when forwarding When a timer is enqueued we try to forward the timer base clock. This mechanism has two issues: 1) Forwarding a remote base unlocked The forwarding function is called from get_target_base() with the current timer base lock held. But if the new target base is a different base than the current base (can happen with NOHZ, sigh!) then the forwarding is done on an unlocked base. This can lead to corruption of base->clk. Solution is simple: Invoke the forwarding after the target base is locked. 2) Possible corruption due to jiffies advancing This is similar to the issue in get_net_timer_interrupt() which was fixed in the previous patch. jiffies can advance between check and assignement and therefore advancing base->clk beyond the next expiry value. So we need to read jiffies into a local variable once and do the checks and assignment with the local copy. Fixes: a683f390b93f("timers: Forward the wheel clock whenever possible") Reported-by: Ashton Holmes Reported-by: Michael Thayer Signed-off-by: Thomas Gleixner Cc: Michal Necasek Cc: Peter Zijlstra Cc: knut.osmundsen@oracle.com Cc: stable@vger.kernel.org Cc: stern@rowland.harvard.edu Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20161022110552.253640125@linutronix.de Signed-off-by: Thomas Gleixner --- kernel/time/timer.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 7c446fb5163a6..c611c47de8849 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -878,7 +878,7 @@ static inline struct timer_base *get_timer_base(u32 tflags) #ifdef CONFIG_NO_HZ_COMMON static inline struct timer_base * -__get_target_base(struct timer_base *base, unsigned tflags) +get_target_base(struct timer_base *base, unsigned tflags) { #ifdef CONFIG_SMP if ((tflags & TIMER_PINNED) || !base->migration_enabled) @@ -891,25 +891,27 @@ __get_target_base(struct timer_base *base, unsigned tflags) static inline void forward_timer_base(struct timer_base *base) { + unsigned long jnow = READ_ONCE(jiffies); + /* * We only forward the base when it's idle and we have a delta between * base clock and jiffies. */ - if (!base->is_idle || (long) (jiffies - base->clk) < 2) + if (!base->is_idle || (long) (jnow - base->clk) < 2) return; /* * If the next expiry value is > jiffies, then we fast forward to * jiffies otherwise we forward to the next expiry value. */ - if (time_after(base->next_expiry, jiffies)) - base->clk = jiffies; + if (time_after(base->next_expiry, jnow)) + base->clk = jnow; else base->clk = base->next_expiry; } #else static inline struct timer_base * -__get_target_base(struct timer_base *base, unsigned tflags) +get_target_base(struct timer_base *base, unsigned tflags) { return get_timer_this_cpu_base(tflags); } @@ -917,14 +919,6 @@ __get_target_base(struct timer_base *base, unsigned tflags) static inline void forward_timer_base(struct timer_base *base) { } #endif -static inline struct timer_base * -get_target_base(struct timer_base *base, unsigned tflags) -{ - struct timer_base *target = __get_target_base(base, tflags); - - forward_timer_base(target); - return target; -} /* * We are using hashed locking: Holding per_cpu(timer_bases[x]).lock means @@ -1037,6 +1031,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) } } + /* Try to forward a stale timer base clock */ + forward_timer_base(base); + timer->expires = expires; /* * If 'idx' was calculated above and the base time did not advance -- GitLab From 0ce57f8af1782fd12d3a81872a4ab97244989802 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 25 Oct 2016 14:04:34 +0200 Subject: [PATCH 1009/1167] ahci: fix the single MSI-X case in ahci_init_one We need to make sure hpriv->irq is set properly if we don't use per-port vectors, so switch from blindly assigning pdev->irq to using pci_irq_vector, which handles all interrupt types correctly. Signed-off-by: Christoph Hellwig Reported-by: Robert Richter Tested-by: Robert Richter Tested-by: David Daney Fixes: 0b9e2988ab22 ("ahci: use pci_alloc_irq_vectors") Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 60e42e2ed68fa..9669fc7c19df7 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1620,7 +1620,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* legacy intx interrupts */ pci_intx(pdev, 1); } - hpriv->irq = pdev->irq; + hpriv->irq = pci_irq_vector(pdev, 0); if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) host->flags |= ATA_HOST_PARALLEL_SCAN; -- GitLab From a467a672cf097ec11332a9b22db6e31d3ef50359 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 26 Oct 2016 10:07:44 +1030 Subject: [PATCH 1010/1167] MAINTAINERS: Begin module maintainer transition Being a Linux kernel maintainer has been my proudest professional accomplishment, spanning the last 19 years. But now we have a surfeit of excellent hackers, and I can hand this over without regret. I'll still be around as co-maintainer for another cycle, but Jessica is now the one to convince if you want your patches applied. She rocks, and is far more timely than me too! Signed-off-by: Rusty Russell Acked-by: Jessica Yu --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index c447953063428..f30b8ea700fdd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8100,6 +8100,7 @@ S: Maintained F: drivers/media/dvb-frontends/mn88473* MODULE SUPPORT +M: Jessica Yu M: Rusty Russell S: Maintained F: include/linux/module.h -- GitLab From 8ef4227615e158faa4ee85a1d6466782f7e22f2f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 24 Oct 2016 15:27:59 +1000 Subject: [PATCH 1011/1167] x86/io: add interface to reserve io memtype for a resource range. (v1.1) A recent change to the mm code in: 87744ab3832b mm: fix cache mode tracking in vm_insert_mixed() started enforcing checking the memory type against the registered list for amixed pfn insertion mappings. It happens that the drm drivers for a number of gpus relied on this being broken. Currently the driver only inserted VRAM mappings into the tracking table when they came from the kernel, and userspace mappings never landed in the table. This led to a regression where all the mapping end up as UC instead of WC now. I've considered a number of solutions but since this needs to be fixed in fixes and not next, and some of the solutions were going to introduce overhead that hadn't been there before I didn't consider them viable at this stage. These mainly concerned hooking into the TTM io reserve APIs, but these API have a bunch of fast paths I didn't want to unwind to add this to. The solution I've decided on is to add a new API like the arch_phys_wc APIs (these would have worked but wc_del didn't take a range), and use them from the drivers to add a WC compatible mapping to the table for all VRAM on those GPUs. This means we can then create userspace mapping that won't get degraded to UC. v1.1: use CONFIG_X86_PAT + add some comments in io.h Cc: Toshi Kani Cc: Borislav Petkov Cc: H. Peter Anvin Cc: Andy Lutomirski Cc: Denys Vlasenko Cc: Brian Gerst Cc: x86@kernel.org Cc: mcgrof@suse.com Cc: Dan Williams Acked-by: Ingo Molnar Reviewed-by: Thomas Gleixner Signed-off-by: Dave Airlie --- arch/x86/include/asm/io.h | 6 ++++++ arch/x86/mm/pat.c | 14 ++++++++++++++ include/linux/io.h | 22 ++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index de25aad078538..d34bd370074b4 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -351,4 +351,10 @@ extern void arch_phys_wc_del(int handle); #define arch_phys_wc_add arch_phys_wc_add #endif +#ifdef CONFIG_X86_PAT +extern int arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size); +extern void arch_io_free_memtype_wc(resource_size_t start, resource_size_t size); +#define arch_io_reserve_memtype_wc arch_io_reserve_memtype_wc +#endif + #endif /* _ASM_X86_IO_H */ diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 170cc4ff057b3..83e701f160a91 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -730,6 +730,20 @@ void io_free_memtype(resource_size_t start, resource_size_t end) free_memtype(start, end); } +int arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size) +{ + enum page_cache_mode type = _PAGE_CACHE_MODE_WC; + + return io_reserve_memtype(start, start + size, &type); +} +EXPORT_SYMBOL(arch_io_reserve_memtype_wc); + +void arch_io_free_memtype_wc(resource_size_t start, resource_size_t size) +{ + io_free_memtype(start, start + size); +} +EXPORT_SYMBOL(arch_io_free_memtype_wc); + pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot) { diff --git a/include/linux/io.h b/include/linux/io.h index e2c8419278c19..82ef36eac8a16 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -141,4 +141,26 @@ enum { void *memremap(resource_size_t offset, size_t size, unsigned long flags); void memunmap(void *addr); +/* + * On x86 PAT systems we have memory tracking that keeps track of + * the allowed mappings on memory ranges. This tracking works for + * all the in-kernel mapping APIs (ioremap*), but where the user + * wishes to map a range from a physical device into user memory + * the tracking won't be updated. This API is to be used by + * drivers which remap physical device pages into userspace, + * and wants to make sure they are mapped WC and not UC. + */ +#ifndef arch_io_reserve_memtype_wc +static inline int arch_io_reserve_memtype_wc(resource_size_t base, + resource_size_t size) +{ + return 0; +} + +static inline void arch_io_free_memtype_wc(resource_size_t base, + resource_size_t size) +{ +} +#endif + #endif /* _LINUX_IO_H */ -- GitLab From e1957dba5b54b9c9b1d16f9d5f3f8d41d82bee41 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Oct 2016 07:56:59 +0200 Subject: [PATCH 1012/1167] cfg80211: process events caused by suspend before suspending When suspending without WoWLAN, cfg80211 will ask drivers to disconnect. Even when the driver does this synchronously, and immediately returns with a notification, cfg80211 schedules the handling thereof to a workqueue, and may then call back into the driver when the driver was already suspended/ing. Fix this by processing all events caused by cfg80211_leave_all() directly after that function returns. The driver still needs to do the right thing here and wait for the firmware response, but that is - at least - true for mwifiex where this occurred. Reported-by: Amitkumar Karwar Tested-by: Amitkumar Karwar Signed-off-by: Johannes Berg --- net/wireless/sysfs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 0082f4b01795a..14b3f007826d9 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -104,13 +104,16 @@ static int wiphy_suspend(struct device *dev) rtnl_lock(); if (rdev->wiphy.registered) { - if (!rdev->wiphy.wowlan_config) + if (!rdev->wiphy.wowlan_config) { cfg80211_leave_all(rdev); + cfg80211_process_rdev_events(rdev); + } if (rdev->ops->suspend) ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config); if (ret == 1) { /* Driver refuse to configure wowlan */ cfg80211_leave_all(rdev); + cfg80211_process_rdev_events(rdev); ret = rdev_suspend(rdev, NULL); } } -- GitLab From b4f7f4ad425a84fd5d40da21aff8681997b25ff9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 21 Oct 2016 15:57:23 +0300 Subject: [PATCH 1013/1167] mac80211: fix some sphinx warnings Signed-off-by: Jani Nikula Signed-off-by: Johannes Berg --- include/net/mac80211.h | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a810dfcb83c23..e2dba93e374fd 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -811,14 +811,18 @@ enum mac80211_rate_control_flags { * in the control information, and it will be filled by the rate * control algorithm according to what should be sent. For example, * if this array contains, in the format { , } the - * information + * information:: + * * { 3, 2 }, { 2, 2 }, { 1, 4 }, { -1, 0 }, { -1, 0 } + * * then this means that the frame should be transmitted * up to twice at rate 3, up to twice at rate 2, and up to four * times at rate 1 if it doesn't get acknowledged. Say it gets * acknowledged by the peer after the fifth attempt, the status - * information should then contain + * information should then contain:: + * * { 3, 2 }, { 2, 2 }, { 1, 1 }, { -1, 0 } ... + * * since it was transmitted twice at rate 3, twice at rate 2 * and once at rate 1 after which we received an acknowledgement. */ @@ -1168,8 +1172,8 @@ enum mac80211_rx_vht_flags { * @rate_idx: index of data rate into band's supported rates or MCS index if * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT) * @vht_nss: number of streams (VHT only) - * @flag: %RX_FLAG_* - * @vht_flag: %RX_VHT_FLAG_* + * @flag: %RX_FLAG_\* + * @vht_flag: %RX_VHT_FLAG_\* * @rx_flags: internal RX flags for mac80211 * @ampdu_reference: A-MPDU reference number, must be a different value for * each A-MPDU but the same for each subframe within one A-MPDU @@ -1432,7 +1436,7 @@ enum ieee80211_vif_flags { * @probe_req_reg: probe requests should be reported to mac80211 for this * interface. * @drv_priv: data area for driver use, will always be aligned to - * sizeof(void *). + * sizeof(void \*). * @txq: the multicast data TX queue (if driver uses the TXQ abstraction) */ struct ieee80211_vif { @@ -1743,7 +1747,7 @@ struct ieee80211_sta_rates { * @wme: indicates whether the STA supports QoS/WME (if local devices does, * otherwise always false) * @drv_priv: data area for driver use, will always be aligned to - * sizeof(void *), size is determined in hw information. + * sizeof(void \*), size is determined in hw information. * @uapsd_queues: bitmap of queues configured for uapsd. Only valid * if wme is supported. * @max_sp: max Service Period. Only valid if wme is supported. @@ -2146,12 +2150,12 @@ enum ieee80211_hw_flags { * * @radiotap_mcs_details: lists which MCS information can the HW * reports, by default it is set to _MCS, _GI and _BW but doesn't - * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only + * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_\* values, only * adding _BW is supported today. * * @radiotap_vht_details: lists which VHT MCS information the HW reports, * the default is _GI | _BANDWIDTH. - * Use the %IEEE80211_RADIOTAP_VHT_KNOWN_* values. + * Use the %IEEE80211_RADIOTAP_VHT_KNOWN_\* values. * * @radiotap_timestamp: Information for the radiotap timestamp field; if the * 'units_pos' member is set to a non-negative value it must be set to @@ -2486,6 +2490,7 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); * in the software stack cares about, we will, in the future, have mac80211 * tell the driver which information elements are interesting in the sense * that we want to see changes in them. This will include + * * - a list of information element IDs * - a list of OUIs for the vendor information element * -- GitLab From 7cf321d118a825c1541b43ca45294126fd474efa Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 24 Oct 2016 15:37:48 +1000 Subject: [PATCH 1014/1167] drm/drivers: add support for using the arch wc mapping API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a regression in all these drivers since the cache mode tracking was fixed for mixed mappings. It uses the new arch API to add the VRAM range to the PAT mapping tracking tables. Fixes: 87744ab3832 (mm: fix cache mode tracking in vm_insert_mixed()) Reviewed-by: Christian König . Signed-off-by: Dave Airlie --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 5 +++++ drivers/gpu/drm/ast/ast_ttm.c | 6 ++++++ drivers/gpu/drm/cirrus/cirrus_ttm.c | 7 +++++++ drivers/gpu/drm/mgag200/mgag200_ttm.c | 7 +++++++ drivers/gpu/drm/nouveau/nouveau_ttm.c | 8 ++++++++ drivers/gpu/drm/radeon/radeon_object.c | 5 +++++ 6 files changed, 38 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index aa074fac0c7f6..f3efb1c5dae96 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -754,6 +754,10 @@ static const char *amdgpu_vram_names[] = { int amdgpu_bo_init(struct amdgpu_device *adev) { + /* reserve PAT memory space to WC for VRAM */ + arch_io_reserve_memtype_wc(adev->mc.aper_base, + adev->mc.aper_size); + /* Add an MTRR for the VRAM */ adev->mc.vram_mtrr = arch_phys_wc_add(adev->mc.aper_base, adev->mc.aper_size); @@ -769,6 +773,7 @@ void amdgpu_bo_fini(struct amdgpu_device *adev) { amdgpu_ttm_fini(adev); arch_phys_wc_del(adev->mc.vram_mtrr); + arch_io_free_memtype_wc(adev->mc.aper_base, adev->mc.aper_size); } int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo, diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 608df4c905202..0743e65cb2402 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -267,6 +267,8 @@ int ast_mm_init(struct ast_private *ast) return ret; } + arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); ast->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), pci_resource_len(dev->pdev, 0)); @@ -275,11 +277,15 @@ int ast_mm_init(struct ast_private *ast) void ast_mm_fini(struct ast_private *ast) { + struct drm_device *dev = ast->dev; + ttm_bo_device_release(&ast->ttm.bdev); ast_ttm_global_release(ast); arch_phys_wc_del(ast->fb_mtrr); + arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); } void ast_ttm_placement(struct ast_bo *bo, int domain) diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index bb2438dd8733f..5e7e63ce7bcef 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -267,6 +267,9 @@ int cirrus_mm_init(struct cirrus_device *cirrus) return ret; } + arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); + cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), pci_resource_len(dev->pdev, 0)); @@ -276,6 +279,8 @@ int cirrus_mm_init(struct cirrus_device *cirrus) void cirrus_mm_fini(struct cirrus_device *cirrus) { + struct drm_device *dev = cirrus->dev; + if (!cirrus->mm_inited) return; @@ -285,6 +290,8 @@ void cirrus_mm_fini(struct cirrus_device *cirrus) arch_phys_wc_del(cirrus->fb_mtrr); cirrus->fb_mtrr = 0; + arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); } void cirrus_ttm_placement(struct cirrus_bo *bo, int domain) diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 919b35f2ad248..dcf7d11ac380d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -266,6 +266,9 @@ int mgag200_mm_init(struct mga_device *mdev) return ret; } + arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); + mdev->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), pci_resource_len(dev->pdev, 0)); @@ -274,10 +277,14 @@ int mgag200_mm_init(struct mga_device *mdev) void mgag200_mm_fini(struct mga_device *mdev) { + struct drm_device *dev = mdev->dev; + ttm_bo_device_release(&mdev->ttm.bdev); mgag200_ttm_global_release(mdev); + arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); arch_phys_wc_del(mdev->fb_mtrr); mdev->fb_mtrr = 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 1825dbc331926..a6dbe8258040d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -398,6 +398,9 @@ nouveau_ttm_init(struct nouveau_drm *drm) /* VRAM init */ drm->gem.vram_available = drm->device.info.ram_user; + arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1), + device->func->resource_size(device, 1)); + ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM, drm->gem.vram_available >> PAGE_SHIFT); if (ret) { @@ -430,6 +433,8 @@ nouveau_ttm_init(struct nouveau_drm *drm) void nouveau_ttm_fini(struct nouveau_drm *drm) { + struct nvkm_device *device = nvxx_device(&drm->device); + ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM); ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT); @@ -439,4 +444,7 @@ nouveau_ttm_fini(struct nouveau_drm *drm) arch_phys_wc_del(drm->ttm.mtrr); drm->ttm.mtrr = 0; + arch_io_free_memtype_wc(device->func->resource_addr(device, 1), + device->func->resource_size(device, 1)); + } diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index be30861afae9a..41b72ce6613fe 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -446,6 +446,10 @@ void radeon_bo_force_delete(struct radeon_device *rdev) int radeon_bo_init(struct radeon_device *rdev) { + /* reserve PAT memory space to WC for VRAM */ + arch_io_reserve_memtype_wc(rdev->mc.aper_base, + rdev->mc.aper_size); + /* Add an MTRR for the VRAM */ if (!rdev->fastfb_working) { rdev->mc.vram_mtrr = arch_phys_wc_add(rdev->mc.aper_base, @@ -463,6 +467,7 @@ void radeon_bo_fini(struct radeon_device *rdev) { radeon_ttm_fini(rdev); arch_phys_wc_del(rdev->mc.vram_mtrr); + arch_io_free_memtype_wc(rdev->mc.aper_base, rdev->mc.aper_size); } /* Returns how many bytes TTM can move per IB. -- GitLab From 2925d366f450dc1db0ac88f2509a0eec0fef4226 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 17 Oct 2016 17:16:02 -0700 Subject: [PATCH 1015/1167] extcon: qcom-spmi-misc: Sync the extcon state on interrupt The driver was changed after submission to use the new style APIs like extcon_set_state(). Unfortunately, that only sets the state, and doesn't notify any consumers that the cable state has changed. Use extcon_set_state_sync() here instead so that we notify cable consumers of the state change. This fixes USB host-device role switching on the db8074 platform. Fixes: 38085c987f52 ("extcon: Add support for qcom SPMI PMIC USB id detection hardware") Signed-off-by: Stephen Boyd Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-qcom-spmi-misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c index ca957a5f42912..b8cde096a808f 100644 --- a/drivers/extcon/extcon-qcom-spmi-misc.c +++ b/drivers/extcon/extcon-qcom-spmi-misc.c @@ -51,7 +51,7 @@ static void qcom_usb_extcon_detect_cable(struct work_struct *work) if (ret) return; - extcon_set_state(info->edev, EXTCON_USB_HOST, !id); + extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !id); } static irqreturn_t qcom_usb_irq_handler(int irq, void *dev_id) -- GitLab From 62c61514191bfe5731b43619b9b1bf4b423beeb0 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 23 Oct 2016 09:32:34 -0700 Subject: [PATCH 1016/1167] doc: Add missing parameter for msi_setup commit 92ca8d20dee2 ("genirq/msi: Switch to new irq spreading") introduced new parameter to msi_init_setup and but did not update docbook comments. Fixes 'make htmldocs' warning. Signed-off-by: Stephen Hemminger Cc: bhelgaas@google.com Cc: linux-pci@vger.kernel.org Signed-off-by: Thomas Gleixner --- drivers/pci/msi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index bfdd0744b686a..ad70507cfb566 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -610,6 +610,7 @@ static int msi_verify_entries(struct pci_dev *dev) * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function * @nvec: number of interrupts to allocate + * @affinity: flag to indicate cpu irq affinity mask should be set * * Setup the MSI capability structure of the device with the requested * number of interrupts. A return value of zero indicates the successful @@ -752,6 +753,7 @@ static void msix_program_entries(struct pci_dev *dev, * @dev: pointer to the pci_dev data structure of MSI-X device function * @entries: pointer to an array of struct msix_entry entries * @nvec: number of @entries + * @affinity: flag to indicate cpu irq affinity mask should be set * * Setup the MSI-X capability structure of device function with a * single MSI-X irq. A return of zero indicates the successful setup of -- GitLab From 5de0a8c0c240338cb5b73363b0673c6aa804bb1c Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 24 Oct 2016 15:01:48 -0400 Subject: [PATCH 1017/1167] x86: Fix export for mcount and __fentry__ Commit 784d5699eddc5 ("x86: move exports to actual definitions") removed the EXPORT_SYMBOL(__fentry__) and EXPORT_SYMBOL(mcount) from x8664_ksyms_64.c, and added EXPORT_SYMBOL(function_hook) in mcount_64.S instead. The problem is that function_hook isn't a function at all, but a macro that is defined as either mcount or __fentry__ depending on the support from gcc. Originally, I thought this was a macro issue, like what __stringify() is used for. But the problem is a bit deeper. The Makefile.build has some magic that does post processing of files to create the CRC bindings. It does some searches for EXPORT_SYMBOL() and because it finds a macro name and not the actual functions, this causes function_hook not to be converted into mcount or __fentry__ and they are missed. Instead of adding more magic to Makefile.build, just add EXPORT_SYMBOL() for mcount and __fentry__ where the ifdef is used. Since this is assembly and not C, it doesn't require being set after the function is defined. Signed-off-by: Steven Rostedt Tested-by: Borislav Petkov Cc: Gabriel C Cc: Nicholas Piggin Cc: Al Viro Link: http://lkml.kernel.org/r/20161024150148.4f9d90e4@gandalf.local.home Signed-off-by: Thomas Gleixner --- arch/x86/kernel/mcount_64.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/mcount_64.S b/arch/x86/kernel/mcount_64.S index efe73aacf966e..7b0d3da52fb42 100644 --- a/arch/x86/kernel/mcount_64.S +++ b/arch/x86/kernel/mcount_64.S @@ -18,8 +18,10 @@ #ifdef CC_USING_FENTRY # define function_hook __fentry__ +EXPORT_SYMBOL(__fentry__) #else # define function_hook mcount +EXPORT_SYMBOL(mcount) #endif /* All cases save the original rbp (8 bytes) */ @@ -295,7 +297,6 @@ trace: jmp fgraph_trace END(function_hook) #endif /* CONFIG_DYNAMIC_FTRACE */ -EXPORT_SYMBOL(function_hook) #endif /* CONFIG_FUNCTION_TRACER */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER -- GitLab From 94d7dea448fae6cbb83395323c1d2fd7f19dc388 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 26 Oct 2016 16:57:15 +0800 Subject: [PATCH 1018/1167] block: flush: fix IO hang in case of flood fua req This patch fixes one issue reported by Kent, which can be triggered in bcachefs over sata disk. Actually it is a generic issue in block flush vs. blk-tag. Cc: Christoph Hellwig Reported-by: Kent Overstreet Signed-off-by: Ming Lei Signed-off-by: Jens Axboe --- block/blk-flush.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/block/blk-flush.c b/block/blk-flush.c index 6a14b68b91358..3c882cbc75417 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -342,6 +342,34 @@ static void flush_data_end_io(struct request *rq, int error) struct request_queue *q = rq->q; struct blk_flush_queue *fq = blk_get_flush_queue(q, NULL); + /* + * Updating q->in_flight[] here for making this tag usable + * early. Because in blk_queue_start_tag(), + * q->in_flight[BLK_RW_ASYNC] is used to limit async I/O and + * reserve tags for sync I/O. + * + * More importantly this way can avoid the following I/O + * deadlock: + * + * - suppose there are 40 fua requests comming to flush queue + * and queue depth is 31 + * - 30 rqs are scheduled then blk_queue_start_tag() can't alloc + * tag for async I/O any more + * - all the 30 rqs are completed before FLUSH_PENDING_TIMEOUT + * and flush_data_end_io() is called + * - the other rqs still can't go ahead if not updating + * q->in_flight[BLK_RW_ASYNC] here, meantime these rqs + * are held in flush data queue and make no progress of + * handling post flush rq + * - only after the post flush rq is handled, all these rqs + * can be completed + */ + + elv_completed_request(q, rq); + + /* for avoiding double accounting */ + rq->cmd_flags &= ~REQ_STARTED; + /* * After populating an empty queue, kick it to avoid stall. Read * the comment in flush_end_io(). -- GitLab From 26984c3bc29aa15b705475177842feddcd3d9df0 Mon Sep 17 00:00:00 2001 From: Yisheng Xie Date: Fri, 21 Oct 2016 16:13:55 +0800 Subject: [PATCH 1019/1167] arm64/numa: fix pcpu_cpu_distance() to get correct CPU proximity The pcpu_build_alloc_info() function group CPUs according to their proximity, by call callback function @cpu_distance_fn from different ARCHs. For arm64 the callback of @cpu_distance_fn is pcpu_cpu_distance(from, to) -> node_distance(from, to) The @from and @to for function node_distance() should be nid. However, pcpu_cpu_distance() in arch/arm64/mm/numa.c just past the cpu id for @from and @to, and didn't convert to numa node id. For this incorrect cpu proximity get from ARCH, it may cause each CPU in one group and make group_cnt out of bound: setup_per_cpu_areas() pcpu_embed_first_chunk() pcpu_build_alloc_info() in pcpu_build_alloc_info, since cpu_distance_fn will return REMOTE_DISTANCE if we pass cpu ids (0,1,2...), so cpu_distance_fn(cpu, tcpu) > LOCAL_DISTANCE will wrongly be ture. This may results in triggering the BUG_ON(unit != nr_units) later: [ 0.000000] kernel BUG at mm/percpu.c:1916! [ 0.000000] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP [ 0.000000] Modules linked in: [ 0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 4.9.0-rc1-00003-g14155ca-dirty #26 [ 0.000000] Hardware name: Hisilicon Hi1616 Evaluation Board (DT) [ 0.000000] task: ffff000008d6e900 task.stack: ffff000008d60000 [ 0.000000] PC is at pcpu_embed_first_chunk+0x420/0x704 [ 0.000000] LR is at pcpu_embed_first_chunk+0x3bc/0x704 [ 0.000000] pc : [] lr : [] pstate: 800000c5 [ 0.000000] sp : ffff000008d63eb0 [ 0.000000] x29: ffff000008d63eb0 [ 0.000000] x28: 0000000000000000 [ 0.000000] x27: 0000000000000040 [ 0.000000] x26: ffff8413fbfcef00 [ 0.000000] x25: 0000000000000042 [ 0.000000] x24: 0000000000000042 [ 0.000000] x23: 0000000000001000 [ 0.000000] x22: 0000000000000046 [ 0.000000] x21: 0000000000000001 [ 0.000000] x20: ffff000008cb3bc8 [ 0.000000] x19: ffff8413fbfcf570 [ 0.000000] x18: 0000000000000000 [ 0.000000] x17: ffff000008e49ae0 [ 0.000000] x16: 0000000000000003 [ 0.000000] x15: 000000000000001e [ 0.000000] x14: 0000000000000004 [ 0.000000] x13: 0000000000000000 [ 0.000000] x12: 000000000000006f [ 0.000000] x11: 00000413fbffff00 [ 0.000000] x10: 0000000000000004 [ 0.000000] x9 : 0000000000000000 [ 0.000000] x8 : 0000000000000001 [ 0.000000] x7 : ffff8413fbfcf63c [ 0.000000] x6 : ffff000008d65d28 [ 0.000000] x5 : ffff000008d65e50 [ 0.000000] x4 : 0000000000000000 [ 0.000000] x3 : ffff000008cb3cc8 [ 0.000000] x2 : 0000000000000040 [ 0.000000] x1 : 0000000000000040 [ 0.000000] x0 : 0000000000000000 [...] [ 0.000000] Call trace: [ 0.000000] Exception stack(0xffff000008d63ce0 to 0xffff000008d63e10) [ 0.000000] 3ce0: ffff8413fbfcf570 0001000000000000 ffff000008d63eb0 ffff000008c754f4 [ 0.000000] 3d00: ffff000008d63d50 ffff0000081af210 00000413fbfff010 0000000000001000 [ 0.000000] 3d20: ffff000008d63d50 ffff0000081af220 00000413fbfff010 0000000000001000 [ 0.000000] 3d40: 00000413fbfcef00 0000000000000004 ffff000008d63db0 ffff0000081af390 [ 0.000000] 3d60: 00000413fbfcef00 0000000000001000 0000000000000000 0000000000001000 [ 0.000000] 3d80: 0000000000000000 0000000000000040 0000000000000040 ffff000008cb3cc8 [ 0.000000] 3da0: 0000000000000000 ffff000008d65e50 ffff000008d65d28 ffff8413fbfcf63c [ 0.000000] 3dc0: 0000000000000001 0000000000000000 0000000000000004 00000413fbffff00 [ 0.000000] 3de0: 000000000000006f 0000000000000000 0000000000000004 000000000000001e [ 0.000000] 3e00: 0000000000000003 ffff000008e49ae0 [ 0.000000] [] pcpu_embed_first_chunk+0x420/0x704 [ 0.000000] [] setup_per_cpu_areas+0x38/0xc8 [ 0.000000] [] start_kernel+0x10c/0x390 [ 0.000000] [] __primary_switched+0x5c/0x64 [ 0.000000] Code: b8018660 17ffffd7 6b16037f 54000080 (d4210000) [ 0.000000] ---[ end trace 0000000000000000 ]--- [ 0.000000] Kernel panic - not syncing: Attempted to kill the idle task! Fix by getting cpu's node id with early_cpu_to_node() then pass it to node_distance() as the original intention. Fixes: 7af3a0a99252 ("arm64/numa: support HAVE_SETUP_PER_CPU_AREA") Signed-off-by: Yisheng Xie Signed-off-by: Hanjun Guo Cc: Catalin Marinas Cc: Lorenzo Pieralisi Cc: Will Deacon Cc: Zhen Lei Signed-off-by: Will Deacon --- arch/arm64/mm/numa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/mm/numa.c b/arch/arm64/mm/numa.c index 778a985c8a707..9a71d0678a083 100644 --- a/arch/arm64/mm/numa.c +++ b/arch/arm64/mm/numa.c @@ -147,7 +147,7 @@ static int __init early_cpu_to_node(int cpu) static int __init pcpu_cpu_distance(unsigned int from, unsigned int to) { - return node_distance(from, to); + return node_distance(early_cpu_to_node(from), early_cpu_to_node(to)); } static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, -- GitLab From 3f7a09f44e5ef8a2629842f2d22892114e603fc1 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Fri, 21 Oct 2016 16:13:56 +0800 Subject: [PATCH 1020/1167] arm64/numa: fix incorrect log for memory-less node When booting on NUMA system with memory-less node (no memory dimm on this memory controller), the print for setup_node_data() is incorrect: NUMA: Initmem setup node 2 [mem 0x00000000-0xffffffffffffffff] It can be fixed by printing [mem 0x00000000-0x00000000] when end_pfn is 0, but print will be more useful. Fixes: 1a2db300348b ("arm64, numa: Add NUMA support for arm64 platforms.") Signed-off-by: Hanjun Guo Cc: Catalin Marinas Cc: Ganapatrao Kulkarni Cc: Lorenzo Pieralisi Cc: Mark Rutland Cc: Will Deacon Cc: Yisheng Xie Signed-off-by: Will Deacon --- arch/arm64/mm/numa.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm64/mm/numa.c b/arch/arm64/mm/numa.c index 9a71d0678a083..4b32168cf91a0 100644 --- a/arch/arm64/mm/numa.c +++ b/arch/arm64/mm/numa.c @@ -223,8 +223,11 @@ static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn) void *nd; int tnid; - pr_info("Initmem setup node %d [mem %#010Lx-%#010Lx]\n", - nid, start_pfn << PAGE_SHIFT, (end_pfn << PAGE_SHIFT) - 1); + if (start_pfn < end_pfn) + pr_info("Initmem setup node %d [mem %#010Lx-%#010Lx]\n", nid, + start_pfn << PAGE_SHIFT, (end_pfn << PAGE_SHIFT) - 1); + else + pr_info("Initmem setup node %d []\n", nid); nd_pa = memblock_alloc_try_nid(nd_size, SMP_CACHE_BYTES, nid); nd = __va(nd_pa); -- GitLab From 3fa72fe9c614717d22ae75b84d45f41da65c10fe Mon Sep 17 00:00:00 2001 From: Neeraj Upadhyay Date: Fri, 21 Oct 2016 14:28:46 +0530 Subject: [PATCH 1021/1167] arm64: mm: fix __page_to_voff definition Fix parameter name for __page_to_voff, to match its definition. At present, we don't see any issue, as page_to_virt's caller declares 'page'. Fixes: 9f2875912dac ("arm64: mm: restrict virt_to_page() to the linear mapping") Acked-by: Mark Rutland Acked-by: Ard Biesheuvel Signed-off-by: Neeraj Upadhyay Signed-off-by: Will Deacon --- arch/arm64/include/asm/memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index ba62df8c6e354..b71086d251954 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -217,7 +217,7 @@ static inline void *phys_to_virt(phys_addr_t x) #define _virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) #else #define __virt_to_pgoff(kaddr) (((u64)(kaddr) & ~PAGE_OFFSET) / PAGE_SIZE * sizeof(struct page)) -#define __page_to_voff(kaddr) (((u64)(page) & ~VMEMMAP_START) * PAGE_SIZE / sizeof(struct page)) +#define __page_to_voff(page) (((u64)(page) & ~VMEMMAP_START) * PAGE_SIZE / sizeof(struct page)) #define page_to_virt(page) ((void *)((__page_to_voff(page)) | PAGE_OFFSET)) #define virt_to_page(vaddr) ((struct page *)((__virt_to_pgoff(vaddr)) | VMEMMAP_START)) -- GitLab From 92d230dd8cafac417e130e404d4b64eafe2271de Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 22 Oct 2016 14:31:06 +0000 Subject: [PATCH 1022/1167] rocker: fix error return code in rocker_world_check_init() Fix to return error code -EINVAL from the error handling case instead of 0, as done elsewhere in this function. Fixes: e420114eef4a ("rocker: introduce worlds infrastructure") Signed-off-by: Wei Yongjun Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 5424fb341613f..24b746406bc7a 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -1471,7 +1471,7 @@ static int rocker_world_check_init(struct rocker_port *rocker_port) if (rocker->wops) { if (rocker->wops->mode != mode) { dev_err(&rocker->pdev->dev, "hardware has ports in different worlds, which is not supported\n"); - return err; + return -EINVAL; } return 0; } -- GitLab From 293de7dee4f9602676846dbeb84b1580123306b4 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 23 Oct 2016 09:28:29 -0700 Subject: [PATCH 1023/1167] doc: update docbook annotations for socket and skb The skbuff and sock structure both had missing parameter annotation values. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/skbuff.h | 1 + include/net/sock.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 601258f6e6215..32810f279f8e4 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -936,6 +936,7 @@ struct sk_buff_fclones { /** * skb_fclone_busy - check if fclone is busy + * @sk: socket * @skb: buffer * * Returns true if skb is a fast clone, and its clone is not freed. diff --git a/include/net/sock.h b/include/net/sock.h index ebf75db08e062..73c6b008f1b76 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -252,6 +252,7 @@ struct sock_common { * @sk_pacing_rate: Pacing rate (if supported by transport/packet scheduler) * @sk_max_pacing_rate: Maximum pacing rate (%SO_MAX_PACING_RATE) * @sk_sndbuf: size of send buffer in bytes + * @sk_padding: unused element for alignment * @sk_no_check_tx: %SO_NO_CHECK setting, set checksum in TX packets * @sk_no_check_rx: allow zero checksum in RX packets * @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO) @@ -302,7 +303,8 @@ struct sock_common { * @sk_backlog_rcv: callback to process the backlog * @sk_destruct: called at sock freeing time, i.e. when all refcnt == 0 * @sk_reuseport_cb: reuseport group container - */ + * @sk_rcu: used during RCU grace period + */ struct sock { /* * Now struct inet_timewait_sock also uses sock_common, so please just -- GitLab From ecc515d7238f2cffac839069d56dc271141defa0 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 24 Oct 2016 01:01:09 +0800 Subject: [PATCH 1024/1167] sctp: fix the panic caused by route update Commit 7303a1475008 ("sctp: identify chunks that need to be fragmented at IP level") made the chunk be fragmented at IP level in the next round if it's size exceed PMTU. But there still is another case, PMTU can be updated if transport's dst expires and transport's pmtu_pending is set in sctp_packet_transmit. If the new PMTU is less than the chunk, the same issue with that commit can be triggered. So we should drop this packet and let it retransmit in another round where it would be fragmented at IP level. This patch is to fix it by checking the chunk size after PMTU may be updated and dropping this packet if it's size exceed PMTU. Fixes: 90017accff61 ("sctp: Add GSO support") Signed-off-by: Xin Long Acked-by: Neil Horman Signed-off-by: David S. Miller --- net/sctp/output.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/sctp/output.c b/net/sctp/output.c index 2a5c1896d18fa..6cb0df859195e 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -418,6 +418,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) __u8 has_data = 0; int gso = 0; int pktcount = 0; + int auth_len = 0; struct dst_entry *dst; unsigned char *auth = NULL; /* pointer to auth in skb data */ @@ -510,7 +511,12 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) list_for_each_entry(chunk, &packet->chunk_list, list) { int padded = SCTP_PAD4(chunk->skb->len); - if (pkt_size + padded > tp->pathmtu) + if (chunk == packet->auth) + auth_len = padded; + else if (auth_len + padded + packet->overhead > + tp->pathmtu) + goto nomem; + else if (pkt_size + padded > tp->pathmtu) break; pkt_size += padded; } -- GitLab From 10df8e6152c6c400a563a673e9956320bfce1871 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 23 Oct 2016 18:03:06 -0700 Subject: [PATCH 1025/1167] udp: fix IP_CHECKSUM handling First bug was added in commit ad6f939ab193 ("ip: Add offset parameter to ip_cmsg_recv") : Tom missed that ipv4 udp messages could be received on AF_INET6 socket. ip_cmsg_recv(msg, skb) should have been replaced by ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr)); Then commit e6afc8ace6dd ("udp: remove headers from UDP packets before queueing") forgot to adjust the offsets now UDP headers are pulled before skb are put in receive queue. Fixes: ad6f939ab193 ("ip: Add offset parameter to ip_cmsg_recv") Fixes: e6afc8ace6dd ("udp: remove headers from UDP packets before queueing") Signed-off-by: Eric Dumazet Cc: Sam Kumar Cc: Willem de Bruijn Tested-by: Willem de Bruijn Signed-off-by: David S. Miller --- include/net/ip.h | 4 ++-- net/ipv4/ip_sockglue.c | 11 ++++++----- net/ipv4/udp.c | 2 +- net/ipv6/udp.c | 3 ++- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index c9d07988911ea..5413883ac47f0 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -578,7 +578,7 @@ int ip_options_rcv_srr(struct sk_buff *skb); */ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb); -void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int offset); +void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int tlen, int offset); int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc, bool allow_ipv6); int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, @@ -600,7 +600,7 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport, static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) { - ip_cmsg_recv_offset(msg, skb, 0); + ip_cmsg_recv_offset(msg, skb, 0, 0); } bool icmp_global_allow(void); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index af4919792b6a8..b8a2d63d1fb82 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -98,7 +98,7 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb) } static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb, - int offset) + int tlen, int offset) { __wsum csum = skb->csum; @@ -106,8 +106,9 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb, return; if (offset != 0) - csum = csum_sub(csum, csum_partial(skb_transport_header(skb), - offset, 0)); + csum = csum_sub(csum, + csum_partial(skb_transport_header(skb) + tlen, + offset, 0)); put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum); } @@ -153,7 +154,7 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) } void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, - int offset) + int tlen, int offset) { struct inet_sock *inet = inet_sk(skb->sk); unsigned int flags = inet->cmsg_flags; @@ -216,7 +217,7 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, } if (flags & IP_CMSG_CHECKSUM) - ip_cmsg_recv_checksum(msg, skb, offset); + ip_cmsg_recv_checksum(msg, skb, tlen, offset); } EXPORT_SYMBOL(ip_cmsg_recv_offset); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 311613e413cbe..d123d68f4d1de 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1322,7 +1322,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, *addr_len = sizeof(*sin); } if (inet->cmsg_flags) - ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr) + off); + ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr), off); err = copied; if (flags & MSG_TRUNC) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 9aa7c1c7a9ce1..b2ef061e6836a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -427,7 +427,8 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, if (is_udp4) { if (inet->cmsg_flags) - ip_cmsg_recv(msg, skb); + ip_cmsg_recv_offset(msg, skb, + sizeof(struct udphdr), off); } else { if (np->rxopt.all) ip6_datagram_recv_specific_ctl(sk, msg, skb); -- GitLab From e52fed7177f74382f742c27de2cc5314790aebb6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 23 Oct 2016 21:32:47 -0700 Subject: [PATCH 1026/1167] netvsc: fix incorrect receive checksum offloading The Hyper-V netvsc driver was looking at the incorrect status bits in the checksum info. It was setting the receive checksum unnecessary flag based on the IP header checksum being correct. The checksum flag is skb is about TCP and UDP checksum status. Because of this bug, any packet received with bad TCP checksum would be passed up the stack and to the application causing data corruption. The problem is reproducible via netcat and netem. This had a side effect of not doing receive checksum offload on IPv6. The driver was also also always doing checksum offload independent of the checksum setting done via ethtool. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 5d6e75a40d383..c71d966d905f8 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -607,15 +607,18 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, packet->total_data_buflen); skb->protocol = eth_type_trans(skb, net); - if (csum_info) { - /* We only look at the IP checksum here. - * Should we be dropping the packet if checksum - * failed? How do we deal with other checksums - TCP/UDP? - */ - if (csum_info->receive.ip_checksum_succeeded) + + /* skb is already created with CHECKSUM_NONE */ + skb_checksum_none_assert(skb); + + /* + * In Linux, the IP checksum is always checked. + * Do L4 checksum offload if enabled and present. + */ + if (csum_info && (net->features & NETIF_F_RXCSUM)) { + if (csum_info->receive.tcp_checksum_succeeded || + csum_info->receive.udp_checksum_succeeded) skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb->ip_summed = CHECKSUM_NONE; } if (vlan_tci & VLAN_TAG_PRESENT) -- GitLab From 67f0160fe34ec5391a428603b9832c9f99d8f3a1 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Mon, 24 Oct 2016 08:48:09 +0300 Subject: [PATCH 1027/1167] MAINTAINERS: Update qlogic networking drivers Following Cavium's acquisition of qlogic we need to update all the qlogic drivers maintainer's entries to point to our new e-mail addresses, as well as update some of the driver's maintainers as those are no longer working for Cavium. I would like to thank Sony Chacko and Rajesh Borundia for their support and development of our various networking drivers. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- MAINTAINERS | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1fc66f0aceb58..af299a77ab20f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2543,15 +2543,18 @@ S: Supported F: drivers/net/ethernet/broadcom/genet/ BROADCOM BNX2 GIGABIT ETHERNET DRIVER -M: Sony Chacko -M: Dept-HSGLinuxNICDev@qlogic.com +M: Rasesh Mody +M: Harish Patil +M: Dept-GELinuxNICDev@cavium.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/broadcom/bnx2.* F: drivers/net/ethernet/broadcom/bnx2_* BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER -M: Ariel Elior +M: Yuval Mintz +M: Ariel Elior +M: everest-linux-l2@cavium.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/broadcom/bnx2x/ @@ -2758,7 +2761,9 @@ S: Supported F: drivers/scsi/bfa/ BROCADE BNA 10 GIGABIT ETHERNET DRIVER -M: Rasesh Mody +M: Rasesh Mody +M: Sudarsana Kalluru +M: Dept-GELinuxNICDev@cavium.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/brocade/bna/ @@ -8492,11 +8497,10 @@ F: Documentation/devicetree/bindings/net/wireless/ F: drivers/net/wireless/ NETXEN (1/10) GbE SUPPORT -M: Manish Chopra -M: Sony Chacko -M: Rajesh Borundia +M: Manish Chopra +M: Rahul Verma +M: Dept-GELinuxNICDev@cavium.com L: netdev@vger.kernel.org -W: http://www.qlogic.com S: Supported F: drivers/net/ethernet/qlogic/netxen/ @@ -9873,33 +9877,32 @@ F: Documentation/scsi/LICENSE.qla4xxx F: drivers/scsi/qla4xxx/ QLOGIC QLA3XXX NETWORK DRIVER -M: Jitendra Kalsaria -M: Ron Mercer -M: linux-driver@qlogic.com +M: Dept-GELinuxNICDev@cavium.com L: netdev@vger.kernel.org S: Supported F: Documentation/networking/LICENSE.qla3xxx F: drivers/net/ethernet/qlogic/qla3xxx.* QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER -M: Dept-GELinuxNICDev@qlogic.com +M: Harish Patil +M: Manish Chopra +M: Dept-GELinuxNICDev@cavium.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/qlogic/qlcnic/ QLOGIC QLGE 10Gb ETHERNET DRIVER -M: Harish Patil -M: Sudarsana Kalluru -M: Dept-GELinuxNICDev@qlogic.com -M: linux-driver@qlogic.com +M: Harish Patil +M: Manish Chopra +M: Dept-GELinuxNICDev@cavium.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/qlogic/qlge/ QLOGIC QL4xxx ETHERNET DRIVER -M: Yuval Mintz -M: Ariel Elior -M: everest-linux-l2@qlogic.com +M: Yuval Mintz +M: Ariel Elior +M: everest-linux-l2@cavium.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/qlogic/qed/ -- GitLab From 03dab869b7b239c4e013ec82aea22e181e441cfc Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 26 Oct 2016 15:01:54 +0100 Subject: [PATCH 1028/1167] KEYS: Fix short sprintf buffer in /proc/keys show function This fixes CVE-2016-7042. Fix a short sprintf buffer in proc_keys_show(). If the gcc stack protector is turned on, this can cause a panic due to stack corruption. The problem is that xbuf[] is not big enough to hold a 64-bit timeout rendered as weeks: (gdb) p 0xffffffffffffffffULL/(60*60*24*7) $2 = 30500568904943 That's 14 chars plus NUL, not 11 chars plus NUL. Expand the buffer to 16 chars. I think the unpatched code apparently works if the stack-protector is not enabled because on a 32-bit machine the buffer won't be overflowed and on a 64-bit machine there's a 64-bit aligned pointer at one side and an int that isn't checked again on the other side. The panic incurred looks something like: Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffffff81352ebe CPU: 0 PID: 1692 Comm: reproducer Not tainted 4.7.2-201.fc24.x86_64 #1 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 0000000000000086 00000000fbbd2679 ffff8800a044bc00 ffffffff813d941f ffffffff81a28d58 ffff8800a044bc98 ffff8800a044bc88 ffffffff811b2cb6 ffff880000000010 ffff8800a044bc98 ffff8800a044bc30 00000000fbbd2679 Call Trace: [] dump_stack+0x63/0x84 [] panic+0xde/0x22a [] ? proc_keys_show+0x3ce/0x3d0 [] __stack_chk_fail+0x19/0x30 [] proc_keys_show+0x3ce/0x3d0 [] ? key_validate+0x50/0x50 [] ? key_default_cmp+0x20/0x20 [] seq_read+0x2cc/0x390 [] proc_reg_read+0x42/0x70 [] __vfs_read+0x37/0x150 [] ? security_file_permission+0xa0/0xc0 [] vfs_read+0x96/0x130 [] SyS_read+0x55/0xc0 [] entry_SYSCALL_64_fastpath+0x1a/0xa4 Reported-by: Ondrej Kozina Signed-off-by: David Howells Tested-by: Ondrej Kozina cc: stable@vger.kernel.org Signed-off-by: James Morris --- security/keys/proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/keys/proc.c b/security/keys/proc.c index f0611a6368cd2..b9f531c9e4fa7 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -181,7 +181,7 @@ static int proc_keys_show(struct seq_file *m, void *v) struct timespec now; unsigned long timo; key_ref_t key_ref, skey_ref; - char xbuf[12]; + char xbuf[16]; int rc; struct keyring_search_context ctx = { -- GitLab From 7df3e59c3d1df4f87fe874c7956ef7a3d2f4d5fb Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 26 Oct 2016 15:02:01 +0100 Subject: [PATCH 1029/1167] KEYS: Sort out big_key initialisation big_key has two separate initialisation functions, one that registers the key type and one that registers the crypto. If the key type fails to register, there's no problem if the crypto registers successfully because there's no way to reach the crypto except through the key type. However, if the key type registers successfully but the crypto does not, big_key_rng and big_key_blkcipher may end up set to NULL - but the code neither checks for this nor unregisters the big key key type. Furthermore, since the key type is registered before the crypto, it is theoretically possible for the kernel to try adding a big_key before the crypto is set up, leading to the same effect. Fix this by merging big_key_crypto_init() and big_key_init() and calling the resulting function late. If they're going to be encrypted, we shouldn't be creating big_keys before we have the facilities to do the encryption available. The key type registration is also moved after the crypto initialisation. The fix also includes message printing on failure. If the big_key type isn't correctly set up, simply doing: dd if=/dev/zero bs=4096 count=1 | keyctl padd big_key a @s ought to cause an oops. Fixes: 13100a72f40f5748a04017e0ab3df4cf27c809ef ('Security: Keys: Big keys stored encrypted') Signed-off-by: David Howells cc: Peter Hlavaty cc: Kirill Marinushkin cc: Artem Savkov cc: stable@vger.kernel.org Signed-off-by: James Morris --- security/keys/big_key.c | 59 ++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/security/keys/big_key.c b/security/keys/big_key.c index c0b3030b56348..835c1ab30d01e 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c @@ -9,6 +9,7 @@ * 2 of the Licence, or (at your option) any later version. */ +#define pr_fmt(fmt) "big_key: "fmt #include #include #include @@ -341,44 +342,48 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) */ static int __init big_key_init(void) { - return register_key_type(&key_type_big_key); -} - -/* - * Initialize big_key crypto and RNG algorithms - */ -static int __init big_key_crypto_init(void) -{ - int ret = -EINVAL; + struct crypto_skcipher *cipher; + struct crypto_rng *rng; + int ret; - /* init RNG */ - big_key_rng = crypto_alloc_rng(big_key_rng_name, 0, 0); - if (IS_ERR(big_key_rng)) { - big_key_rng = NULL; - return -EFAULT; + rng = crypto_alloc_rng(big_key_rng_name, 0, 0); + if (IS_ERR(rng)) { + pr_err("Can't alloc rng: %ld\n", PTR_ERR(rng)); + return PTR_ERR(rng); } + big_key_rng = rng; + /* seed RNG */ - ret = crypto_rng_reset(big_key_rng, NULL, crypto_rng_seedsize(big_key_rng)); - if (ret) - goto error; + ret = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng)); + if (ret) { + pr_err("Can't reset rng: %d\n", ret); + goto error_rng; + } /* init block cipher */ - big_key_skcipher = crypto_alloc_skcipher(big_key_alg_name, - 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(big_key_skcipher)) { - big_key_skcipher = NULL; - ret = -EFAULT; - goto error; + cipher = crypto_alloc_skcipher(big_key_alg_name, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(cipher)) { + ret = PTR_ERR(cipher); + pr_err("Can't alloc crypto: %d\n", ret); + goto error_rng; + } + + big_key_skcipher = cipher; + + ret = register_key_type(&key_type_big_key); + if (ret < 0) { + pr_err("Can't register type: %d\n", ret); + goto error_cipher; } return 0; -error: +error_cipher: + crypto_free_skcipher(big_key_skcipher); +error_rng: crypto_free_rng(big_key_rng); - big_key_rng = NULL; return ret; } -device_initcall(big_key_init); -late_initcall(big_key_crypto_init); +late_initcall(big_key_init); -- GitLab From 31e6ec4519c0fe0ee4a2f6ba3ab278e9506b9500 Mon Sep 17 00:00:00 2001 From: Artem Savkov Date: Wed, 26 Oct 2016 15:02:09 +0100 Subject: [PATCH 1030/1167] security/keys: make BIG_KEYS dependent on stdrng. Since BIG_KEYS can't be compiled as module it requires one of the "stdrng" providers to be compiled into kernel. Otherwise big_key_crypto_init() fails on crypto_alloc_rng step and next dereference of big_key_skcipher (e.g. in big_key_preparse()) results in a NULL pointer dereference. Fixes: 13100a72f40f5748a04017e0ab3df4cf27c809ef ('Security: Keys: Big keys stored encrypted') Signed-off-by: Artem Savkov Signed-off-by: David Howells cc: Stephan Mueller cc: Kirill Marinushkin cc: stable@vger.kernel.org Signed-off-by: James Morris --- security/keys/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/keys/Kconfig b/security/keys/Kconfig index f826e87390233..d942c7c2bc0aa 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -41,7 +41,7 @@ config BIG_KEYS bool "Large payload keys" depends on KEYS depends on TMPFS - select CRYPTO + depends on (CRYPTO_ANSI_CPRNG = y || CRYPTO_DRBG = y) select CRYPTO_AES select CRYPTO_ECB select CRYPTO_RNG -- GitLab From 56fb2d6eb63acd48b50437b415b6f7d2fcffe75d Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 26 Oct 2016 10:34:08 -0500 Subject: [PATCH 1031/1167] objtool: Fix rare switch jump table pattern detection The following commit: 3732710ff6f2 ("objtool: Improve rare switch jump table pattern detection") ... improved objtool's ability to detect GCC switch statement jump tables for GCC 6. However the check to allow short jumps with the scanned range of instructions wasn't quite right. The pattern detection should allow jumps to the indirect jump instruction itself. This fixes the following warning: drivers/infiniband/sw/rxe/rxe_comp.o: warning: objtool: rxe_completer()+0x315: sibling call from callable instruction with changed frame pointer Reported-by: Arnd Bergmann Signed-off-by: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 3732710ff6f2 ("objtool: Improve rare switch jump table pattern detection") Link: http://lkml.kernel.org/r/20161026153408.2rifnw7bvoc5sex7@treble Signed-off-by: Ingo Molnar --- tools/objtool/builtin-check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 4490601a92354..e8a1f699058a2 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -754,7 +754,7 @@ static struct rela *find_switch_table(struct objtool_file *file, if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && (insn->jump_dest->offset <= insn->offset || - insn->jump_dest->offset >= orig_insn->offset)) + insn->jump_dest->offset > orig_insn->offset)) break; text_rela = find_rela_by_dest_range(insn->sec, insn->offset, -- GitLab From f5d6d2da0d9098a4aa0ebcc187aa0fc167045d6b Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 26 Oct 2016 13:37:04 +0200 Subject: [PATCH 1032/1167] sched/fair: Remove unused but set variable 'rq' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit: 8663e24d56dc ("sched/fair: Reorder cgroup creation code") ... the variable 'rq' in alloc_fair_sched_group() is set but no longer used. Remove it to fix the following GCC warning when building with 'W=1': kernel/sched/fair.c:8842:13: warning: variable ‘rq’ set but not used [-Wunused-but-set-variable] Signed-off-by: Tobias Klauser Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20161026113704.8981-1-tklauser@distanz.ch Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index d941c97dfbc32..c242944f5cbd5 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -8839,7 +8839,6 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) { struct sched_entity *se; struct cfs_rq *cfs_rq; - struct rq *rq; int i; tg->cfs_rq = kzalloc(sizeof(cfs_rq) * nr_cpu_ids, GFP_KERNEL); @@ -8854,8 +8853,6 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) init_cfs_bandwidth(tg_cfs_bandwidth(tg)); for_each_possible_cpu(i) { - rq = cpu_rq(i); - cfs_rq = kzalloc_node(sizeof(struct cfs_rq), GFP_KERNEL, cpu_to_node(i)); if (!cfs_rq) -- GitLab From bdc3478f90cd4d2928197f36629d5cf93b64dbe9 Mon Sep 17 00:00:00 2001 From: Marcel Hasler Date: Thu, 27 Oct 2016 00:42:27 +0200 Subject: [PATCH 1033/1167] ALSA: usb-audio: Add quirk for Syntek STK1160 The stk1160 chip needs QUIRK_AUDIO_ALIGN_TRANSFER. This patch resolves the issue reported on the mailing list (http://marc.info/?l=linux-sound&m=139223599126215&w=2) and also fixes bug 180071 (https://bugzilla.kernel.org/show_bug.cgi?id=180071). Signed-off-by: Marcel Hasler Cc: Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index c60a776e815d7..8a59d4782a0f4 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2907,6 +2907,23 @@ AU0828_DEVICE(0x2040, 0x7260, "Hauppauge", "HVR-950Q"), AU0828_DEVICE(0x2040, 0x7213, "Hauppauge", "HVR-950Q"), AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), +/* Syntek STK1160 */ +{ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .idVendor = 0x05e1, + .idProduct = 0x0408, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Syntek", + .product_name = "STK1160", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER + } +}, + /* Digidesign Mbox */ { /* Thanks to Clemens Ladisch */ -- GitLab From 39715bf972ed4fee18fe5409609a971fb16b1771 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Wed, 5 Oct 2016 07:57:26 +0200 Subject: [PATCH 1034/1167] powerpc/process: Fix CONFIG_ALIVEC typo in restore_tm_state() It should be ALTIVEC, not ALIVEC. Cyril explains: If a thread performs a transaction with altivec and then gets preempted for whatever reason, this bug may cause the kernel to not re-enable altivec when that thread runs again. This will result in an altivec unavailable fault, when that fault happens inside a user transaction the kernel has no choice but to enable altivec and doom the transaction. The result is that transactions using altivec may get aborted more often than they should. The difficulty in catching this with a selftest is my deliberate use of the word may above. Optimisations to avoid FPU/altivec/VSX faults mean that the kernel will always leave them on for 255 switches. This code prevents the kernel turning it off if it got to the 256th switch (and userspace was transactional). Fixes: dc16b553c949 ("powerpc: Always restore FPU/VEC/VSX if hardware transactional memory in use") Reviewed-by: Cyril Bur Signed-off-by: Valentin Rothberg Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 9e7c10fe205f7..ce6dc61b15b21 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1012,7 +1012,7 @@ void restore_tm_state(struct pt_regs *regs) /* Ensure that restore_math() will restore */ if (msr_diff & MSR_FP) current->thread.load_fp = 1; -#ifdef CONFIG_ALIVEC +#ifdef CONFIG_ALTIVEC if (cpu_has_feature(CPU_FTR_ALTIVEC) && msr_diff & MSR_VEC) current->thread.load_vec = 1; #endif -- GitLab From bd77c4498616e27d5725b5959d880ce2272fefa9 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Mon, 24 Oct 2016 08:50:43 +0530 Subject: [PATCH 1035/1167] powerpc/mm/radix: Use tlbiel only if we ever ran on the current cpu Before this patch, we used tlbiel, if we ever ran only on this core. That was mostly derived from the nohash usage of the same. But is incorrect, the ISA 3.0 clarifies tlbiel such that: "All TLB entries that have all of the following properties are made invalid on the thread executing the tlbiel instruction" ie. tlbiel only invalidates TLB entries on the current thread. So if the mm has been used on any other thread (aka. cpu) then we must broadcast the invalidate. This bug could lead to invalid TLB entries if a program runs on multiple threads of a core. Hence use tlbiel, if we only ever ran on only the current cpu. Fixes: 1a472c9dba6b ("powerpc/mm/radix: Add tlbflush routines") Cc: stable@vger.kernel.org # v4.7+ Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/tlb.h | 12 ++++++++++++ arch/powerpc/mm/tlb-radix.c | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/include/asm/tlb.h b/arch/powerpc/include/asm/tlb.h index f6f68f73e8581..99e1397b71dac 100644 --- a/arch/powerpc/include/asm/tlb.h +++ b/arch/powerpc/include/asm/tlb.h @@ -52,11 +52,23 @@ static inline int mm_is_core_local(struct mm_struct *mm) return cpumask_subset(mm_cpumask(mm), topology_sibling_cpumask(smp_processor_id())); } + +static inline int mm_is_thread_local(struct mm_struct *mm) +{ + return cpumask_equal(mm_cpumask(mm), + cpumask_of(smp_processor_id())); +} + #else static inline int mm_is_core_local(struct mm_struct *mm) { return 1; } + +static inline int mm_is_thread_local(struct mm_struct *mm) +{ + return 1; +} #endif #endif /* __KERNEL__ */ diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c index 0e49ec541ab57..bda8c43be78a4 100644 --- a/arch/powerpc/mm/tlb-radix.c +++ b/arch/powerpc/mm/tlb-radix.c @@ -175,7 +175,7 @@ void radix__flush_tlb_mm(struct mm_struct *mm) if (unlikely(pid == MMU_NO_CONTEXT)) goto no_context; - if (!mm_is_core_local(mm)) { + if (!mm_is_thread_local(mm)) { int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); if (lock_tlbie) @@ -201,7 +201,7 @@ void radix__flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr) if (unlikely(pid == MMU_NO_CONTEXT)) goto no_context; - if (!mm_is_core_local(mm)) { + if (!mm_is_thread_local(mm)) { int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); if (lock_tlbie) @@ -226,7 +226,7 @@ void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr, pid = mm ? mm->context.id : 0; if (unlikely(pid == MMU_NO_CONTEXT)) goto bail; - if (!mm_is_core_local(mm)) { + if (!mm_is_thread_local(mm)) { int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); if (lock_tlbie) @@ -321,7 +321,7 @@ void radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start, { unsigned long pid; unsigned long addr; - int local = mm_is_core_local(mm); + int local = mm_is_thread_local(mm); unsigned long ap = mmu_get_ap(psize); int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); unsigned long page_size = 1UL << mmu_psize_defs[psize].shift; -- GitLab From fb479e44a9e240a23c2d208c2ace23542a47f41c Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 13 Oct 2016 13:17:14 +1100 Subject: [PATCH 1036/1167] powerpc/64s: relocation, register save fixes for system reset interrupt This patch does a couple of things. First of all, powernv immediately explodes when running a relocated kernel, because the system reset exception for handling sleeps does not do correct relocated branches. Secondly, the sleep handling code trashes the condition and cfar registers, which we would like to preserve for debugging purposes (for non-sleep case exception). This patch changes the exception to use the standard format that saves registers before any tests or branches are made. It adds the test for idle-wakeup as an "extra" to break out of the normal exception path. Then it branches to a relocated idle handler that calls the various idle handling functions. After this patch, POWER8 CPU simulator now boots powernv kernel that is running at non-zero. Fixes: 948cf67c4726 ("powerpc: Add NAP mode support on Power7 in HV mode") Cc: stable@vger.kernel.org # v3.0+ Signed-off-by: Nicholas Piggin Acked-by: Gautham R. Shenoy Acked-by: Balbir Singh Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/exception-64s.h | 16 ++++++++ arch/powerpc/kernel/exceptions-64s.S | 50 ++++++++++++++---------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 2e4e7d878c8ee..84d49b197c329 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -93,6 +93,10 @@ ld reg,PACAKBASE(r13); /* get high part of &label */ \ ori reg,reg,(FIXED_SYMBOL_ABS_ADDR(label))@l; +#define __LOAD_HANDLER(reg, label) \ + ld reg,PACAKBASE(r13); \ + ori reg,reg,(ABS_ADDR(label))@l; + /* Exception register prefixes */ #define EXC_HV H #define EXC_STD @@ -208,6 +212,18 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) #define kvmppc_interrupt kvmppc_interrupt_pr #endif +#ifdef CONFIG_RELOCATABLE +#define BRANCH_TO_COMMON(reg, label) \ + __LOAD_HANDLER(reg, label); \ + mtctr reg; \ + bctr + +#else +#define BRANCH_TO_COMMON(reg, label) \ + b label + +#endif + #define __KVM_HANDLER_PROLOG(area, n) \ BEGIN_FTR_SECTION_NESTED(947) \ ld r10,area+EX_CFAR(r13); \ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index f129408c60229..08ba447a4b3da 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -95,19 +95,35 @@ __start_interrupts: /* No virt vectors corresponding with 0x0..0x100 */ EXC_VIRT_NONE(0x4000, 0x4100) -EXC_REAL_BEGIN(system_reset, 0x100, 0x200) - SET_SCRATCH0(r13) + #ifdef CONFIG_PPC_P7_NAP -BEGIN_FTR_SECTION - /* Running native on arch 2.06 or later, check if we are - * waking up from nap/sleep/winkle. + /* + * If running native on arch 2.06 or later, check if we are waking up + * from nap/sleep/winkle, and branch to idle handler. */ - mfspr r13,SPRN_SRR1 - rlwinm. r13,r13,47-31,30,31 - beq 9f +#define IDLETEST(n) \ + BEGIN_FTR_SECTION ; \ + mfspr r10,SPRN_SRR1 ; \ + rlwinm. r10,r10,47-31,30,31 ; \ + beq- 1f ; \ + cmpwi cr3,r10,2 ; \ + BRANCH_TO_COMMON(r10, system_reset_idle_common) ; \ +1: \ + END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) +#else +#define IDLETEST NOTEST +#endif - cmpwi cr3,r13,2 - GET_PACA(r13) +EXC_REAL_BEGIN(system_reset, 0x100, 0x200) + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD, + IDLETEST, 0x100) + +EXC_REAL_END(system_reset, 0x100, 0x200) +EXC_VIRT_NONE(0x4100, 0x4200) + +#ifdef CONFIG_PPC_P7_NAP +EXC_COMMON_BEGIN(system_reset_idle_common) bl pnv_restore_hyp_resource li r0,PNV_THREAD_RUNNING @@ -130,14 +146,8 @@ BEGIN_FTR_SECTION blt cr3,2f b pnv_wakeup_loss 2: b pnv_wakeup_noloss +#endif -9: -END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) -#endif /* CONFIG_PPC_P7_NAP */ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD, - NOTEST, 0x100) -EXC_REAL_END(system_reset, 0x100, 0x200) -EXC_VIRT_NONE(0x4100, 0x4200) EXC_COMMON(system_reset_common, 0x100, system_reset_exception) #ifdef CONFIG_PPC_PSERIES @@ -817,10 +827,8 @@ EXC_VIRT(trap_0b, 0x4b00, 0x4c00, 0xb00) TRAMP_KVM(PACA_EXGEN, 0xb00) EXC_COMMON(trap_0b_common, 0xb00, unknown_exception) - -#define LOAD_SYSCALL_HANDLER(reg) \ - ld reg,PACAKBASE(r13); \ - ori reg,reg,(ABS_ADDR(system_call_common))@l; +#define LOAD_SYSCALL_HANDLER(reg) \ + __LOAD_HANDLER(reg, system_call_common) /* Syscall routine is used twice, in reloc-off and reloc-on paths */ #define SYSCALL_PSERIES_1 \ -- GitLab From 42acfc6615f47e465731c263bee0c799edb098f2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 3 Oct 2016 11:00:17 +0200 Subject: [PATCH 1037/1167] tty: vt, fix bogus division in csi_J MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In csi_J(3), the third parameter of scr_memsetw (vc_screenbuf_size) is divided by 2 inappropriatelly. But scr_memsetw expects size, not count, because it divides the size by 2 on its own before doing actual memset-by-words. So remove the bogus division. Signed-off-by: Jiri Slaby Cc: Petr Písař Fixes: f8df13e0a9 (tty: Clean console safely) Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 06fb39c1d6dd5..ae203c2cd15a7 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1176,7 +1176,7 @@ static void csi_J(struct vc_data *vc, int vpar) break; case 3: /* erase scroll-back buffer (and whole display) */ scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char, - vc->vc_screenbuf_size >> 1); + vc->vc_screenbuf_size); set_origin(vc); if (con_is_visible(vc)) update_screen(vc); -- GitLab From b20fb13c7c093f9170fbf162fc7f333d7a5cf77a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Oct 2016 15:42:54 +0200 Subject: [PATCH 1038/1167] serial: stm32: Fix comparisons with undefined register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/tty/serial/stm32-usart.c: In function ‘stm32_receive_chars’: drivers/tty/serial/stm32-usart.c:130: warning: comparison is always true due to limited range of data type drivers/tty/serial/stm32-usart.c: In function ‘stm32_tx_dma_complete’: drivers/tty/serial/stm32-usart.c:177: warning: comparison is always false due to limited range of data type stm32_usart_offsets.icr is u8, while UNDEF_REG = ~0 is int, and thus 0xffffffff. As all registers in stm32_usart_offsets are u8, change the definition of UNDEF_REG to 0xff to fix this. Fixes: ada8618ff3bfe183 ("serial: stm32: adding support for stm32f7") Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 41d9749231027..cd97ceb76e4ff 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -31,7 +31,7 @@ struct stm32_usart_info { struct stm32_usart_config cfg; }; -#define UNDEF_REG ~0 +#define UNDEF_REG 0xff /* Register offsets */ struct stm32_usart_info stm32f4_info = { -- GitLab From bc2a024f865d712bb5748aabe77cd515d7d5eea9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Oct 2016 15:55:24 +0200 Subject: [PATCH 1039/1167] serial: SERIAL_STM32 should depend on HAS_DMA If NO_DMA=y: drivers/built-in.o: In function `stm32_serial_remove': stm32-usart.c:(.text+0xcea1a): undefined reference to `bad_dma_ops' stm32-usart.c:(.text+0xcea7a): undefined reference to `bad_dma_ops' Add a dependency on HAS_DMA to fix this. Signed-off-by: Geert Uytterhoeven Acked-by: Alexandre Torgue Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index c7831407a882d..25c1d7bc01004 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1625,6 +1625,7 @@ config SERIAL_SPRD_CONSOLE config SERIAL_STM32 tristate "STMicroelectronics STM32 serial port support" select SERIAL_CORE + depends on HAS_DMA depends on ARM || COMPILE_TEST help This driver is for the on-chip Serial Controller on -- GitLab From 0267a4ff9836a1a4e59044db5bb8cdaddb986d3f Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Wed, 12 Oct 2016 13:17:27 +0530 Subject: [PATCH 1040/1167] serial: xuartps: Add new compatible string for ZynqMP This patch Adds the new compatible string for ZynqMP SoC. Signed-off-by: Nava kishore Manne Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index f37edaa5ac757..dd4c02fa4820a 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1200,6 +1200,7 @@ static int __init cdns_early_console_setup(struct earlycon_device *device, OF_EARLYCON_DECLARE(cdns, "xlnx,xuartps", cdns_early_console_setup); OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p8", cdns_early_console_setup); OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p12", cdns_early_console_setup); +OF_EARLYCON_DECLARE(cdns, "xlnx,zynqmp-uart", cdns_early_console_setup); /** * cdns_uart_console_write - perform write operation @@ -1438,6 +1439,7 @@ static const struct of_device_id cdns_uart_of_match[] = { { .compatible = "xlnx,xuartps", }, { .compatible = "cdns,uart-r1p8", }, { .compatible = "cdns,uart-r1p12", .data = &zynqmp_uart_def }, + { .compatible = "xlnx,zynqmp-uart", .data = &zynqmp_uart_def }, {} }; MODULE_DEVICE_TABLE(of, cdns_uart_of_match); -- GitLab From 78c22449f2d32aafd8804047f7e3bee4926b52eb Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Wed, 12 Oct 2016 13:17:28 +0530 Subject: [PATCH 1041/1167] devicetree: bindings: uart: Add new compatible string for ZynqMP This patch Adds the new compatible string for ZynqMP SoC. Signed-off-by: Nava kishore Manne Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/cdns,uart.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/cdns,uart.txt b/Documentation/devicetree/bindings/serial/cdns,uart.txt index a3eb154c32caf..227bb770b0276 100644 --- a/Documentation/devicetree/bindings/serial/cdns,uart.txt +++ b/Documentation/devicetree/bindings/serial/cdns,uart.txt @@ -1,7 +1,9 @@ Binding for Cadence UART Controller Required properties: -- compatible : should be "cdns,uart-r1p8", or "xlnx,xuartps" +- compatible : + Use "xlnx,xuartps","cdns,uart-r1p8" for Zynq-7xxx SoC. + Use "xlnx,zynqmp-uart","cdns,uart-r1p12" for Zynq Ultrascale+ MPSoC. - reg: Should contain UART controller registers location and length. - interrupts: Should contain UART controller interrupts. - clocks: Must contain phandles to the UART clocks -- GitLab From beadba5e19e2c44ec3527d3d1fc3ac3eda957e09 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 23 Oct 2016 11:38:18 +0000 Subject: [PATCH 1042/1167] serial: pch_uart: add terminate entry for dmi_system_id tables Make sure dmi_system_id tables are NULL terminated. Signed-off-by: Wei Yongjun Acked-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index d391650b82e7b..42caccb5e87ee 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -419,6 +419,7 @@ static struct dmi_system_id pch_uart_dmi_table[] = { }, (void *)MINNOW_UARTCLK, }, + { } }; /* Return UART clock, checking for board specific clocks. */ -- GitLab From 0ead21ad25f53117a1e39f0bddcb363e38886996 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 24 Oct 2016 17:00:27 +0900 Subject: [PATCH 1043/1167] serial: 8250_uniphier: fix more unterminated string Commit 1681d2116c96 ("serial: 8250_uniphier: add "\n" at the end of error log") missed this. Signed-off-by: Denys Vlasenko [masahiro: add commit log] Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_uniphier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index b8d9c8c9d02a9..a8babb0cf6597 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -199,7 +199,7 @@ static int uniphier_uart_probe(struct platform_device *pdev) regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { - dev_err(dev, "failed to get memory resource"); + dev_err(dev, "failed to get memory resource\n"); return -EINVAL; } -- GitLab From 09065c5f0f1ff4bfb309975e182b746989a869c5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 24 Oct 2016 17:00:28 +0900 Subject: [PATCH 1044/1167] serial: 8250_uniphier: fix clearing divisor latch access bit At this point, 'value' is always a byte, then this code is clearing bit 15, which is already clear. I meant to clear bit 7. Signed-off-by: Masahiro Yamada Reported-by: Denys Vlasenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_uniphier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index a8babb0cf6597..417d9e7038e1a 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -99,7 +99,7 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value) case UART_LCR: valshift = UNIPHIER_UART_LCR_SHIFT; /* Divisor latch access bit does not exist. */ - value &= ~(UART_LCR_DLAB << valshift); + value &= ~UART_LCR_DLAB; /* fall through */ case UART_MCR: offset = UNIPHIER_UART_LCR_MCR; -- GitLab From be2c92b8f1648527620058fdac2bae12b07f1fe9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 24 Oct 2016 15:56:49 -0500 Subject: [PATCH 1045/1167] serial: core: fix console problems on uart_close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 761ed4a94582 ('tty: serial_core: convert uart_close to use tty_port_close') started setting the ttyport console flag for serial drivers. This is causing crashes, hangs, or garbage output on several platforms because the serial shutdown is skipped and IRQs are left enabled. Partially revert commit 761ed4a94582 and drop reporting UART tty_ports as a console leaving the console handling to the serial_core as it was before. Fixes: 761ed4a94582ab29 ("tty: serial_core: convert uart_close to use tty_port_close") Reported-by: Niklas Söderlund Reported-by: Mike Galbraith Reported-by: Mugunthan V N Cc: Peter Hurley Cc: Geert Uytterhoeven Cc: Alan Cox Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 6e4f63627479d..664c99aeeca58 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2746,8 +2746,6 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) uport->cons = drv->cons; uport->minor = drv->tty_driver->minor_start + uport->line; - port->console = uart_console(uport); - /* * If this port is a console, then the spinlock is already * initialised. -- GitLab From f00a7c57569db04633818bc5e0c0e35d62733b02 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Oct 2016 11:13:48 +0300 Subject: [PATCH 1046/1167] serial: 8250_lpss: enable MSI for sure The commit 4fe0d154880b ("PCI: Use positive flags in pci_alloc_irq_vectors()") replaces flags from negative to positive values which makes mandatory to have the last argument in pci_alloc_irq_vectors() non-zero (if we want to be no-op). This basically drops MSI enabling in 8250_lpss driver. Restore desired behaviour in 8250_lpss by passing PCI_IRQ_ALL_TYPES instead of 0 to pci_alloc_irq_vectors(). Fixes: 60a9244a5d14 ("serial: 8250_lpss: enable MSI for Intel Quark") Cc: Christoph Hellwig Signed-off-by: Andy Shevchenko Reviewed-by: Bryan O'Donoghue Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_lpss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 886fcf37f291a..b9923464599f6 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -213,7 +213,7 @@ static int qrk_serial_setup(struct lpss8250 *lpss, struct uart_port *port) struct pci_dev *pdev = to_pci_dev(port->dev); int ret; - ret = pci_alloc_irq_vectors(pdev, 1, 1, 0); + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); if (ret < 0) return ret; -- GitLab From d704b2d32c39c256dea659e142a31b875a13c63b Mon Sep 17 00:00:00 2001 From: Aaron Brice Date: Thu, 6 Oct 2016 15:13:04 -0700 Subject: [PATCH 1047/1167] tty: serial: fsl_lpuart: Fix Tx DMA edge case In the case where head == 0 on the circular buffer, there should be one DMA buffer, not two. The second zero-length buffer would break the lpuart driver, transfer would never complete. Signed-off-by: Aaron Brice Acked-by: Stefan Agner Tested-by: Stefan Agner Tested-by: Bhuvanchandra DV Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index de9d5107c00a0..76103f2c4a800 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -328,7 +328,7 @@ static void lpuart_dma_tx(struct lpuart_port *sport) sport->dma_tx_bytes = uart_circ_chars_pending(xmit); - if (xmit->tail < xmit->head) { + if (xmit->tail < xmit->head || xmit->head == 0) { sport->dma_tx_nents = 1; sg_init_one(sgl, xmit->buf + xmit->tail, sport->dma_tx_bytes); } else { @@ -359,7 +359,6 @@ static void lpuart_dma_tx(struct lpuart_port *sport) sport->dma_tx_in_progress = true; sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc); dma_async_issue_pending(sport->dma_tx_chan); - } static void lpuart_dma_tx_complete(void *arg) -- GitLab From 32b2921e6a7461fe63b71217067a6cf4bddb132f Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 14 Oct 2016 15:18:28 +0200 Subject: [PATCH 1048/1167] tty: limit terminal size to 4M chars Size of kmalloc() in vc_do_resize() is controlled by user. Too large kmalloc() size triggers WARNING message on console. Put a reasonable upper bound on terminal size to prevent WARNINGs. Signed-off-by: Dmitry Vyukov CC: David Rientjes Cc: One Thousand Gnomes Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: Peter Hurley Cc: linux-kernel@vger.kernel.org Cc: syzkaller@googlegroups.com Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index ae203c2cd15a7..26cda08bc6117 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -870,6 +870,8 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) return 0; + if (new_screen_size > (4 << 20)) + return -EINVAL; newscreen = kmalloc(new_screen_size, GFP_USER); if (!newscreen) return -ENOMEM; -- GitLab From ecb988a3b7985913d1f0112f66667cdd15e40711 Mon Sep 17 00:00:00 2001 From: Steve Shih Date: Mon, 17 Oct 2016 09:51:05 -0700 Subject: [PATCH 1049/1167] tty: serial: 8250: 8250_core: NXP SC16C2552 workaround NXP SC16C2552 requires that we always write a reset to the RX FIFO and TX FIFO whenever we enable the FIFOs Cc: xe-kernel@external.cisco.com Signed-off-by: Steve Shih Signed-off-by: David Singleton Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 1bfb6fdbaa208..1731b98d24710 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -83,7 +83,8 @@ static const struct serial8250_config uart_config[] = { .name = "16550A", .fifo_size = 16, .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, .rxtrig_bytes = {1, 4, 8, 14}, .flags = UART_CAP_FIFO, }, -- GitLab From c03e1b8703a4a0c8bac7f6b65d8fcb539ec62d82 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 21 Oct 2016 23:00:43 +0300 Subject: [PATCH 1050/1167] sh-sci: document R8A7743/5 support Renesas RZ/G SoC also have the SCIF, SCIFA, SCIFB, and HSCIF ports and they seem compatible with the R-Car gen2 SoC in this respect... Document RZ/G1[ME] (also known as R8A774[35]) SoC bindings. Signed-off-by: Sergei Shtylyov Acked-by: Simon Horman Acked-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/renesas,sci-serial.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index 1e4000d83aee0..8d27d1a603e7b 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -9,6 +9,14 @@ Required properties: - "renesas,scifb-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFB compatible UART. - "renesas,scifa-r8a7740" for R8A7740 (R-Mobile A1) SCIFA compatible UART. - "renesas,scifb-r8a7740" for R8A7740 (R-Mobile A1) SCIFB compatible UART. + - "renesas,scif-r8a7743" for R8A7743 (RZ/G1M) SCIF compatible UART. + - "renesas,scifa-r8a7743" for R8A7743 (RZ/G1M) SCIFA compatible UART. + - "renesas,scifb-r8a7743" for R8A7743 (RZ/G1M) SCIFB compatible UART. + - "renesas,hscif-r8a7743" for R8A7743 (RZ/G1M) HSCIF compatible UART. + - "renesas,scif-r8a7745" for R8A7745 (RZ/G1E) SCIF compatible UART. + - "renesas,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART. + - "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART. + - "renesas,hscif-r8a7745" for R8A7745 (RZ/G1E) HSCIF compatible UART. - "renesas,scif-r8a7778" for R8A7778 (R-Car M1) SCIF compatible UART. - "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART. - "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART. -- GitLab From 03842c17397e14cb8bb1adc2015f5dce6c733ffe Mon Sep 17 00:00:00 2001 From: Francois Berder Date: Tue, 25 Oct 2016 13:24:13 +0100 Subject: [PATCH 1051/1167] sc16is7xx: always write state when configuring GPIO as an output The regmap_update first reads the IOState register and then triggers a write if needed. However, GPIOS might be configured as an input so the read to IOState on this GPIO is the current state which might be random. Signed-off-by: Francois Berder Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 2675792a8f596..fb0672554123a 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1130,9 +1130,13 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, { struct sc16is7xx_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[0].port; + u8 state = sc16is7xx_port_read(port, SC16IS7XX_IOSTATE_REG); - sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), - val ? BIT(offset) : 0); + if (val) + state |= BIT(offset); + else + state &= ~BIT(offset); + sc16is7xx_port_write(port, SC16IS7XX_IOSTATE_REG, state); sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), BIT(offset)); -- GitLab From 009e39ae44f4191188aeb6dfbf661b771dbbe515 Mon Sep 17 00:00:00 2001 From: Scot Doyle Date: Thu, 13 Oct 2016 12:12:43 -0500 Subject: [PATCH 1052/1167] vt: clear selection before resizing When resizing a vt its selection may exceed the new size, resulting in an invalid memory access [1]. Clear the selection before resizing. [1] http://lkml.kernel.org/r/CACT4Y+acDTwy4umEvf5ROBGiRJNrxHN4Cn5szCXE5Jw-d1B=Xw@mail.gmail.com Reported-and-tested-by: Dmitry Vyukov Signed-off-by: Scot Doyle Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 26cda08bc6117..8c3bf3d613c06 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -876,6 +876,9 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (!newscreen) return -ENOMEM; + if (vc == sel_cons) + clear_selection(); + old_rows = vc->vc_rows; old_row_size = vc->vc_size_row; -- GitLab From 2a9becdd4dbed499815938308bdab9aae70dd561 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 14 Oct 2016 10:56:42 -0700 Subject: [PATCH 1053/1167] kernfs: Add noop_fsync to supported kernfs_file_fops If you edit a kernfs backed file with vi(1), you see an ugly error message when you write the file because vi tries to fsync(2) the file after writing, which fails. We have noop_fsync() for this, use it. Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 2bcb86e6e6ca0..78219d5644e90 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -911,6 +911,7 @@ const struct file_operations kernfs_file_fops = { .open = kernfs_fop_open, .release = kernfs_fop_release, .poll = kernfs_fop_poll, + .fsync = noop_fsync, }; /** -- GitLab From 248ff02165437864146d6fbd2d99b2359c3723e6 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Fri, 7 Oct 2016 09:09:30 -0700 Subject: [PATCH 1054/1167] driver core: Make Kconfig text for DEBUG_TEST_DRIVER_REMOVE stronger The current state of driver removal is not great. CONFIG_DEBUG_TEST_DRIVER_REMOVE finds lots of errors. The help text currently undersells exactly how many errors this option will find. Add a bit more description to indicate this option shouldn't be turned on unless you actually want to debug driver removal. The text can be changed later when more drivers are fixed up. Signed-off-by: Laura Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/base/Kconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index fdf44cac08e6d..d02e7c0f5bfdf 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -213,14 +213,16 @@ config DEBUG_DEVRES If you are unsure about this, Say N here. config DEBUG_TEST_DRIVER_REMOVE - bool "Test driver remove calls during probe" + bool "Test driver remove calls during probe (UNSTABLE)" depends on DEBUG_KERNEL help Say Y here if you want the Driver core to test driver remove functions by calling probe, remove, probe. This tests the remove path without having to unbind the driver or unload the driver module. - If you are unsure about this, say N here. + This option is expected to find errors and may render your system + unusable. You should say N here unless you are explicitly looking to + test this functionality. config SYS_HYPERVISOR bool -- GitLab From 7fe311302f7d52601cd799ad508a6f92cb3d748d Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 27 Oct 2016 09:49:19 -0600 Subject: [PATCH 1055/1167] blk-mq: update hardware and software queues for sleeping alloc If we end up sleeping due to running out of requests, we should update the hardware and software queues in the map ctx structure. Otherwise we could end up having rq->mq_ctx point to the pre-sleep context, and risk corrupting ctx->rq_list since we'll be grabbing the wrong lock when inserting the request. Reported-by: Dave Jones Reported-by: Chris Mason Tested-by: Chris Mason Fixes: 63581af3f31e ("blk-mq: remove non-blocking pass in blk_mq_map_request") Signed-off-by: Jens Axboe --- block/blk-mq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index ddc2eed647714..f3d27a6dee09d 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1217,9 +1217,9 @@ static struct request *blk_mq_map_request(struct request_queue *q, blk_mq_set_alloc_data(&alloc_data, q, 0, ctx, hctx); rq = __blk_mq_alloc_request(&alloc_data, op, op_flags); - hctx->queued++; - data->hctx = hctx; - data->ctx = ctx; + data->hctx = alloc_data.hctx; + data->ctx = alloc_data.ctx; + data->hctx->queued++; return rq; } -- GitLab From 9dcb8b685fc30813b35ab4b4bf39244430753190 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 26 Oct 2016 10:15:30 -0700 Subject: [PATCH 1056/1167] mm: remove per-zone hashtable of bitlock waitqueues The per-zone waitqueues exist because of a scalability issue with the page waitqueues on some NUMA machines, but it turns out that they hurt normal loads, and now with the vmalloced stacks they also end up breaking gfs2 that uses a bit_wait on a stack object: wait_on_bit(&gh->gh_iflags, HIF_WAIT, TASK_UNINTERRUPTIBLE) where 'gh' can be a reference to the local variable 'mount_gh' on the stack of fill_super(). The reason the per-zone hash table breaks for this case is that there is no "zone" for virtual allocations, and trying to look up the physical page to get at it will fail (with a BUG_ON()). It turns out that I actually complained to the mm people about the per-zone hash table for another reason just a month ago: the zone lookup also hurts the regular use of "unlock_page()" a lot, because the zone lookup ends up forcing several unnecessary cache misses and generates horrible code. As part of that earlier discussion, we had a much better solution for the NUMA scalability issue - by just making the page lock have a separate contention bit, the waitqueue doesn't even have to be looked at for the normal case. Peter Zijlstra already has a patch for that, but let's see if anybody even notices. In the meantime, let's fix the actual gfs2 breakage by simplifying the bitlock waitqueues and removing the per-zone issue. Reported-by: Andreas Gruenbacher Tested-by: Bob Peterson Acked-by: Mel Gorman Cc: Peter Zijlstra Cc: Andy Lutomirski Cc: Steven Whitehouse Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 30 +---------- kernel/sched/core.c | 16 ++++++ kernel/sched/wait.c | 10 ---- mm/filemap.c | 4 +- mm/memory_hotplug.c | 28 ---------- mm/page_alloc.c | 115 +---------------------------------------- 6 files changed, 21 insertions(+), 182 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 7f2ae99e5daf3..0f088f3a2fed8 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -440,33 +440,7 @@ struct zone { seqlock_t span_seqlock; #endif - /* - * wait_table -- the array holding the hash table - * wait_table_hash_nr_entries -- the size of the hash table array - * wait_table_bits -- wait_table_size == (1 << wait_table_bits) - * - * The purpose of all these is to keep track of the people - * waiting for a page to become available and make them - * runnable again when possible. The trouble is that this - * consumes a lot of space, especially when so few things - * wait on pages at a given time. So instead of using - * per-page waitqueues, we use a waitqueue hash table. - * - * The bucket discipline is to sleep on the same queue when - * colliding and wake all in that wait queue when removing. - * When something wakes, it must check to be sure its page is - * truly available, a la thundering herd. The cost of a - * collision is great, but given the expected load of the - * table, they should be so rare as to be outweighed by the - * benefits from the saved space. - * - * __wait_on_page_locked() and unlock_page() in mm/filemap.c, are the - * primary users of these fields, and in mm/page_alloc.c - * free_area_init_core() performs the initialization of them. - */ - wait_queue_head_t *wait_table; - unsigned long wait_table_hash_nr_entries; - unsigned long wait_table_bits; + int initialized; /* Write-intensive fields used from the page allocator */ ZONE_PADDING(_pad1_) @@ -546,7 +520,7 @@ static inline bool zone_spans_pfn(const struct zone *zone, unsigned long pfn) static inline bool zone_is_initialized(struct zone *zone) { - return !!zone->wait_table; + return zone->initialized; } static inline bool zone_is_empty(struct zone *zone) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 94732d1ab00ab..42d4027f9e265 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7515,11 +7515,27 @@ static struct kmem_cache *task_group_cache __read_mostly; DECLARE_PER_CPU(cpumask_var_t, load_balance_mask); DECLARE_PER_CPU(cpumask_var_t, select_idle_mask); +#define WAIT_TABLE_BITS 8 +#define WAIT_TABLE_SIZE (1 << WAIT_TABLE_BITS) +static wait_queue_head_t bit_wait_table[WAIT_TABLE_SIZE] __cacheline_aligned; + +wait_queue_head_t *bit_waitqueue(void *word, int bit) +{ + const int shift = BITS_PER_LONG == 32 ? 5 : 6; + unsigned long val = (unsigned long)word << shift | bit; + + return bit_wait_table + hash_long(val, WAIT_TABLE_BITS); +} +EXPORT_SYMBOL(bit_waitqueue); + void __init sched_init(void) { int i, j; unsigned long alloc_size = 0, ptr; + for (i = 0; i < WAIT_TABLE_SIZE; i++) + init_waitqueue_head(bit_wait_table + i); + #ifdef CONFIG_FAIR_GROUP_SCHED alloc_size += 2 * nr_cpu_ids * sizeof(void **); #endif diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c index 4f7053579fe3c..9453efe9b25a6 100644 --- a/kernel/sched/wait.c +++ b/kernel/sched/wait.c @@ -480,16 +480,6 @@ void wake_up_bit(void *word, int bit) } EXPORT_SYMBOL(wake_up_bit); -wait_queue_head_t *bit_waitqueue(void *word, int bit) -{ - const int shift = BITS_PER_LONG == 32 ? 5 : 6; - const struct zone *zone = page_zone(virt_to_page(word)); - unsigned long val = (unsigned long)word << shift | bit; - - return &zone->wait_table[hash_long(val, zone->wait_table_bits)]; -} -EXPORT_SYMBOL(bit_waitqueue); - /* * Manipulate the atomic_t address to produce a better bit waitqueue table hash * index (we're keying off bit -1, but that would produce a horrible hash diff --git a/mm/filemap.c b/mm/filemap.c index 849f459ad0780..c7fe2f16503f9 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -790,9 +790,7 @@ EXPORT_SYMBOL(__page_cache_alloc); */ wait_queue_head_t *page_waitqueue(struct page *page) { - const struct zone *zone = page_zone(page); - - return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)]; + return bit_waitqueue(page, 0); } EXPORT_SYMBOL(page_waitqueue); diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 962927309b6e9..b18dab401be6e 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -268,7 +268,6 @@ void __init register_page_bootmem_info_node(struct pglist_data *pgdat) unsigned long i, pfn, end_pfn, nr_pages; int node = pgdat->node_id; struct page *page; - struct zone *zone; nr_pages = PAGE_ALIGN(sizeof(struct pglist_data)) >> PAGE_SHIFT; page = virt_to_page(pgdat); @@ -276,19 +275,6 @@ void __init register_page_bootmem_info_node(struct pglist_data *pgdat) for (i = 0; i < nr_pages; i++, page++) get_page_bootmem(node, page, NODE_INFO); - zone = &pgdat->node_zones[0]; - for (; zone < pgdat->node_zones + MAX_NR_ZONES - 1; zone++) { - if (zone_is_initialized(zone)) { - nr_pages = zone->wait_table_hash_nr_entries - * sizeof(wait_queue_head_t); - nr_pages = PAGE_ALIGN(nr_pages) >> PAGE_SHIFT; - page = virt_to_page(zone->wait_table); - - for (i = 0; i < nr_pages; i++, page++) - get_page_bootmem(node, page, NODE_INFO); - } - } - pfn = pgdat->node_start_pfn; end_pfn = pgdat_end_pfn(pgdat); @@ -2158,20 +2144,6 @@ void try_offline_node(int nid) */ node_set_offline(nid); unregister_one_node(nid); - - /* free waittable in each zone */ - for (i = 0; i < MAX_NR_ZONES; i++) { - struct zone *zone = pgdat->node_zones + i; - - /* - * wait_table may be allocated from boot memory, - * here only free if it's allocated by vmalloc. - */ - if (is_vmalloc_addr(zone->wait_table)) { - vfree(zone->wait_table); - zone->wait_table = NULL; - } - } } EXPORT_SYMBOL(try_offline_node); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 2b3bf6767d544..de7c6e43b1c96 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4976,72 +4976,6 @@ void __ref build_all_zonelists(pg_data_t *pgdat, struct zone *zone) #endif } -/* - * Helper functions to size the waitqueue hash table. - * Essentially these want to choose hash table sizes sufficiently - * large so that collisions trying to wait on pages are rare. - * But in fact, the number of active page waitqueues on typical - * systems is ridiculously low, less than 200. So this is even - * conservative, even though it seems large. - * - * The constant PAGES_PER_WAITQUEUE specifies the ratio of pages to - * waitqueues, i.e. the size of the waitq table given the number of pages. - */ -#define PAGES_PER_WAITQUEUE 256 - -#ifndef CONFIG_MEMORY_HOTPLUG -static inline unsigned long wait_table_hash_nr_entries(unsigned long pages) -{ - unsigned long size = 1; - - pages /= PAGES_PER_WAITQUEUE; - - while (size < pages) - size <<= 1; - - /* - * Once we have dozens or even hundreds of threads sleeping - * on IO we've got bigger problems than wait queue collision. - * Limit the size of the wait table to a reasonable size. - */ - size = min(size, 4096UL); - - return max(size, 4UL); -} -#else -/* - * A zone's size might be changed by hot-add, so it is not possible to determine - * a suitable size for its wait_table. So we use the maximum size now. - * - * The max wait table size = 4096 x sizeof(wait_queue_head_t). ie: - * - * i386 (preemption config) : 4096 x 16 = 64Kbyte. - * ia64, x86-64 (no preemption): 4096 x 20 = 80Kbyte. - * ia64, x86-64 (preemption) : 4096 x 24 = 96Kbyte. - * - * The maximum entries are prepared when a zone's memory is (512K + 256) pages - * or more by the traditional way. (See above). It equals: - * - * i386, x86-64, powerpc(4K page size) : = ( 2G + 1M)byte. - * ia64(16K page size) : = ( 8G + 4M)byte. - * powerpc (64K page size) : = (32G +16M)byte. - */ -static inline unsigned long wait_table_hash_nr_entries(unsigned long pages) -{ - return 4096UL; -} -#endif - -/* - * This is an integer logarithm so that shifts can be used later - * to extract the more random high bits from the multiplicative - * hash function before the remainder is taken. - */ -static inline unsigned long wait_table_bits(unsigned long size) -{ - return ffz(~size); -} - /* * Initially all pages are reserved - free ones are freed * up by free_all_bootmem() once the early boot process is @@ -5304,49 +5238,6 @@ void __init setup_per_cpu_pageset(void) alloc_percpu(struct per_cpu_nodestat); } -static noinline __ref -int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages) -{ - int i; - size_t alloc_size; - - /* - * The per-page waitqueue mechanism uses hashed waitqueues - * per zone. - */ - zone->wait_table_hash_nr_entries = - wait_table_hash_nr_entries(zone_size_pages); - zone->wait_table_bits = - wait_table_bits(zone->wait_table_hash_nr_entries); - alloc_size = zone->wait_table_hash_nr_entries - * sizeof(wait_queue_head_t); - - if (!slab_is_available()) { - zone->wait_table = (wait_queue_head_t *) - memblock_virt_alloc_node_nopanic( - alloc_size, zone->zone_pgdat->node_id); - } else { - /* - * This case means that a zone whose size was 0 gets new memory - * via memory hot-add. - * But it may be the case that a new node was hot-added. In - * this case vmalloc() will not be able to use this new node's - * memory - this wait_table must be initialized to use this new - * node itself as well. - * To use this new node's memory, further consideration will be - * necessary. - */ - zone->wait_table = vmalloc(alloc_size); - } - if (!zone->wait_table) - return -ENOMEM; - - for (i = 0; i < zone->wait_table_hash_nr_entries; ++i) - init_waitqueue_head(zone->wait_table + i); - - return 0; -} - static __meminit void zone_pcp_init(struct zone *zone) { /* @@ -5367,10 +5258,7 @@ int __meminit init_currently_empty_zone(struct zone *zone, unsigned long size) { struct pglist_data *pgdat = zone->zone_pgdat; - int ret; - ret = zone_wait_table_init(zone, size); - if (ret) - return ret; + pgdat->nr_zones = zone_idx(zone) + 1; zone->zone_start_pfn = zone_start_pfn; @@ -5382,6 +5270,7 @@ int __meminit init_currently_empty_zone(struct zone *zone, zone_start_pfn, (zone_start_pfn + size)); zone_init_free_lists(zone); + zone->initialized = 1; return 0; } -- GitLab From 570dd45042a7c8a7aba1ee029c5dd0f5ccf41b9b Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 27 Oct 2016 10:42:20 -0700 Subject: [PATCH 1057/1167] btrfs: fix races on root_log_ctx lists btrfs_remove_all_log_ctxs takes a shortcut where it avoids walking the list because it knows all of the waiters are patiently waiting for the commit to finish. But, there's a small race where btrfs_sync_log can remove itself from the list if it finds a log commit is already done. Also, it uses list_del_init() to remove itself from the list, but there's no way to know if btrfs_remove_all_log_ctxs has already run, so we don't know for sure if it is safe to call list_del_init(). This gets rid of all the shortcuts for btrfs_remove_all_log_ctxs(), and just calls it with the proper locking. This is part two of the corruption fixed by cbd60aa7cd1. I should have done this in the first place, but convinced myself the optimizations were safe. A 12 hour run of dbench 2048 will eventually trigger a list debug WARN_ON for the list_del_init() in btrfs_sync_log(). Fixes: d1433debe7f4346cf9fc0dafc71c3137d2a97bc4 Reported-by: Dave Jones cc: stable@vger.kernel.org # 3.15+ Signed-off-by: Chris Mason --- fs/btrfs/tree-log.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 688df71c1bf7c..4b1c0a6eee042 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2713,14 +2713,12 @@ static inline void btrfs_remove_all_log_ctxs(struct btrfs_root *root, int index, int error) { struct btrfs_log_ctx *ctx; + struct btrfs_log_ctx *safe; - if (!error) { - INIT_LIST_HEAD(&root->log_ctxs[index]); - return; - } - - list_for_each_entry(ctx, &root->log_ctxs[index], list) + list_for_each_entry_safe(ctx, safe, &root->log_ctxs[index], list) { + list_del_init(&ctx->list); ctx->log_ret = error; + } INIT_LIST_HEAD(&root->log_ctxs[index]); } @@ -2961,13 +2959,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, mutex_unlock(&root->log_mutex); out_wake_log_root: - /* - * We needn't get log_mutex here because we are sure all - * the other tasks are blocked. - */ + mutex_lock(&log_root_tree->log_mutex); btrfs_remove_all_log_ctxs(log_root_tree, index2, ret); - mutex_lock(&log_root_tree->log_mutex); log_root_tree->log_transid_committed++; atomic_set(&log_root_tree->log_commit[index2], 0); mutex_unlock(&log_root_tree->log_mutex); @@ -2978,10 +2972,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) wake_up(&log_root_tree->log_commit_wait[index2]); out: - /* See above. */ - btrfs_remove_all_log_ctxs(root, index1, ret); - mutex_lock(&root->log_mutex); + btrfs_remove_all_log_ctxs(root, index1, ret); root->log_transid_committed++; atomic_set(&root->log_commit[index1], 0); mutex_unlock(&root->log_mutex); -- GitLab From 4fc6d239ee5640909932c47f3c7b93dd8e415fea Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Mon, 24 Oct 2016 12:40:53 +0200 Subject: [PATCH 1058/1167] Revert "at803x: fix suspend/resume for SGMII link" This reverts commit 98267311fe3b334ae7c107fa0e2413adcf3ba735. Suspending the SGMII alongside the copper side made the at803x inaccessable while powered down, e.g. it can't be re-probed after suspend. Signed-off-by: Zefir Kurtisi Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index f279a897a5c7f..cf74d108953e7 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -52,9 +52,6 @@ #define AT803X_DEBUG_REG_5 0x05 #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) -#define AT803X_REG_CHIP_CONFIG 0x1f -#define AT803X_BT_BX_REG_SEL 0x8000 - #define ATH8030_PHY_ID 0x004dd076 #define ATH8031_PHY_ID 0x004dd074 #define ATH8035_PHY_ID 0x004dd072 @@ -209,7 +206,6 @@ static int at803x_suspend(struct phy_device *phydev) { int value; int wol_enabled; - int ccr; mutex_lock(&phydev->lock); @@ -225,16 +221,6 @@ static int at803x_suspend(struct phy_device *phydev) phy_write(phydev, MII_BMCR, value); - if (phydev->interface != PHY_INTERFACE_MODE_SGMII) - goto done; - - /* also power-down SGMII interface */ - ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); - phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL); - phy_write(phydev, MII_BMCR, phy_read(phydev, MII_BMCR) | BMCR_PDOWN); - phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL); - -done: mutex_unlock(&phydev->lock); return 0; @@ -243,7 +229,6 @@ static int at803x_suspend(struct phy_device *phydev) static int at803x_resume(struct phy_device *phydev) { int value; - int ccr; mutex_lock(&phydev->lock); @@ -251,17 +236,6 @@ static int at803x_resume(struct phy_device *phydev) value &= ~(BMCR_PDOWN | BMCR_ISOLATE); phy_write(phydev, MII_BMCR, value); - if (phydev->interface != PHY_INTERFACE_MODE_SGMII) - goto done; - - /* also power-up SGMII interface */ - ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); - phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL); - value = phy_read(phydev, MII_BMCR) & ~(BMCR_PDOWN | BMCR_ISOLATE); - phy_write(phydev, MII_BMCR, value); - phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL); - -done: mutex_unlock(&phydev->lock); return 0; -- GitLab From f62265b53ef34a372b657c99e23d32e95b464316 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Mon, 24 Oct 2016 12:40:54 +0200 Subject: [PATCH 1059/1167] at803x: double check SGMII side autoneg In SGMII mode, we observed an autonegotiation issue after power-down-up cycles where the copper side reports successful link establishment but the SGMII side's link is down. This happened in a setup where the at8031 is connected over SGMII to a eTSEC (fsl gianfar), but so far could not be reproduced with other Ethernet device / driver combinations. This commit adds a wrapper function for at8031 that in case of operating in SGMII mode double checks SGMII link state when generic aneg_done() succeeds. It prints a warning on failure but intentionally does not try to recover from this state. As a result, if you ever see a warning '803x_aneg_done: SGMII link is not ok' you will end up having an Ethernet link up but won't get any data through. This should not happen, if it does, please contact the module maintainer. Signed-off-by: Zefir Kurtisi Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index cf74d108953e7..a52b560e428b8 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -42,10 +42,18 @@ #define AT803X_MMD_ACCESS_CONTROL 0x0D #define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E #define AT803X_FUNC_DATA 0x4003 +#define AT803X_REG_CHIP_CONFIG 0x1f +#define AT803X_BT_BX_REG_SEL 0x8000 #define AT803X_DEBUG_ADDR 0x1D #define AT803X_DEBUG_DATA 0x1E +#define AT803X_MODE_CFG_MASK 0x0F +#define AT803X_MODE_CFG_SGMII 0x01 + +#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ +#define AT803X_PSSR_MR_AN_COMPLETE 0x0200 + #define AT803X_DEBUG_REG_0 0x00 #define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) @@ -355,6 +363,36 @@ static void at803x_link_change_notify(struct phy_device *phydev) } } +static int at803x_aneg_done(struct phy_device *phydev) +{ + int ccr; + + int aneg_done = genphy_aneg_done(phydev); + if (aneg_done != BMSR_ANEGCOMPLETE) + return aneg_done; + + /* + * in SGMII mode, if copper side autoneg is successful, + * also check SGMII side autoneg result + */ + ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); + if ((ccr & AT803X_MODE_CFG_MASK) != AT803X_MODE_CFG_SGMII) + return aneg_done; + + /* switch to SGMII/fiber page */ + phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL); + + /* check if the SGMII link is OK. */ + if (!(phy_read(phydev, AT803X_PSSR) & AT803X_PSSR_MR_AN_COMPLETE)) { + pr_warn("803x_aneg_done: SGMII link is not ok\n"); + aneg_done = 0; + } + /* switch back to copper page */ + phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL); + + return aneg_done; +} + static struct phy_driver at803x_driver[] = { { /* ATHEROS 8035 */ @@ -406,6 +444,7 @@ static struct phy_driver at803x_driver[] = { .flags = PHY_HAS_INTERRUPT, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .aneg_done = at803x_aneg_done, .ack_interrupt = &at803x_ack_interrupt, .config_intr = &at803x_config_intr, } }; -- GitLab From e0f841f5cbf2a195c63f3441f3d8ef1cd2bdeeed Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 24 Oct 2016 15:44:26 +0200 Subject: [PATCH 1060/1167] macsec: Fix header length if SCI is added if explicitly disabled Even if sending SCIs is explicitly disabled, the code that creates the Security Tag might still decide to add it (e.g. if multiple RX SCs are defined on the MACsec interface). But because the header length so far only depended on the configuration option the SCI overwrote the original frame's contents (EtherType and e.g. the beginning of the IP header) and if encrypted did not visibly end up in the packet, while the SC flag in the TCI field of the Security Tag was still set, resulting in invalid MACsec frames. Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver") Signed-off-by: Tobias Brunner Acked-by: Sabrina Dubroca Signed-off-by: David S. Miller --- drivers/net/macsec.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 3ea47f28e143b..d2e61e0029262 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -397,6 +397,14 @@ static struct macsec_cb *macsec_skb_cb(struct sk_buff *skb) #define DEFAULT_ENCRYPT false #define DEFAULT_ENCODING_SA 0 +static bool send_sci(const struct macsec_secy *secy) +{ + const struct macsec_tx_sc *tx_sc = &secy->tx_sc; + + return tx_sc->send_sci || + (secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb); +} + static sci_t make_sci(u8 *addr, __be16 port) { sci_t sci; @@ -437,15 +445,15 @@ static unsigned int macsec_extra_len(bool sci_present) /* Fill SecTAG according to IEEE 802.1AE-2006 10.5.3 */ static void macsec_fill_sectag(struct macsec_eth_header *h, - const struct macsec_secy *secy, u32 pn) + const struct macsec_secy *secy, u32 pn, + bool sci_present) { const struct macsec_tx_sc *tx_sc = &secy->tx_sc; - memset(&h->tci_an, 0, macsec_sectag_len(tx_sc->send_sci)); + memset(&h->tci_an, 0, macsec_sectag_len(sci_present)); h->eth.h_proto = htons(ETH_P_MACSEC); - if (tx_sc->send_sci || - (secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb)) { + if (sci_present) { h->tci_an |= MACSEC_TCI_SC; memcpy(&h->secure_channel_id, &secy->sci, sizeof(h->secure_channel_id)); @@ -650,6 +658,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, struct macsec_tx_sc *tx_sc; struct macsec_tx_sa *tx_sa; struct macsec_dev *macsec = macsec_priv(dev); + bool sci_present; u32 pn; secy = &macsec->secy; @@ -687,7 +696,8 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, unprotected_len = skb->len; eth = eth_hdr(skb); - hh = (struct macsec_eth_header *)skb_push(skb, macsec_extra_len(tx_sc->send_sci)); + sci_present = send_sci(secy); + hh = (struct macsec_eth_header *)skb_push(skb, macsec_extra_len(sci_present)); memmove(hh, eth, 2 * ETH_ALEN); pn = tx_sa_update_pn(tx_sa, secy); @@ -696,7 +706,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, kfree_skb(skb); return ERR_PTR(-ENOLINK); } - macsec_fill_sectag(hh, secy, pn); + macsec_fill_sectag(hh, secy, pn, sci_present); macsec_set_shortlen(hh, unprotected_len - 2 * ETH_ALEN); skb_put(skb, secy->icv_len); @@ -726,10 +736,10 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, skb_to_sgvec(skb, sg, 0, skb->len); if (tx_sc->encrypt) { - int len = skb->len - macsec_hdr_len(tx_sc->send_sci) - + int len = skb->len - macsec_hdr_len(sci_present) - secy->icv_len; aead_request_set_crypt(req, sg, sg, len, iv); - aead_request_set_ad(req, macsec_hdr_len(tx_sc->send_sci)); + aead_request_set_ad(req, macsec_hdr_len(sci_present)); } else { aead_request_set_crypt(req, sg, sg, 0, iv); aead_request_set_ad(req, skb->len - secy->icv_len); -- GitLab From e30520c2b075fae3977d482a31b54b0256160a57 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 24 Oct 2016 17:54:18 +0200 Subject: [PATCH 1061/1167] kalmia: avoid potential uninitialized variable use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kalmia_send_init_packet() returns zero or a negative return code, but gcc has no way of knowing that there cannot be a positive return code, so it determines that copying the ethernet address at the end of kalmia_bind() will access uninitialized data: drivers/net/usb/kalmia.c: In function ‘kalmia_bind’: arch/x86/include/asm/string_32.h:78:22: error: ‘*((void *)ðernet_addr+4)’ may be used uninitialized in this function [-Werror=maybe-uninitialized] *((short *)to + 2) = *((short *)from + 2); ^ drivers/net/usb/kalmia.c:138:5: note: ‘*((void *)ðernet_addr+4)’ was declared here This warning is harmless, but for consistency, we should make the check for the return code match what the driver does everywhere else and just progate it, which then gets rid of the warning. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/usb/kalmia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c index 5662babf05832..3e37724d30ae7 100644 --- a/drivers/net/usb/kalmia.c +++ b/drivers/net/usb/kalmia.c @@ -151,7 +151,7 @@ kalmia_bind(struct usbnet *dev, struct usb_interface *intf) status = kalmia_init_and_get_ethernet_addr(dev, ethernet_addr); - if (status < 0) { + if (status) { usb_set_intfdata(intf, NULL); usb_driver_release_interface(driver_of(intf), intf); return status; -- GitLab From 830218c1add1da16519b71909e5cf21522b7d062 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 24 Oct 2016 10:52:35 -0700 Subject: [PATCH 1062/1167] net: ipv6: Fix processing of RAs in presence of VRF rt6_add_route_info and rt6_add_dflt_router were updated to pull the FIB table from the device index, but the corresponding rt6_get_route_info and rt6_get_dflt_router functions were not leading to the failure to process RA's: ICMPv6: RA: ndisc_router_discovery failed to add default route Fix the 'get' functions by using the table id associated with the device when applicable. Also, now that default routes can be added to tables other than the default table, rt6_purge_dflt_routers needs to be updated as well to look at all tables. To handle that efficiently, add a flag to the table denoting if it is has a default route via RA. Fixes: ca254490c8dfd ("net: Add VRF support to IPv6 stack") Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 2 ++ net/ipv6/route.c | 68 ++++++++++++++++++++++++++++++------------- 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index fb961a576abe4..a74e2aa40ef42 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -230,6 +230,8 @@ struct fib6_table { rwlock_t tb6_lock; struct fib6_node tb6_root; struct inet_peer_base tb6_peers; + unsigned int flags; +#define RT6_TABLE_HAS_DFLT_ROUTER BIT(0) }; #define RT6_TABLE_UNSPEC RT_TABLE_UNSPEC diff --git a/net/ipv6/route.c b/net/ipv6/route.c index bdbc38e8bf290..3ac19eb81a86e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -102,11 +102,13 @@ static int rt6_score_route(struct rt6_info *rt, int oif, int strict); #ifdef CONFIG_IPV6_ROUTE_INFO static struct rt6_info *rt6_add_route_info(struct net *net, const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, int ifindex, + const struct in6_addr *gwaddr, + struct net_device *dev, unsigned int pref); static struct rt6_info *rt6_get_route_info(struct net *net, const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, int ifindex); + const struct in6_addr *gwaddr, + struct net_device *dev); #endif struct uncached_list { @@ -803,7 +805,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, rt = rt6_get_dflt_router(gwaddr, dev); else rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, - gwaddr, dev->ifindex); + gwaddr, dev); if (rt && !lifetime) { ip6_del_rt(rt); @@ -811,8 +813,8 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, } if (!rt && lifetime) - rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex, - pref); + rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, + dev, pref); else if (rt) rt->rt6i_flags = RTF_ROUTEINFO | (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); @@ -2325,13 +2327,16 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) #ifdef CONFIG_IPV6_ROUTE_INFO static struct rt6_info *rt6_get_route_info(struct net *net, const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, int ifindex) + const struct in6_addr *gwaddr, + struct net_device *dev) { + u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO; + int ifindex = dev->ifindex; struct fib6_node *fn; struct rt6_info *rt = NULL; struct fib6_table *table; - table = fib6_get_table(net, RT6_TABLE_INFO); + table = fib6_get_table(net, tb_id); if (!table) return NULL; @@ -2357,12 +2362,13 @@ static struct rt6_info *rt6_get_route_info(struct net *net, static struct rt6_info *rt6_add_route_info(struct net *net, const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, int ifindex, + const struct in6_addr *gwaddr, + struct net_device *dev, unsigned int pref) { struct fib6_config cfg = { .fc_metric = IP6_RT_PRIO_USER, - .fc_ifindex = ifindex, + .fc_ifindex = dev->ifindex, .fc_dst_len = prefixlen, .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref), @@ -2371,7 +2377,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net, .fc_nlinfo.nl_net = net, }; - cfg.fc_table = l3mdev_fib_table_by_index(net, ifindex) ? : RT6_TABLE_INFO; + cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO, cfg.fc_dst = *prefix; cfg.fc_gateway = *gwaddr; @@ -2381,16 +2387,17 @@ static struct rt6_info *rt6_add_route_info(struct net *net, ip6_route_add(&cfg); - return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex); + return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev); } #endif struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev) { + u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT; struct rt6_info *rt; struct fib6_table *table; - table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT); + table = fib6_get_table(dev_net(dev), tb_id); if (!table) return NULL; @@ -2424,20 +2431,20 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, cfg.fc_gateway = *gwaddr; - ip6_route_add(&cfg); + if (!ip6_route_add(&cfg)) { + struct fib6_table *table; + + table = fib6_get_table(dev_net(dev), cfg.fc_table); + if (table) + table->flags |= RT6_TABLE_HAS_DFLT_ROUTER; + } return rt6_get_dflt_router(gwaddr, dev); } -void rt6_purge_dflt_routers(struct net *net) +static void __rt6_purge_dflt_routers(struct fib6_table *table) { struct rt6_info *rt; - struct fib6_table *table; - - /* NOTE: Keep consistent with rt6_get_dflt_router */ - table = fib6_get_table(net, RT6_TABLE_DFLT); - if (!table) - return; restart: read_lock_bh(&table->tb6_lock); @@ -2451,6 +2458,27 @@ void rt6_purge_dflt_routers(struct net *net) } } read_unlock_bh(&table->tb6_lock); + + table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER; +} + +void rt6_purge_dflt_routers(struct net *net) +{ + struct fib6_table *table; + struct hlist_head *head; + unsigned int h; + + rcu_read_lock(); + + for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { + head = &net->ipv6.fib_table_hash[h]; + hlist_for_each_entry_rcu(table, head, tb6_hlist) { + if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER) + __rt6_purge_dflt_routers(table); + } + } + + rcu_read_unlock(); } static void rtmsg_to_fib6_config(struct net *net, -- GitLab From d5d32e4b76687f4df9ad3ba8d3702b7347f51fa6 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 24 Oct 2016 12:27:23 -0700 Subject: [PATCH 1063/1167] net: ipv6: Do not consider link state for nexthop validation Similar to IPv4, do not consider link state when validating next hops. Currently, if the link is down default routes can fail to insert: $ ip -6 ro add vrf blue default via 2100:2::64 dev eth2 RTNETLINK answers: No route to host With this patch the command succeeds. Fixes: 8c14586fc320 ("net: ipv6: Use passed in table for nexthop lookups") Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip6_route.h | 1 + net/ipv6/route.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index e0cd318d5103f..f83e78d071a30 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -32,6 +32,7 @@ struct route_info { #define RT6_LOOKUP_F_SRCPREF_TMP 0x00000008 #define RT6_LOOKUP_F_SRCPREF_PUBLIC 0x00000010 #define RT6_LOOKUP_F_SRCPREF_COA 0x00000020 +#define RT6_LOOKUP_F_IGNORE_LINKSTATE 0x00000040 /* We do not (yet ?) support IPv6 jumbograms (RFC 2675) * Unlike IPv4, hdr->seg_len doesn't include the IPv6 header diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 3ac19eb81a86e..947ed1ded0263 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -658,7 +658,8 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, struct net_device *dev = rt->dst.dev; if (dev && !netif_carrier_ok(dev) && - idev->cnf.ignore_routes_with_linkdown) + idev->cnf.ignore_routes_with_linkdown && + !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) goto out; if (rt6_check_expired(rt)) @@ -1052,6 +1053,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int strict = 0; strict |= flags & RT6_LOOKUP_F_IFACE; + strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE; if (net->ipv6.devconf_all->forwarding == 0) strict |= RT6_LOOKUP_F_REACHABLE; @@ -1791,7 +1793,7 @@ static struct rt6_info *ip6_nh_lookup_table(struct net *net, }; struct fib6_table *table; struct rt6_info *rt; - int flags = RT6_LOOKUP_F_IFACE; + int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE; table = fib6_get_table(net, cfg->fc_table); if (!table) -- GitLab From bc72f3dd89e087e33afe8c490fbe132e3dcd9afe Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 24 Oct 2016 23:40:30 +0200 Subject: [PATCH 1064/1167] flow_dissector: fix vlan tag handling gcc warns about an uninitialized pointer dereference in the vlan priority handling: net/core/flow_dissector.c: In function '__skb_flow_dissect': net/core/flow_dissector.c:281:61: error: 'vlan' may be used uninitialized in this function [-Werror=maybe-uninitialized] As pointed out by Jiri Pirko, the variable is never actually used without being initialized first as the only way it end up uninitialized is with skb_vlan_tag_present(skb)==true, and that means it does not get accessed. However, the warning hints at some related issues that I'm addressing here: - the second check for the vlan tag is different from the first one that tests the skb for being NULL first, causing both the warning and a possible NULL pointer dereference that was not entirely fixed. - The same patch that introduced the NULL pointer check dropped an earlier optimization that skipped the repeated check of the protocol type - The local '_vlan' variable is referenced through the 'vlan' pointer but the variable has gone out of scope by the time that it is accessed, causing undefined behavior Caching the result of the 'skb && skb_vlan_tag_present(skb)' check in a local variable allows the compiler to further optimize the later check. With those changes, the warning also disappears. Fixes: 3805a938a6c2 ("flow_dissector: Check skb for VLAN only if skb specified.") Fixes: d5709f7ab776 ("flow_dissector: For stripped vlan, get vlan info from skb->vlan_tci") Signed-off-by: Arnd Bergmann Acked-by: Jiri Pirko Acked-by: Eric Garver Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 44e6ba9d3a6b2..ab193e5def07e 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -246,13 +246,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb, case htons(ETH_P_8021AD): case htons(ETH_P_8021Q): { const struct vlan_hdr *vlan; + struct vlan_hdr _vlan; + bool vlan_tag_present = skb && skb_vlan_tag_present(skb); - if (skb && skb_vlan_tag_present(skb)) + if (vlan_tag_present) proto = skb->protocol; - if (eth_type_vlan(proto)) { - struct vlan_hdr _vlan; - + if (!vlan_tag_present || eth_type_vlan(skb->protocol)) { vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), data, hlen, &_vlan); if (!vlan) @@ -270,7 +270,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, FLOW_DISSECTOR_KEY_VLAN, target_container); - if (skb_vlan_tag_present(skb)) { + if (vlan_tag_present) { key_vlan->vlan_id = skb_vlan_tag_get_id(skb); key_vlan->vlan_priority = (skb_vlan_tag_get_prio(skb) >> VLAN_PRIO_SHIFT); -- GitLab From c121f72a66c5f92fbe2fc53baa274eef39875cec Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 24 Oct 2016 23:46:18 +0100 Subject: [PATCH 1065/1167] net: bgmac: fix spelling mistake: "connecton" -> "connection" trivial fix to spelling mistake in dev_err message Signed-off-by: Colin Ian King Acked-by: Jon Mason Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bgmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 856379cbb4026..31ca204b38d20 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1449,7 +1449,7 @@ static int bgmac_phy_connect(struct bgmac *bgmac) phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link, PHY_INTERFACE_MODE_MII); if (IS_ERR(phy_dev)) { - dev_err(bgmac->dev, "PHY connecton failed\n"); + dev_err(bgmac->dev, "PHY connection failed\n"); return PTR_ERR(phy_dev); } -- GitLab From a3b8cb1f84a0de95323902c76bab245675d6d218 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 22 Sep 2016 15:06:52 -0700 Subject: [PATCH 1066/1167] ixgbe: fix panic when using macvlan with l2-fwd-offload enabled Fix NULL pointer dereference in the case where a macvlan interface is brought up while the PF is still down: BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 IP: [] ixgbe_alloc_rx_buffers+0x42/0x1a0 [ixgbe] Call Trace: [] ixgbe_configure_rx_ring+0x2eb/0x3d0 [ixgbe] [] ixgbe_fwd_ring_up+0xd1/0x380 [ixgbe] [] ixgbe_fwd_add+0x149/0x230 [ixgbe] [] macvlan_open+0x260/0x2b0 [macvlan] Reported-by: Matthew Garrett Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index a244d9a67264c..bd93d823cc25e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -9135,10 +9135,14 @@ static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev) goto fwd_add_err; fwd_adapter->pool = pool; fwd_adapter->real_adapter = adapter; - err = ixgbe_fwd_ring_up(vdev, fwd_adapter); - if (err) - goto fwd_add_err; - netif_tx_start_all_queues(vdev); + + if (netif_running(pdev)) { + err = ixgbe_fwd_ring_up(vdev, fwd_adapter); + if (err) + goto fwd_add_err; + netif_tx_start_all_queues(vdev); + } + return fwd_adapter; fwd_add_err: /* unwind counter and free adapter struct */ -- GitLab From ea6acb7ef78960e4b6f1cd8c4162a5e490e83dcd Mon Sep 17 00:00:00 2001 From: David Ertman Date: Tue, 20 Sep 2016 07:10:50 -0700 Subject: [PATCH 1067/1167] i40e: Fix configure TCs after initial DCB disable in commit a036244c068612a43fa8c0f33a0eb4daa4d8dba0 a fix was put into place to avoid a kernel panic when a non- supported traffic class configuration was put into place and then lldp was enabled/disabled on the link partner switch. This fix caused it to be necessary to unload/reload the driver to reenable DCB once a supported TC config was in place. The root cause of the original panic was that the function i40e_pf_get_default_tc was allowing for a default TC other than TC 0, and only TC 0 is supported as a default. This patch removes the get_default_tc function and replaces it with a #define since there is only one TC supported as a default. Change-Id: I448371974e946386d0a7718d73668b450b7c72ef Signed-off-by: Dave Ertman Tested-by: Ronald Bynoe Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 31 +++------------------ 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 2030d7c1dc94a..6d61e443bdf86 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -92,6 +92,7 @@ #define I40E_AQ_LEN 256 #define I40E_AQ_WORK_LIMIT 66 /* max number of VFs + a little */ #define I40E_MAX_USER_PRIORITY 8 +#define I40E_DEFAULT_TRAFFIC_CLASS BIT(0) #define I40E_DEFAULT_MSG_ENABLE 4 #define I40E_QUEUE_WAIT_RETRY_LIMIT 10 #define I40E_INT_NAME_STR_LEN (IFNAMSIZ + 16) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ac1faee2a5b88..050d005d2edea 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4640,29 +4640,6 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf) return num_tc; } -/** - * i40e_pf_get_default_tc - Get bitmap for first enabled TC - * @pf: PF being queried - * - * Return a bitmap for first enabled traffic class for this PF. - **/ -static u8 i40e_pf_get_default_tc(struct i40e_pf *pf) -{ - u8 enabled_tc = pf->hw.func_caps.enabled_tcmap; - u8 i = 0; - - if (!enabled_tc) - return 0x1; /* TC0 */ - - /* Find the first enabled TC */ - for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & BIT(i)) - break; - } - - return BIT(i); -} - /** * i40e_pf_get_pf_tc_map - Get bitmap for enabled traffic classes * @pf: PF being queried @@ -4673,7 +4650,7 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf) { /* If DCB is not enabled for this PF then just return default TC */ if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) - return i40e_pf_get_default_tc(pf); + return I40E_DEFAULT_TRAFFIC_CLASS; /* SFP mode we want PF to be enabled for all TCs */ if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) @@ -4683,7 +4660,7 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf) if (pf->hw.func_caps.iscsi) return i40e_get_iscsi_tc_map(pf); else - return i40e_pf_get_default_tc(pf); + return I40E_DEFAULT_TRAFFIC_CLASS; } /** @@ -5029,7 +5006,7 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf) if (v == pf->lan_vsi) tc_map = i40e_pf_get_tc_map(pf); else - tc_map = i40e_pf_get_default_tc(pf); + tc_map = I40E_DEFAULT_TRAFFIC_CLASS; #ifdef I40E_FCOE if (pf->vsi[v]->type == I40E_VSI_FCOE) tc_map = i40e_get_fcoe_tc_map(pf); @@ -5717,7 +5694,7 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf, u8 type; /* Not DCB capable or capability disabled */ - if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) + if (!(pf->flags & I40E_FLAG_DCB_CAPABLE)) return ret; /* Ignore if event is not for Nearest Bridge */ -- GitLab From 4c95aa5d8fc34be18fcab01b1c6251c8c2b61520 Mon Sep 17 00:00:00 2001 From: Guilherme G Piccoli Date: Thu, 22 Sep 2016 10:03:58 -0300 Subject: [PATCH 1068/1167] i40e: disable MSI-X interrupts if we cannot reserve enough vectors If we fail on allocating enough MSI-X interrupts, we should disable them since they were previously enabled in this point of code. Not disabling them can lead to WARN_ON() being triggered and subsequent failure in enabling MSI as a fallback; the below message was shown without this patch while we played with interrupt allocation in i40e driver: [ 21.461346] sysfs: cannot create duplicate filename '/devices/pci0007:00/0007:00:00.0/0007:01:00.3/msi_irqs' [ 21.461459] ------------[ cut here ]------------ [ 21.461514] WARNING: CPU: 64 PID: 1155 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x88/0xc0 Also, we noticed that without this patch, if we modprobe the module without enough MSI-X interrupts (triggering the above warning), unload the module and re-load it again, we got a crash on the system. Signed-off-by: Guilherme G Piccoli Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 050d005d2edea..6abc1301a8e44 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7684,6 +7684,7 @@ static int i40e_init_msix(struct i40e_pf *pf) pf->flags &= ~I40E_FLAG_MSIX_ENABLED; kfree(pf->msix_entries); pf->msix_entries = NULL; + pci_disable_msix(pf->pdev); return -ENODEV; } else if (v_actual == I40E_MIN_MSIX) { -- GitLab From 9ee7837449b3d6f0fcf9132c6b5e5aaa58cc67d4 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Mon, 24 Oct 2016 20:18:27 -0400 Subject: [PATCH 1069/1167] net sched filters: fix notification of filter delete with proper handle Daniel says: While trying out [1][2], I noticed that tc monitor doesn't show the correct handle on delete: $ tc monitor qdisc clsact ffff: dev eno1 parent ffff:fff1 filter dev eno1 ingress protocol all pref 49152 bpf handle 0x2a [...] deleted filter dev eno1 ingress protocol all pref 49152 bpf handle 0xf3be0c80 some context to explain the above: The user identity of any tc filter is represented by a 32-bit identifier encoded in tcm->tcm_handle. Example 0x2a in the bpf filter above. A user wishing to delete, get or even modify a specific filter uses this handle to reference it. Every classifier is free to provide its own semantics for the 32 bit handle. Example: classifiers like u32 use schemes like 800:1:801 to describe the semantics of their filters represented as hash table, bucket and node ids etc. Classifiers also have internal per-filter representation which is different from this externally visible identity. Most classifiers set this internal representation to be a pointer address (which allows fast retrieval of said filters in their implementations). This internal representation is referenced with the "fh" variable in the kernel control code. When a user successfuly deletes a specific filter, by specifying the correct tcm->tcm_handle, an event is generated to user space which indicates which specific filter was deleted. Before this patch, the "fh" value was sent to user space as the identity. As an example what is shown in the sample bpf filter delete event above is 0xf3be0c80. This is infact a 32-bit truncation of 0xffff8807f3be0c80 which happens to be a 64-bit memory address of the internal filter representation (address of the corresponding filter's struct cls_bpf_prog); After this patch the appropriate user identifiable handle as encoded in the originating request tcm->tcm_handle is generated in the event. One of the cardinal rules of netlink rules is to be able to take an event (such as a delete in this case) and reflect it back to the kernel and successfully delete the filter. This patch achieves that. Note, this issue has existed since the original TC action infrastructure code patch back in 2004 as found in: https://git.kernel.org/cgit/linux/kernel/git/history/history.git/commit/ [1] http://patchwork.ozlabs.org/patch/682828/ [2] http://patchwork.ozlabs.org/patch/682829/ Fixes: 4e54c4816bfe ("[NET]: Add tc extensions infrastructure.") Reported-by: Daniel Borkmann Acked-by: Cong Wang Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_api.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 2ee29a3375f66..2b2a7974e4bba 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -345,7 +345,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) if (err == 0) { struct tcf_proto *next = rtnl_dereference(tp->next); - tfilter_notify(net, skb, n, tp, fh, + tfilter_notify(net, skb, n, tp, + t->tcm_handle, RTM_DELTFILTER, false); if (tcf_destroy(tp, false)) RCU_INIT_POINTER(*back, next); -- GitLab From 599b076d15ee3ead7af20fc907079df00b2d59a0 Mon Sep 17 00:00:00 2001 From: Huaibin Wang Date: Mon, 26 Sep 2016 09:51:18 +0200 Subject: [PATCH 1070/1167] i40e: fix call of ndo_dflt_bridge_getlink() Order of arguments is wrong. The wrong code has been introduced by commit 7d4f8d871ab1, but is compiled only since commit 9df70b66418e. Note that this may break netlink dumps. Fixes: 9df70b66418e ("i40e: Remove incorrect #ifdef's") Fixes: 7d4f8d871ab1 ("switchdev; add VLAN support for port's bridge_getlink") CC: Carolyn Wyborny Signed-off-by: Huaibin Wang Signed-off-by: Nicolas Dichtel Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6abc1301a8e44..31c97e3937a42 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -9034,7 +9034,7 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, return 0; return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode, - nlflags, 0, 0, filter_mask, NULL); + 0, 0, nlflags, filter_mask, NULL); } /* Hardware supports L4 tunnel length of 128B (=2^7) which includes -- GitLab From 9db4f36e82c2394c958d8e42a498fb664684bc22 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 27 Oct 2016 15:49:12 -0700 Subject: [PATCH 1071/1167] mm: remove unused variable in memory hotplug When I removed the per-zone bitlock hashed waitqueues in commit 9dcb8b685fc3 ("mm: remove per-zone hashtable of bitlock waitqueues"), I removed all the magic hotplug memory initialization of said waitqueues too. But when I actually _tested_ the resulting build, I stupidly assumed that "allmodconfig" would enable memory hotplug. And it doesn't, because it enables KASAN instead, which then disables hotplug memory support. As a result, my build test of the per-zone waitqueues was totally broken, and I didn't notice that the compiler warns about the now unused iterator variable 'i'. I guess I should be happy that that seems to be the worst breakage from my clearly horribly failed test coverage. Reported-by: Stephen Rothwell Signed-off-by: Linus Torvalds --- mm/memory_hotplug.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index b18dab401be6e..cad4b9125695c 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -2117,7 +2117,6 @@ void try_offline_node(int nid) unsigned long start_pfn = pgdat->node_start_pfn; unsigned long end_pfn = start_pfn + pgdat->node_spanned_pages; unsigned long pfn; - int i; for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { unsigned long section_nr = pfn_to_section_nr(pfn); -- GitLab From 867dfe342118b1ea0256a85f7c0d9ceb0ead032a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 25 Oct 2016 17:52:04 +0200 Subject: [PATCH 1072/1167] nvdimm: make CONFIG_NVDIMM_DAX 'bool' A bugfix just tried to address a randconfig build problem and introduced a variant of the same problem: with CONFIG_LIBNVDIMM=y and CONFIG_NVDIMM_DAX=m, the nvdimm module now fails to link: drivers/nvdimm/built-in.o: In function `to_nd_device_type': bus.c:(.text+0x1b5d): undefined reference to `is_nd_dax' drivers/nvdimm/built-in.o: In function `nd_region_notify_driver_action.constprop.2': region_devs.c:(.text+0x6b6c): undefined reference to `is_nd_dax' region_devs.c:(.text+0x6b8c): undefined reference to `to_nd_dax' drivers/nvdimm/built-in.o: In function `nd_region_probe': region.c:(.text+0x70f3): undefined reference to `nd_dax_create' drivers/nvdimm/built-in.o: In function `mode_show': namespace_devs.c:(.text+0xa196): undefined reference to `is_nd_dax' drivers/nvdimm/built-in.o: In function `nvdimm_namespace_common_probe': (.text+0xa55f): undefined reference to `is_nd_dax' drivers/nvdimm/built-in.o: In function `nvdimm_namespace_common_probe': (.text+0xa56e): undefined reference to `to_nd_dax' This reverts the earlier fix, making NVDIMM_DAX a 'bool' option again as it should be (it gets linked into the libnvdimm module). To fix the original problem, I'm adding a dependency on LIBNVDIMM to DEV_DAX_PMEM, which ensures we can't have that one built-in if the rest is a module. Fixes: 4e65e9381c7a ("/dev/dax: fix Kconfig dependency build breakage") Signed-off-by: Arnd Bergmann Reviewed-by: Ross Zwisler Signed-off-by: Dan Williams --- drivers/dax/Kconfig | 2 +- drivers/nvdimm/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig index daadd20aa936a..3e2ab3b14eea2 100644 --- a/drivers/dax/Kconfig +++ b/drivers/dax/Kconfig @@ -14,7 +14,7 @@ if DEV_DAX config DEV_DAX_PMEM tristate "PMEM DAX: direct access to persistent memory" - depends on NVDIMM_DAX + depends on LIBNVDIMM && NVDIMM_DAX default DEV_DAX help Support raw access to persistent memory. Note that this diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 8b2b740d6679e..124c2432ac9cb 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig @@ -89,7 +89,7 @@ config NVDIMM_PFN Select Y if unsure config NVDIMM_DAX - tristate "NVDIMM DAX: Raw access to persistent memory" + bool "NVDIMM DAX: Raw access to persistent memory" default LIBNVDIMM depends on NVDIMM_PFN help -- GitLab From 67463e54beb63114965c3d2c7cb81d1d524e2697 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 27 Oct 2016 16:23:01 -0700 Subject: [PATCH 1073/1167] Allow KASAN and HOTPLUG_MEMORY to co-exist when doing build testing No, KASAN may not be able to co-exist with HOTPLUG_MEMORY at runtime, but for build testing there is no reason not to allow them together. This hopefully means better build coverage and fewer embarrasing silly problems like the one fixed by commit 9db4f36e82c2 ("mm: remove unused variable in memory hotplug") in the future. Cc: Stephen Rothwell Cc: Andrey Ryabinin Cc: Alexander Potapenko Signed-off-by: Linus Torvalds --- mm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/Kconfig b/mm/Kconfig index be0ee11fa0d9e..86e3e0e74d20e 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -187,7 +187,7 @@ config MEMORY_HOTPLUG bool "Allow for memory hot-add" depends on SPARSEMEM || X86_64_ACPI_NUMA depends on ARCH_ENABLE_MEMORY_HOTPLUG - depends on !KASAN + depends on COMPILE_TEST || !KASAN config MEMORY_HOTPLUG_SPARSE def_bool y -- GitLab From 52e73eb2872c9af6f382b2b22954ca8214397a4e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 27 Oct 2016 17:04:05 -0700 Subject: [PATCH 1074/1167] device-dax: fix percpu_ref_exit ordering We need to wait until the percpu_ref is released before exit. Otherwise, we sometimes lose the race and trigger this new warning that was added in v4.9 (commit a67823c1ed10 "percpu-refcount: init ->confirm_switch member properly"): WARNING: CPU: 0 PID: 3629 at lib/percpu-refcount.c:107 percpu_ref_exit+0x51/0x60 [..] Call Trace: [] dump_stack+0x85/0xc2 [] __warn+0xcb/0xf0 [] warn_slowpath_null+0x1d/0x20 [] percpu_ref_exit+0x51/0x60 [] dax_pmem_percpu_exit+0x1a/0x50 [dax_pmem] [] devm_action_release+0xf/0x20 Cc: Fixes: ab68f2622136 ("/dev/dax, pmem: direct access to persistent memory") Signed-off-by: Dan Williams --- drivers/dax/pmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 9630d8837ba94..4a15fa5df98bc 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -44,7 +44,6 @@ static void dax_pmem_percpu_exit(void *data) dev_dbg(dax_pmem->dev, "%s\n", __func__); percpu_ref_exit(ref); - wait_for_completion(&dax_pmem->cmp); } static void dax_pmem_percpu_kill(void *data) @@ -54,6 +53,7 @@ static void dax_pmem_percpu_kill(void *data) dev_dbg(dax_pmem->dev, "%s\n", __func__); percpu_ref_kill(ref); + wait_for_completion(&dax_pmem->cmp); } static int dax_pmem_probe(struct device *dev) -- GitLab From 86d9f48534e800e4d62cdc1b5aaf539f4c1d47d6 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Thu, 27 Oct 2016 17:46:18 -0700 Subject: [PATCH 1075/1167] mm/slab: fix kmemcg cache creation delayed issue There is a bug report that SLAB makes extreme load average due to over 2000 kworker thread. https://bugzilla.kernel.org/show_bug.cgi?id=172981 This issue is caused by kmemcg feature that try to create new set of kmem_caches for each memcg. Recently, kmem_cache creation is slowed by synchronize_sched() and futher kmem_cache creation is also delayed since kmem_cache creation is synchronized by a global slab_mutex lock. So, the number of kworker that try to create kmem_cache increases quietly. synchronize_sched() is for lockless access to node's shared array but it's not needed when a new kmem_cache is created. So, this patch rules out that case. Fixes: 801faf0db894 ("mm/slab: lockless decision to grow cache") Link: http://lkml.kernel.org/r/1475734855-4837-1-git-send-email-iamjoonsoo.kim@lge.com Reported-by: Doug Smythies Tested-by: Doug Smythies Signed-off-by: Joonsoo Kim Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slab.c b/mm/slab.c index 090fb26b3a39b..c451e3f6bbf60 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -966,7 +966,7 @@ static int setup_kmem_cache_node(struct kmem_cache *cachep, * guaranteed to be valid until irq is re-enabled, because it will be * freed after synchronize_sched(). */ - if (force_change) + if (old_shared && force_change) synchronize_sched(); fail: -- GitLab From b274c0bb394c6a69ac12feac7c2db81f5aff5a55 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 27 Oct 2016 17:46:21 -0700 Subject: [PATCH 1076/1167] kcov: properly check if we are in an interrupt in_interrupt() returns a nonzero value when we are either in an interrupt or have bh disabled via local_bh_disable(). Since we are interested in only ignoring coverage from actual interrupts, do a proper check instead of just calling in_interrupt(). As a result of this change, kcov will start to collect coverage from within local_bh_disable()/local_bh_enable() sections. Link: http://lkml.kernel.org/r/1476115803-20712-1-git-send-email-andreyknvl@google.com Signed-off-by: Andrey Konovalov Acked-by: Dmitry Vyukov Cc: Nicolai Stange Cc: Andrey Ryabinin Cc: Kees Cook Cc: James Morse Cc: Vegard Nossum Cc: Quentin Casasnovas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kcov.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index 8d44b3fea9d08..30e6d05aa5a9f 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -53,8 +53,15 @@ void notrace __sanitizer_cov_trace_pc(void) /* * We are interested in code coverage as a function of a syscall inputs, * so we ignore code executed in interrupts. + * The checks for whether we are in an interrupt are open-coded, because + * 1. We can't use in_interrupt() here, since it also returns true + * when we are inside local_bh_disable() section. + * 2. We don't want to use (in_irq() | in_serving_softirq() | in_nmi()), + * since that leads to slower generated code (three separate tests, + * one for each of the flags). */ - if (!t || in_interrupt()) + if (!t || (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_OFFSET + | NMI_MASK))) return; mode = READ_ONCE(t->kcov_mode); if (mode == KCOV_MODE_TRACE) { -- GitLab From 21753583056d48a5fad964d6f272e28168426845 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 27 Oct 2016 17:46:24 -0700 Subject: [PATCH 1077/1167] h8300: fix syscall restarting Back in commit f56141e3e2d9 ("all arches, signal: move restart_block to struct task_struct"), all architectures and core code were changed to use task_struct::restart_block. However, when h8300 support was subsequently restored in v4.2, it was not updated to account for this, and maintains thread_info::restart_block, which is not kept in sync. This patch drops the redundant restart_block from thread_info, and moves h8300 to the common one in task_struct, ensuring that syscall restarting always works as expected. Fixes: f56141e3e2d9 ("all arches, signal: move restart_block to struct task_struct") Link: http://lkml.kernel.org/r/1476714934-11635-1-git-send-email-mark.rutland@arm.com Signed-off-by: Mark Rutland Cc: Andy Lutomirski Cc: Yoshinori Sato Cc: uclinux-h8-devel@lists.sourceforge.jp Cc: [4.2+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/h8300/include/asm/thread_info.h | 4 ---- arch/h8300/kernel/signal.c | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/h8300/include/asm/thread_info.h b/arch/h8300/include/asm/thread_info.h index b408fe660cf8c..3cef06875f5ca 100644 --- a/arch/h8300/include/asm/thread_info.h +++ b/arch/h8300/include/asm/thread_info.h @@ -31,7 +31,6 @@ struct thread_info { int cpu; /* cpu we're on */ int preempt_count; /* 0 => preemptable, <0 => BUG */ mm_segment_t addr_limit; - struct restart_block restart_block; }; /* @@ -44,9 +43,6 @@ struct thread_info { .cpu = 0, \ .preempt_count = INIT_PREEMPT_COUNT, \ .addr_limit = KERNEL_DS, \ - .restart_block = { \ - .fn = do_no_restart_syscall, \ - }, \ } #define init_thread_info (init_thread_union.thread_info) diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index ad1f81f574e57..7138303cbbf25 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -79,7 +79,7 @@ restore_sigcontext(struct sigcontext *usc, int *pd0) unsigned int er0; /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; + current->restart_block.fn = do_no_restart_syscall; /* restore passed registers */ #define COPY(r) do { err |= get_user(regs->r, &usc->sc_##r); } while (0) -- GitLab From 1bc11d70b5db7c6bb1414b283d7f09b1fe1ac0d0 Mon Sep 17 00:00:00 2001 From: Alexander Polakov Date: Thu, 27 Oct 2016 17:46:27 -0700 Subject: [PATCH 1078/1167] mm/list_lru.c: avoid error-path NULL pointer deref As described in https://bugzilla.kernel.org/show_bug.cgi?id=177821: After some analysis it seems to be that the problem is in alloc_super(). In case list_lru_init_memcg() fails it goes into destroy_super(), which calls list_lru_destroy(). And in list_lru_init() we see that in case memcg_init_list_lru() fails, lru->node is freed, but not set NULL, which then leads list_lru_destroy() to believe it is initialized and call memcg_destroy_list_lru(). memcg_destroy_list_lru() in turn can access lru->node[i].memcg_lrus, which is NULL. [akpm@linux-foundation.org: add comment] Signed-off-by: Alexander Polakov Acked-by: Vladimir Davydov Cc: Al Viro Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/list_lru.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/list_lru.c b/mm/list_lru.c index 1d05cb9d363d0..234676e31edd3 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -554,6 +554,8 @@ int __list_lru_init(struct list_lru *lru, bool memcg_aware, err = memcg_init_list_lru(lru, memcg_aware); if (err) { kfree(lru->node); + /* Do this so a list_lru_destroy() doesn't crash: */ + lru->node = NULL; goto out; } -- GitLab From 1f84a18fc010d7a62667199c9be35872bbf31526 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 27 Oct 2016 17:46:29 -0700 Subject: [PATCH 1079/1167] mm: page_alloc: use KERN_CONT where appropriate Recent changes to printk require KERN_CONT uses to continue logging messages. So add KERN_CONT where necessary. [akpm@linux-foundation.org: coding-style fixes] Fixes: 4bcc595ccd80 ("printk: reinstate KERN_CONT for printing continuation lines") Link: http://lkml.kernel.org/r/c7df37c8665134654a17aaeb8b9f6ace1d6db58b.1476239034.git.joe@perches.com Reported-by: Mark Rutland Signed-off-by: Joe Perches Acked-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index de7c6e43b1c96..8fd42aa7c4bd0 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4224,7 +4224,7 @@ static void show_migration_types(unsigned char type) } *p = '\0'; - printk("(%s) ", tmp); + printk(KERN_CONT "(%s) ", tmp); } /* @@ -4335,7 +4335,8 @@ void show_free_areas(unsigned int filter) free_pcp += per_cpu_ptr(zone->pageset, cpu)->pcp.count; show_node(zone); - printk("%s" + printk(KERN_CONT + "%s" " free:%lukB" " min:%lukB" " low:%lukB" @@ -4382,8 +4383,8 @@ void show_free_areas(unsigned int filter) K(zone_page_state(zone, NR_FREE_CMA_PAGES))); printk("lowmem_reserve[]:"); for (i = 0; i < MAX_NR_ZONES; i++) - printk(" %ld", zone->lowmem_reserve[i]); - printk("\n"); + printk(KERN_CONT " %ld", zone->lowmem_reserve[i]); + printk(KERN_CONT "\n"); } for_each_populated_zone(zone) { @@ -4394,7 +4395,7 @@ void show_free_areas(unsigned int filter) if (skip_free_areas_node(filter, zone_to_nid(zone))) continue; show_node(zone); - printk("%s: ", zone->name); + printk(KERN_CONT "%s: ", zone->name); spin_lock_irqsave(&zone->lock, flags); for (order = 0; order < MAX_ORDER; order++) { @@ -4412,11 +4413,12 @@ void show_free_areas(unsigned int filter) } spin_unlock_irqrestore(&zone->lock, flags); for (order = 0; order < MAX_ORDER; order++) { - printk("%lu*%lukB ", nr[order], K(1UL) << order); + printk(KERN_CONT "%lu*%lukB ", + nr[order], K(1UL) << order); if (nr[order]) show_migration_types(types[order]); } - printk("= %lukB\n", K(total)); + printk(KERN_CONT "= %lukB\n", K(total)); } hugetlb_show_meminfo(); -- GitLab From 07a63c41fa1f6533f5668e5b33a295bfd63aa534 Mon Sep 17 00:00:00 2001 From: Aruna Ramakrishna Date: Thu, 27 Oct 2016 17:46:32 -0700 Subject: [PATCH 1080/1167] mm/slab: improve performance of gathering slabinfo stats On large systems, when some slab caches grow to millions of objects (and many gigabytes), running 'cat /proc/slabinfo' can take up to 1-2 seconds. During this time, interrupts are disabled while walking the slab lists (slabs_full, slabs_partial, and slabs_free) for each node, and this sometimes causes timeouts in other drivers (for instance, Infiniband). This patch optimizes 'cat /proc/slabinfo' by maintaining a counter for total number of allocated slabs per node, per cache. This counter is updated when a slab is created or destroyed. This enables us to skip traversing the slabs_full list while gathering slabinfo statistics, and since slabs_full tends to be the biggest list when the cache is large, it results in a dramatic performance improvement. Getting slabinfo statistics now only requires walking the slabs_free and slabs_partial lists, and those lists are usually much smaller than slabs_full. We tested this after growing the dentry cache to 70GB, and the performance improved from 2s to 5ms. Link: http://lkml.kernel.org/r/1472517876-26814-1-git-send-email-aruna.ramakrishna@oracle.com Signed-off-by: Aruna Ramakrishna Acked-by: David Rientjes Cc: Mike Kravetz Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab.c | 43 +++++++++++++++++++++++++++---------------- mm/slab.h | 1 + 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index c451e3f6bbf60..0b0550ca85b40 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -233,6 +233,7 @@ static void kmem_cache_node_init(struct kmem_cache_node *parent) spin_lock_init(&parent->list_lock); parent->free_objects = 0; parent->free_touched = 0; + parent->num_slabs = 0; } #define MAKE_LIST(cachep, listp, slab, nodeid) \ @@ -1382,24 +1383,27 @@ slab_out_of_memory(struct kmem_cache *cachep, gfp_t gfpflags, int nodeid) for_each_kmem_cache_node(cachep, node, n) { unsigned long active_objs = 0, num_objs = 0, free_objects = 0; unsigned long active_slabs = 0, num_slabs = 0; + unsigned long num_slabs_partial = 0, num_slabs_free = 0; + unsigned long num_slabs_full; spin_lock_irqsave(&n->list_lock, flags); - list_for_each_entry(page, &n->slabs_full, lru) { - active_objs += cachep->num; - active_slabs++; - } + num_slabs = n->num_slabs; list_for_each_entry(page, &n->slabs_partial, lru) { active_objs += page->active; - active_slabs++; + num_slabs_partial++; } list_for_each_entry(page, &n->slabs_free, lru) - num_slabs++; + num_slabs_free++; free_objects += n->free_objects; spin_unlock_irqrestore(&n->list_lock, flags); - num_slabs += active_slabs; num_objs = num_slabs * cachep->num; + active_slabs = num_slabs - num_slabs_free; + num_slabs_full = num_slabs - + (num_slabs_partial + num_slabs_free); + active_objs += (num_slabs_full * cachep->num); + pr_warn(" node %d: slabs: %ld/%ld, objs: %ld/%ld, free: %ld\n", node, active_slabs, num_slabs, active_objs, num_objs, free_objects); @@ -2314,6 +2318,7 @@ static int drain_freelist(struct kmem_cache *cache, page = list_entry(p, struct page, lru); list_del(&page->lru); + n->num_slabs--; /* * Safe to drop the lock. The slab is no longer linked * to the cache. @@ -2752,6 +2757,8 @@ static void cache_grow_end(struct kmem_cache *cachep, struct page *page) list_add_tail(&page->lru, &(n->slabs_free)); else fixup_slab_list(cachep, n, page, &list); + + n->num_slabs++; STATS_INC_GROWN(cachep); n->free_objects += cachep->num - page->active; spin_unlock(&n->list_lock); @@ -3443,6 +3450,7 @@ static void free_block(struct kmem_cache *cachep, void **objpp, page = list_last_entry(&n->slabs_free, struct page, lru); list_move(&page->lru, list); + n->num_slabs--; } } @@ -4099,6 +4107,8 @@ void get_slabinfo(struct kmem_cache *cachep, struct slabinfo *sinfo) unsigned long num_objs; unsigned long active_slabs = 0; unsigned long num_slabs, free_objects = 0, shared_avail = 0; + unsigned long num_slabs_partial = 0, num_slabs_free = 0; + unsigned long num_slabs_full = 0; const char *name; char *error = NULL; int node; @@ -4111,33 +4121,34 @@ void get_slabinfo(struct kmem_cache *cachep, struct slabinfo *sinfo) check_irq_on(); spin_lock_irq(&n->list_lock); - list_for_each_entry(page, &n->slabs_full, lru) { - if (page->active != cachep->num && !error) - error = "slabs_full accounting error"; - active_objs += cachep->num; - active_slabs++; - } + num_slabs += n->num_slabs; + list_for_each_entry(page, &n->slabs_partial, lru) { if (page->active == cachep->num && !error) error = "slabs_partial accounting error"; if (!page->active && !error) error = "slabs_partial accounting error"; active_objs += page->active; - active_slabs++; + num_slabs_partial++; } + list_for_each_entry(page, &n->slabs_free, lru) { if (page->active && !error) error = "slabs_free accounting error"; - num_slabs++; + num_slabs_free++; } + free_objects += n->free_objects; if (n->shared) shared_avail += n->shared->avail; spin_unlock_irq(&n->list_lock); } - num_slabs += active_slabs; num_objs = num_slabs * cachep->num; + active_slabs = num_slabs - num_slabs_free; + num_slabs_full = num_slabs - (num_slabs_partial + num_slabs_free); + active_objs += (num_slabs_full * cachep->num); + if (num_objs - active_objs != free_objects && !error) error = "free_objects accounting error"; diff --git a/mm/slab.h b/mm/slab.h index 9653f2e2591ad..bc05fdc3edce1 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -432,6 +432,7 @@ struct kmem_cache_node { struct list_head slabs_partial; /* partial list first, better asm code */ struct list_head slabs_full; struct list_head slabs_free; + unsigned long num_slabs; unsigned long free_objects; unsigned int free_limit; unsigned int colour_next; /* Per-node cache coloring */ -- GitLab From 8c8d4d45204902e144abc0f15b7c658828028fa1 Mon Sep 17 00:00:00 2001 From: Aristeu Rozanski Date: Thu, 27 Oct 2016 17:46:35 -0700 Subject: [PATCH 1081/1167] ipc: account for kmem usage on mqueue and msg When kmem accounting switched from account by default to only account if flagged by __GFP_ACCOUNT, IPC mqueue and messages was left out. The production use case at hand is that mqueues should be customizable via sysctls in Docker containers in a Kubernetes cluster. This can only be safely allowed to the users of the cluster (without the risk that they can cause resource shortage on a node, influencing other users' containers) if all resources they control are bounded, i.e. accounted for. Link: http://lkml.kernel.org/r/1476806075-1210-1-git-send-email-arozansk@redhat.com Signed-off-by: Aristeu Rozanski Reported-by: Stefan Schimanski Acked-by: Davidlohr Bueso Cc: Alexey Dobriyan Cc: Johannes Weiner Cc: Michal Hocko Cc: Vladimir Davydov Cc: Stefan Schimanski Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msgutil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipc/msgutil.c b/ipc/msgutil.c index a521999de4f10..bf74eaa5c39f2 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -53,7 +53,7 @@ static struct msg_msg *alloc_msg(size_t len) size_t alen; alen = min(len, DATALEN_MSG); - msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL); + msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL_ACCOUNT); if (msg == NULL) return NULL; @@ -65,7 +65,7 @@ static struct msg_msg *alloc_msg(size_t len) while (len > 0) { struct msg_msgseg *seg; alen = min(len, DATALEN_SEG); - seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL); + seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_ACCOUNT); if (seg == NULL) goto out_err; *pseg = seg; -- GitLab From c0a0aba8e478229b2f0956918542152fbad3f794 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 27 Oct 2016 17:46:38 -0700 Subject: [PATCH 1082/1167] kconfig.h: remove config_enabled() macro The use of config_enabled() is ambiguous. For config options, IS_ENABLED(), IS_REACHABLE(), etc. will make intention clearer. Sometimes config_enabled() has been used for non-config options because it is useful to check whether the given symbol is defined or not. I have been tackling on deprecating config_enabled(), and now is the time to finish this work. Some new users have appeared for v4.9-rc1, but it is trivial to replace them: - arch/x86/mm/kaslr.c replace config_enabled() with IS_ENABLED() because CONFIG_X86_ESPFIX64 and CONFIG_EFI are boolean. - include/asm-generic/export.h replace config_enabled() with __is_defined(). Then, config_enabled() can be removed now. Going forward, please use IS_ENABLED(), IS_REACHABLE(), etc. for config options, and __is_defined() for non-config symbols. Link: http://lkml.kernel.org/r/1476616078-32252-1-git-send-email-yamada.masahiro@socionext.com Signed-off-by: Masahiro Yamada Acked-by: Ingo Molnar Acked-by: Nicolas Pitre Cc: Peter Oberparleiter Cc: Arnd Bergmann Cc: Kees Cook Cc: Michal Marek Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: Thomas Garnier Cc: Paul Bolle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/mm/kaslr.c | 6 +++--- include/asm-generic/export.h | 2 +- include/linux/kconfig.h | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index ddd2661c45029..887e571827168 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c @@ -104,10 +104,10 @@ void __init kernel_randomize_memory(void) * consistent with the vaddr_start/vaddr_end variables. */ BUILD_BUG_ON(vaddr_start >= vaddr_end); - BUILD_BUG_ON(config_enabled(CONFIG_X86_ESPFIX64) && + BUILD_BUG_ON(IS_ENABLED(CONFIG_X86_ESPFIX64) && vaddr_end >= EFI_VA_START); - BUILD_BUG_ON((config_enabled(CONFIG_X86_ESPFIX64) || - config_enabled(CONFIG_EFI)) && + BUILD_BUG_ON((IS_ENABLED(CONFIG_X86_ESPFIX64) || + IS_ENABLED(CONFIG_EFI)) && vaddr_end >= __START_KERNEL_map); BUILD_BUG_ON(vaddr_end > __START_KERNEL_map); diff --git a/include/asm-generic/export.h b/include/asm-generic/export.h index 43199a049da5f..63554e9f6e0c6 100644 --- a/include/asm-generic/export.h +++ b/include/asm-generic/export.h @@ -70,7 +70,7 @@ KSYM(__kcrctab_\name): #include #define __EXPORT_SYMBOL(sym, val, sec) \ - __cond_export_sym(sym, val, sec, config_enabled(__KSYM_##sym)) + __cond_export_sym(sym, val, sec, __is_defined(__KSYM_##sym)) #define __cond_export_sym(sym, val, sec, conf) \ ___cond_export_sym(sym, val, sec, conf) #define ___cond_export_sym(sym, val, sec, enabled) \ diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h index 15ec117ec5373..8f2e059e4d455 100644 --- a/include/linux/kconfig.h +++ b/include/linux/kconfig.h @@ -31,7 +31,6 @@ * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when * the last step cherry picks the 2nd arg, we get a zero. */ -#define config_enabled(cfg) ___is_defined(cfg) #define __is_defined(x) ___is_defined(x) #define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val) #define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0) @@ -41,13 +40,13 @@ * otherwise. For boolean options, this is equivalent to * IS_ENABLED(CONFIG_FOO). */ -#define IS_BUILTIN(option) config_enabled(option) +#define IS_BUILTIN(option) __is_defined(option) /* * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0 * otherwise. */ -#define IS_MODULE(option) config_enabled(option##_MODULE) +#define IS_MODULE(option) __is_defined(option##_MODULE) /* * IS_REACHABLE(CONFIG_FOO) evaluates to 1 if the currently compiled -- GitLab From 0e07f663c90154079b287931257defbdb1d5405a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 27 Oct 2016 17:46:41 -0700 Subject: [PATCH 1083/1167] latent_entropy: raise CONFIG_FRAME_WARN by default When building with the latent_entropy plugin, set the default CONFIG_FRAME_WARN to 2048, since some __init functions have many basic blocks that, when instrumented by the latent_entropy plugin, grow beyond 1024 byte stack size on 32-bit builds. Link: http://lkml.kernel.org/r/20161018211216.GA39687@beast Signed-off-by: Kees Cook Reported-by: kbuild test robot Cc: Emese Revfy Cc: Ingo Molnar Cc: Michal Marek Cc: "Paul E. McKenney" Cc: Dan Williams Cc: Andrey Ryabinin Cc: Josh Poimboeuf Cc: Tejun Heo Cc: Nikolay Aleksandrov Cc: Dmitry Vyukov Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/Kconfig.debug | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 33bc56cf60d71..b01e547d4d044 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -198,6 +198,7 @@ config FRAME_WARN int "Warn for stack frames larger than (needs gcc 4.4)" range 0 8192 default 0 if KASAN + default 2048 if GCC_PLUGIN_LATENT_ENTROPY default 1024 if !64BIT default 2048 if 64BIT help -- GitLab From 02754e0a484a50a92d44c38879f2cb2792ebc572 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 27 Oct 2016 17:46:44 -0700 Subject: [PATCH 1084/1167] lib/stackdepot.c: bump stackdepot capacity from 16MB to 128MB KASAN uses stackdepot to memorize stacks for all kmalloc/kfree calls. Current stackdepot capacity is 16MB (1024 top level entries x 4 pages on second level). Size of each stack is (num_frames + 3) * sizeof(long). Which gives us ~84K stacks. This capacity was chosen empirically and it is enough to run kernel normally. However, when lots of configs are enabled and a fuzzer tries to maximize code coverage, it easily hits the limit within tens of minutes. I've tested for long a time with number of top level entries bumped 4x (4096). And I think I've seen overflow only once. But I don't have all configs enabled and code coverage has not reached maximum yet. So bump it 8x to 8192. Since we have two-level table, memory cost of this is very moderate -- currently the top-level table is 8KB, with this patch it is 64KB, which is negligible under KASAN. Here is some approx math. 128MB allows us to memorize ~670K stacks (assuming stack is ~200b). I've grepped kernel for kmalloc|kfree|kmem_cache_alloc|kmem_cache_free| kzalloc|kstrdup|kstrndup|kmemdup and it gives ~60K matches. Most of alloc/free call sites are reachable with only one stack. But some utility functions can have large fanout. Assuming average fanout is 5x, total number of alloc/free stacks is ~300K. Link: http://lkml.kernel.org/r/1476458416-122131-1-git-send-email-dvyukov@google.com Signed-off-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Joonsoo Kim Cc: Baozeng Ding Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/stackdepot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stackdepot.c b/lib/stackdepot.c index 60f77f1d470a0..4d830e2999893 100644 --- a/lib/stackdepot.c +++ b/lib/stackdepot.c @@ -50,7 +50,7 @@ STACK_ALLOC_ALIGN) #define STACK_ALLOC_INDEX_BITS (DEPOT_STACK_BITS - \ STACK_ALLOC_NULL_PROTECTION_BITS - STACK_ALLOC_OFFSET_BITS) -#define STACK_ALLOC_SLABS_CAP 1024 +#define STACK_ALLOC_SLABS_CAP 8192 #define STACK_ALLOC_MAX_SLABS \ (((1LL << (STACK_ALLOC_INDEX_BITS)) < STACK_ALLOC_SLABS_CAP) ? \ (1LL << (STACK_ALLOC_INDEX_BITS)) : STACK_ALLOC_SLABS_CAP) -- GitLab From 37df49f433bc3a11f5716fe65aaec5189c6402cb Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 27 Oct 2016 17:46:47 -0700 Subject: [PATCH 1085/1167] mm: kmemleak: ensure that the task stack is not freed during scanning Commit 68f24b08ee89 ("sched/core: Free the stack early if CONFIG_THREAD_INFO_IN_TASK") may cause the task->stack to be freed during kmemleak_scan() execution, leading to either a NULL pointer fault (if task->stack is NULL) or kmemleak accessing already freed memory. This patch uses the new try_get_task_stack() API to ensure that the task stack is not freed during kmemleak stack scanning. Addresses https://bugzilla.kernel.org/show_bug.cgi?id=173901. Fixes: 68f24b08ee89 ("sched/core: Free the stack early if CONFIG_THREAD_INFO_IN_TASK") Link: http://lkml.kernel.org/r/1476266223-14325-1-git-send-email-catalin.marinas@arm.com Signed-off-by: Catalin Marinas Reported-by: CAI Qian Tested-by: CAI Qian Acked-by: Michal Hocko Cc: Andy Lutomirski Cc: CAI Qian Cc: Hillf Danton Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/kmemleak.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index a5e453cf05c49..e5355a5b423fa 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1453,8 +1453,11 @@ static void kmemleak_scan(void) read_lock(&tasklist_lock); do_each_thread(g, p) { - scan_block(task_stack_page(p), task_stack_page(p) + - THREAD_SIZE, NULL); + void *stack = try_get_task_stack(p); + if (stack) { + scan_block(stack, stack + THREAD_SIZE, NULL); + put_task_stack(p); + } } while_each_thread(g, p); read_unlock(&tasklist_lock); } -- GitLab From 06b2849d103f4a91212876a211d0d7df227a9513 Mon Sep 17 00:00:00 2001 From: Leon Yu Date: Thu, 27 Oct 2016 17:46:50 -0700 Subject: [PATCH 1086/1167] proc: fix NULL dereference when reading /proc//auxv Reading auxv of any kernel thread results in NULL pointer dereferencing in auxv_read() where mm can be NULL. Fix that by checking for NULL mm and bailing out early. This is also the original behavior changed by recent commit c5317167854e ("proc: switch auxv to use of __mem_open()"). # cat /proc/2/auxv Unable to handle kernel NULL pointer dereference at virtual address 000000a8 Internal error: Oops: 17 [#1] PREEMPT SMP ARM CPU: 3 PID: 113 Comm: cat Not tainted 4.9.0-rc1-ARCH+ #1 Hardware name: BCM2709 task: ea3b0b00 task.stack: e99b2000 PC is at auxv_read+0x24/0x4c LR is at do_readv_writev+0x2fc/0x37c Process cat (pid: 113, stack limit = 0xe99b2210) Call chain: auxv_read do_readv_writev vfs_readv default_file_splice_read splice_direct_to_actor do_splice_direct do_sendfile SyS_sendfile64 ret_fast_syscall Fixes: c5317167854e ("proc: switch auxv to use of __mem_open()") Link: http://lkml.kernel.org/r/1476966200-14457-1-git-send-email-chianglungyu@gmail.com Signed-off-by: Leon Yu Acked-by: Oleg Nesterov Acked-by: Michal Hocko Cc: Al Viro Cc: Kees Cook Cc: John Stultz Cc: Mateusz Guzik Cc: Janis Danisevskis Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/proc/base.c b/fs/proc/base.c index adfc5b4986f53..ca651ac006608 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1012,6 +1012,9 @@ static ssize_t auxv_read(struct file *file, char __user *buf, { struct mm_struct *mm = file->private_data; unsigned int nwords = 0; + + if (!mm) + return 0; do { nwords += 2; } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */ -- GitLab From 8f72cb4ef90c63bcb5111c2e3ec7ea2727eab2f8 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Thu, 27 Oct 2016 17:46:53 -0700 Subject: [PATCH 1087/1167] CREDITS: update credit information for Martin Kepplinger Content and employer changed. Link: http://lkml.kernel.org/r/1477304102-28830-1-git-send-email-martin.kepplinger@ginzinger.com Signed-off-by: Martin Kepplinger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- CREDITS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CREDITS b/CREDITS index 513aaa3546bff..837367624e459 100644 --- a/CREDITS +++ b/CREDITS @@ -1864,10 +1864,11 @@ S: The Netherlands N: Martin Kepplinger E: martink@posteo.de -E: martin.kepplinger@theobroma-systems.com +E: martin.kepplinger@ginzinger.com W: http://www.martinkepplinger.com D: mma8452 accelerators iio driver -D: Kernel cleanups +D: pegasus_notetaker input driver +D: Kernel fixes and cleanups S: Garnisonstraße 26 S: 4020 Linz S: Austria -- GitLab From 89a2848381b5fcd9c4d9c0cd97680e3b28730e31 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Thu, 27 Oct 2016 17:46:56 -0700 Subject: [PATCH 1088/1167] mm: memcontrol: do not recurse in direct reclaim On 4.0, we saw a stack corruption from a page fault entering direct memory cgroup reclaim, calling into btrfs_releasepage(), which then tried to allocate an extent and recursed back into a kmem charge ad nauseam: [...] btrfs_releasepage+0x2c/0x30 try_to_release_page+0x32/0x50 shrink_page_list+0x6da/0x7a0 shrink_inactive_list+0x1e5/0x510 shrink_lruvec+0x605/0x7f0 shrink_zone+0xee/0x320 do_try_to_free_pages+0x174/0x440 try_to_free_mem_cgroup_pages+0xa7/0x130 try_charge+0x17b/0x830 memcg_charge_kmem+0x40/0x80 new_slab+0x2d9/0x5a0 __slab_alloc+0x2fd/0x44f kmem_cache_alloc+0x193/0x1e0 alloc_extent_state+0x21/0xc0 __clear_extent_bit+0x2b5/0x400 try_release_extent_mapping+0x1a3/0x220 __btrfs_releasepage+0x31/0x70 btrfs_releasepage+0x2c/0x30 try_to_release_page+0x32/0x50 shrink_page_list+0x6da/0x7a0 shrink_inactive_list+0x1e5/0x510 shrink_lruvec+0x605/0x7f0 shrink_zone+0xee/0x320 do_try_to_free_pages+0x174/0x440 try_to_free_mem_cgroup_pages+0xa7/0x130 try_charge+0x17b/0x830 mem_cgroup_try_charge+0x65/0x1c0 handle_mm_fault+0x117f/0x1510 __do_page_fault+0x177/0x420 do_page_fault+0xc/0x10 page_fault+0x22/0x30 On later kernels, kmem charging is opt-in rather than opt-out, and that particular kmem allocation in btrfs_releasepage() is no longer being charged and won't recurse and overrun the stack anymore. But it's not impossible for an accounted allocation to happen from the memcg direct reclaim context, and we needed to reproduce this crash many times before we even got a useful stack trace out of it. Like other direct reclaimers, mark tasks in memcg reclaim PF_MEMALLOC to avoid recursing into any other form of direct reclaim. Then let recursive charges from PF_MEMALLOC contexts bypass the cgroup limit. Link: http://lkml.kernel.org/r/20161025141050.GA13019@cmpxchg.org Signed-off-by: Johannes Weiner Acked-by: Michal Hocko Cc: Vladimir Davydov Cc: Tejun Heo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memcontrol.c | 9 +++++++++ mm/vmscan.c | 2 ++ 2 files changed, 11 insertions(+) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index ae052b5e33152..0f870ba43942e 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1917,6 +1917,15 @@ static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask, current->flags & PF_EXITING)) goto force; + /* + * Prevent unbounded recursion when reclaim operations need to + * allocate memory. This might exceed the limits temporarily, + * but we prefer facilitating memory reclaim and getting back + * under the limit over triggering OOM kills in these cases. + */ + if (unlikely(current->flags & PF_MEMALLOC)) + goto force; + if (unlikely(task_in_memcg_oom(current))) goto nomem; diff --git a/mm/vmscan.c b/mm/vmscan.c index 744f926af4420..76fda22681480 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -3043,7 +3043,9 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, sc.gfp_mask, sc.reclaim_idx); + current->flags |= PF_MEMALLOC; nr_reclaimed = do_try_to_free_pages(zonelist, &sc); + current->flags &= ~PF_MEMALLOC; trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed); -- GitLab From 62e931fac45b17c2a42549389879411572f75804 Mon Sep 17 00:00:00 2001 From: Daniel Mentz Date: Thu, 27 Oct 2016 17:46:59 -0700 Subject: [PATCH 1089/1167] lib/genalloc.c: start search from start of chunk gen_pool_alloc_algo() iterates over the chunks of a pool trying to find a contiguous block of memory that satisfies the allocation request. The shortcut if (size > atomic_read(&chunk->avail)) continue; makes the loop skip over chunks that do not have enough bytes left to fulfill the request. There are two situations, though, where an allocation might still fail: (1) The available memory is not contiguous, i.e. the request cannot be fulfilled due to external fragmentation. (2) A race condition. Another thread runs the same code concurrently and is quicker to grab the available memory. In those situations, the loop calls pool->algo() to search the entire chunk, and pool->algo() returns some value that is >= end_bit to indicate that the search failed. This return value is then assigned to start_bit. The variables start_bit and end_bit describe the range that should be searched, and this range should be reset for every chunk that is searched. Today, the code fails to reset start_bit to 0. As a result, prefixes of subsequent chunks are ignored. Memory allocations might fail even though there is plenty of room left in these prefixes of those other chunks. Fixes: 7f184275aa30 ("lib, Make gen_pool memory allocator lockless") Link: http://lkml.kernel.org/r/1477420604-28918-1-git-send-email-danielmentz@google.com Signed-off-by: Daniel Mentz Reviewed-by: Mathieu Desnoyers Acked-by: Will Deacon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/genalloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/genalloc.c b/lib/genalloc.c index 0a1139644d328..144fe6b1a03ea 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -292,7 +292,7 @@ unsigned long gen_pool_alloc_algo(struct gen_pool *pool, size_t size, struct gen_pool_chunk *chunk; unsigned long addr = 0; int order = pool->min_alloc_order; - int nbits, start_bit = 0, end_bit, remain; + int nbits, start_bit, end_bit, remain; #ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG BUG_ON(in_nmi()); @@ -307,6 +307,7 @@ unsigned long gen_pool_alloc_algo(struct gen_pool *pool, size_t size, if (size > atomic_read(&chunk->avail)) continue; + start_bit = 0; end_bit = chunk_size(chunk) >> order; retry: start_bit = algo(chunk->bits, end_bit, start_bit, -- GitLab From 14f947c87a2164b19c7f8c02234f4f348e03f409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 27 Oct 2016 17:47:02 -0700 Subject: [PATCH 1090/1167] fs: exofs: print a hex number after a 0x prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It makes the message hard to interpret correctly if a base 10 number is prefixed by 0x. So change to a hex number. Link: http://lkml.kernel.org/r/20161026125658.25728-2-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Cc: Boaz Harrosh Cc: Benny Halevy Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/exofs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c index 79101651fe9ed..42f9a0a0c4caf 100644 --- a/fs/exofs/dir.c +++ b/fs/exofs/dir.c @@ -137,7 +137,7 @@ static bool exofs_check_page(struct page *page) bad_entry: EXOFS_ERR( "ERROR [exofs_check_page]: bad entry in directory(0x%lx): %s - " - "offset=%lu, inode=0x%llu, rec_len=%d, name_len=%d\n", + "offset=%lu, inode=0x%llx, rec_len=%d, name_len=%d\n", dir->i_ino, error, (page->index<inode_no)), rec_len, p->name_len); -- GitLab From ee52c44dee63ff2686a7b0d98fff7c80852ac022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 27 Oct 2016 17:47:04 -0700 Subject: [PATCH 1091/1167] block: DAC960: print a hex number after a 0x prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It makes the message hard to interpret correctly if a base 10 number is prefixed by 0x. So change to a hex number. Link: http://lkml.kernel.org/r/20161026125658.25728-3-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/DAC960.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 811e11c82f329..0809cda93cc03 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -2954,7 +2954,7 @@ DAC960_DetectController(struct pci_dev *PCI_Device, case DAC960_PD_Controller: if (!request_region(Controller->IO_Address, 0x80, Controller->FullModelName)) { - DAC960_Error("IO port 0x%d busy for Controller at\n", + DAC960_Error("IO port 0x%lx busy for Controller at\n", Controller, Controller->IO_Address); goto Failure; } @@ -2990,7 +2990,7 @@ DAC960_DetectController(struct pci_dev *PCI_Device, case DAC960_P_Controller: if (!request_region(Controller->IO_Address, 0x80, Controller->FullModelName)){ - DAC960_Error("IO port 0x%d busy for Controller at\n", + DAC960_Error("IO port 0x%lx busy for Controller at\n", Controller, Controller->IO_Address); goto Failure; } -- GitLab From 9105585d13bd2946f0eb2a664e32ec9a9b23bf1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 27 Oct 2016 17:47:07 -0700 Subject: [PATCH 1092/1167] ipack: print a hex number after a 0x prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It makes the result hard to interpret correctly if a base 10 number is prefixed by 0x. So change to a hex number. Link: http://lkml.kernel.org/r/20161026125658.25728-4-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Cc: Samuel Iglesias Gonsalvez Cc: Jens Taprogge Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ipack/ipack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ipack/ipack.c b/drivers/ipack/ipack.c index c0e7b624ce547..12102448fdddf 100644 --- a/drivers/ipack/ipack.c +++ b/drivers/ipack/ipack.c @@ -178,7 +178,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, idev->id_vendor, idev->id_device); } -ipack_device_attr(id_format, "0x%hhu\n"); +ipack_device_attr(id_format, "0x%hhx\n"); static DEVICE_ATTR_RO(id); static DEVICE_ATTR_RO(id_device); -- GitLab From 17a88939568be28a8ea5195b55ef3a84a469777e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 27 Oct 2016 17:47:10 -0700 Subject: [PATCH 1093/1167] cris/arch-v32: cryptocop: print a hex number after a 0x prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It makes the result hard to interpret correctly if a base 10 number is prefixed by 0x. So change to a hex number. Link: http://lkml.kernel.org/r/20161026125658.25728-6-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Cc: Mikael Starvik Cc: Jesper Nilsson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/cris/arch-v32/drivers/cryptocop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c index 099e170a93ee7..0068fd411a847 100644 --- a/arch/cris/arch-v32/drivers/cryptocop.c +++ b/arch/cris/arch-v32/drivers/cryptocop.c @@ -3149,7 +3149,7 @@ static void print_dma_descriptors(struct cryptocop_int_operation *iop) printk("print_dma_descriptors start\n"); printk("iop:\n"); - printk("\tsid: 0x%lld\n", iop->sid); + printk("\tsid: 0x%llx\n", iop->sid); printk("\tcdesc_out: 0x%p\n", iop->cdesc_out); printk("\tcdesc_in: 0x%p\n", iop->cdesc_in); -- GitLab From 8e819101ce6fcc58801c9a813ea99c4da0255eef Mon Sep 17 00:00:00 2001 From: Dimitri Sivanich Date: Thu, 27 Oct 2016 17:47:12 -0700 Subject: [PATCH 1094/1167] drivers/misc/sgi-gru/grumain.c: remove bogus 0x prefix from printk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Would like to have this be a decimal number. Link: http://lkml.kernel.org/r/20161026134746.GA30169@sgi.com Signed-off-by: Dimitri Sivanich Reported-by: Uwe Kleine-König Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/grumain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index 1525870f460aa..33741ad4a74a0 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c @@ -283,7 +283,7 @@ static void gru_unload_mm_tracker(struct gru_state *gru, spin_lock(&gru->gs_asid_lock); BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap); asids->mt_ctxbitmap ^= ctxbitmap; - gru_dbg(grudev, "gid %d, gts %p, gms %p, ctxnum 0x%d, asidmap 0x%lx\n", + gru_dbg(grudev, "gid %d, gts %p, gms %p, ctxnum %d, asidmap 0x%lx\n", gru->gs_gid, gts, gms, gts->ts_ctxnum, gms->ms_asidmap[0]); spin_unlock(&gru->gs_asid_lock); spin_unlock(&gms->ms_asid_lock); -- GitLab From 1c27f646b18fb56308dff82784ca61951bad0b48 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 27 Oct 2016 14:36:23 +0200 Subject: [PATCH 1095/1167] x86/microcode/AMD: Fix more fallout from CONFIG_RANDOMIZE_MEMORY=y We needed the physical address of the container in order to compute the offset within the relocated ramdisk. And we did this by doing __pa() on the virtual address. However, __pa() does checks whether the physical address is within PAGE_OFFSET and __START_KERNEL_map - see __phys_addr() - which fail if we have CONFIG_RANDOMIZE_MEMORY enabled: we feed a virtual address which *doesn't* have the randomization offset into a function which uses PAGE_OFFSET which *does* have that offset. This makes this check fire: VIRTUAL_BUG_ON((x > y) || !phys_addr_valid(x)); ^^^^^^ due to the randomization offset. The fix is as simple as using __pa_nodebug() because we do that randomization offset accounting later in that function ourselves. Reported-by: Bob Peterson Tested-by: Bob Peterson Signed-off-by: Borislav Petkov Cc: Andreas Gruenbacher Cc: Andy Lutomirski Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Mel Gorman Cc: Peter Zijlstra Cc: Steven Whitehouse Cc: Thomas Gleixner Cc: linux-mm Cc: stable@vger.kernel.org # 4.9 Link: http://lkml.kernel.org/r/20161027123623.j2jri5bandimboff@pd.tnic Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/microcode/amd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 620ab06bcf457..017bda12caaed 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -429,7 +429,7 @@ int __init save_microcode_in_initrd_amd(void) * We need the physical address of the container for both bitness since * boot_params.hdr.ramdisk_image is a physical address. */ - cont = __pa(container); + cont = __pa_nodebug(container); cont_va = container; #endif -- GitLab From 0933840acf7b65d6d30a5b6089d882afea57aca3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 20 Oct 2016 13:10:11 +0200 Subject: [PATCH 1096/1167] perf/core: Protect PMU device removal with a 'pmu_bus_running' check, to fix CONFIG_DEBUG_TEST_DRIVER_REMOVE=y kernel panic CAI Qian reported a crash in the PMU uncore device removal code, enabled by the CONFIG_DEBUG_TEST_DRIVER_REMOVE=y option: https://marc.info/?l=linux-kernel&m=147688837328451 The reason for the crash is that perf_pmu_unregister() tries to remove a PMU device which is not added at this point. We add PMU devices only after pmu_bus is registered, which happens in the perf_event_sysfs_init() call and sets the 'pmu_bus_running' flag. The fix is to get the 'pmu_bus_running' flag state at the point the PMU is taken out of the PMU list and remove the device later only if it's set. Reported-by: CAI Qian Tested-by: CAI Qian Signed-off-by: Jiri Olsa Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Greg Kroah-Hartman Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Rob Herring Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20161020111011.GA13361@krava Signed-off-by: Ingo Molnar --- kernel/events/core.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index c6e47e97b33fd..a5d2e62faf7e5 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -8855,7 +8855,10 @@ EXPORT_SYMBOL_GPL(perf_pmu_register); void perf_pmu_unregister(struct pmu *pmu) { + int remove_device; + mutex_lock(&pmus_lock); + remove_device = pmu_bus_running; list_del_rcu(&pmu->entry); mutex_unlock(&pmus_lock); @@ -8869,10 +8872,12 @@ void perf_pmu_unregister(struct pmu *pmu) free_percpu(pmu->pmu_disable_count); if (pmu->type >= PERF_TYPE_MAX) idr_remove(&pmu_idr, pmu->type); - if (pmu->nr_addr_filters) - device_remove_file(pmu->dev, &dev_attr_nr_addr_filters); - device_del(pmu->dev); - put_device(pmu->dev); + if (remove_device) { + if (pmu->nr_addr_filters) + device_remove_file(pmu->dev, &dev_attr_nr_addr_filters); + device_del(pmu->dev); + put_device(pmu->dev); + } free_pmu_context(pmu); } EXPORT_SYMBOL_GPL(perf_pmu_unregister); -- GitLab From 5aab90ce1ec449912a2ebc4d45e0c85dac29e9dd Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 26 Oct 2016 11:48:24 +0200 Subject: [PATCH 1097/1167] perf/powerpc: Don't call perf_event_disable() from atomic context The trinity syscall fuzzer triggered following WARN() on powerpc: WARNING: CPU: 9 PID: 2998 at arch/powerpc/kernel/hw_breakpoint.c:278 ... NIP [c00000000093aedc] .hw_breakpoint_handler+0x28c/0x2b0 LR [c00000000093aed8] .hw_breakpoint_handler+0x288/0x2b0 Call Trace: [c0000002f7933580] [c00000000093aed8] .hw_breakpoint_handler+0x288/0x2b0 (unreliable) [c0000002f7933630] [c0000000000f671c] .notifier_call_chain+0x7c/0xf0 [c0000002f79336d0] [c0000000000f6abc] .__atomic_notifier_call_chain+0xbc/0x1c0 [c0000002f7933780] [c0000000000f6c40] .notify_die+0x70/0xd0 [c0000002f7933820] [c00000000001a74c] .do_break+0x4c/0x100 [c0000002f7933920] [c0000000000089fc] handle_dabr_fault+0x14/0x48 Followed by a lockdep warning: =============================== [ INFO: suspicious RCU usage. ] 4.8.0-rc5+ #7 Tainted: G W ------------------------------- ./include/linux/rcupdate.h:556 Illegal context switch in RCU read-side critical section! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 0 2 locks held by ls/2998: #0: (rcu_read_lock){......}, at: [] .__atomic_notifier_call_chain+0x0/0x1c0 #1: (rcu_read_lock){......}, at: [] .hw_breakpoint_handler+0x0/0x2b0 stack backtrace: CPU: 9 PID: 2998 Comm: ls Tainted: G W 4.8.0-rc5+ #7 Call Trace: [c0000002f7933150] [c00000000094b1f8] .dump_stack+0xe0/0x14c (unreliable) [c0000002f79331e0] [c00000000013c468] .lockdep_rcu_suspicious+0x138/0x180 [c0000002f7933270] [c0000000001005d8] .___might_sleep+0x278/0x2e0 [c0000002f7933300] [c000000000935584] .mutex_lock_nested+0x64/0x5a0 [c0000002f7933410] [c00000000023084c] .perf_event_ctx_lock_nested+0x16c/0x380 [c0000002f7933500] [c000000000230a80] .perf_event_disable+0x20/0x60 [c0000002f7933580] [c00000000093aeec] .hw_breakpoint_handler+0x29c/0x2b0 [c0000002f7933630] [c0000000000f671c] .notifier_call_chain+0x7c/0xf0 [c0000002f79336d0] [c0000000000f6abc] .__atomic_notifier_call_chain+0xbc/0x1c0 [c0000002f7933780] [c0000000000f6c40] .notify_die+0x70/0xd0 [c0000002f7933820] [c00000000001a74c] .do_break+0x4c/0x100 [c0000002f7933920] [c0000000000089fc] handle_dabr_fault+0x14/0x48 While it looks like the first WARN() is probably valid, the other one is triggered by disabling event via perf_event_disable() from atomic context. The event is disabled here in case we were not able to emulate the instruction that hit the breakpoint. By disabling the event we unschedule the event and make sure it's not scheduled back. But we can't call perf_event_disable() from atomic context, instead we need to use the event's pending_disable irq_work method to disable it. Reported-by: Jan Stancek Signed-off-by: Jiri Olsa Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Huang Ying Cc: Jiri Olsa Cc: Linus Torvalds Cc: Michael Neuling Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20161026094824.GA21397@krava Signed-off-by: Ingo Molnar --- arch/powerpc/kernel/hw_breakpoint.c | 2 +- include/linux/perf_event.h | 1 + kernel/events/core.c | 10 ++++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 9781c69eae576..03d089b3ed726 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -275,7 +275,7 @@ int hw_breakpoint_handler(struct die_args *args) if (!stepped) { WARN(1, "Unable to handle hardware breakpoint. Breakpoint at " "0x%lx will be disabled.", info->address); - perf_event_disable(bp); + perf_event_disable_inatomic(bp); goto out; } /* diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 060d0ede88df6..4741ecdb98174 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1257,6 +1257,7 @@ extern u64 perf_swevent_set_period(struct perf_event *event); extern void perf_event_enable(struct perf_event *event); extern void perf_event_disable(struct perf_event *event); extern void perf_event_disable_local(struct perf_event *event); +extern void perf_event_disable_inatomic(struct perf_event *event); extern void perf_event_task_tick(void); #else /* !CONFIG_PERF_EVENTS: */ static inline void * diff --git a/kernel/events/core.c b/kernel/events/core.c index a5d2e62faf7e5..0e292132efaca 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1960,6 +1960,12 @@ void perf_event_disable(struct perf_event *event) } EXPORT_SYMBOL_GPL(perf_event_disable); +void perf_event_disable_inatomic(struct perf_event *event) +{ + event->pending_disable = 1; + irq_work_queue(&event->pending); +} + static void perf_set_shadow_time(struct perf_event *event, struct perf_event_context *ctx, u64 tstamp) @@ -7075,8 +7081,8 @@ static int __perf_event_overflow(struct perf_event *event, if (events && atomic_dec_and_test(&event->event_limit)) { ret = 1; event->pending_kill = POLL_HUP; - event->pending_disable = 1; - irq_work_queue(&event->pending); + + perf_event_disable_inatomic(event); } READ_ONCE(event->overflow_handler)(event, data, regs); -- GitLab From f92b7604149a55cb601fc0b52911b1e11f0f2514 Mon Sep 17 00:00:00 2001 From: Imre Palik Date: Fri, 21 Oct 2016 01:18:59 -0700 Subject: [PATCH 1098/1167] perf/x86/intel: Honour the CPUID for number of fixed counters in hypervisors perf doesn't seem to honour the number of fixed counters specified by CPUID leaf 0xa. It always assumes that Intel CPUs have at least 3 fixed counters. So if some of the fixed counters are masked out by the hypervisor, it still tries to check/set them. This patch makes perf behave nicer when the kernel is running under a hypervisor that doesn't expose all the counters. This patch contains some ideas from Matt Wilson. Signed-off-by: Imre Palik Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Andi Kleen Cc: Alexander Kozyrev Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Artyom Kuanbekov Cc: David Carrillo-Cisneros Cc: David Woodhouse Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Matt Wilson Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1477037939-15605-1-git-send-email-imrep.amz@gmail.com Signed-off-by: Ingo Molnar --- arch/x86/events/intel/core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index eab0915f59951..a74a2dbc01801 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3607,10 +3607,14 @@ __init int intel_pmu_init(void) /* * Quirk: v2 perfmon does not report fixed-purpose events, so - * assume at least 3 events: + * assume at least 3 events, when not running in a hypervisor: */ - if (version > 1) - x86_pmu.num_counters_fixed = max((int)edx.split.num_counters_fixed, 3); + if (version > 1) { + int assume = 3 * !boot_cpu_has(X86_FEATURE_HYPERVISOR); + + x86_pmu.num_counters_fixed = + max((int)edx.split.num_counters_fixed, assume); + } if (boot_cpu_has(X86_FEATURE_PDCM)) { u64 capabilities; -- GitLab From 9bcffe7575b721d7b6d9b3090fe18809d9806e78 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Thu, 27 Oct 2016 18:04:06 +0200 Subject: [PATCH 1099/1167] tty/serial: at91: fix hardware handshake on Atmel platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management when hardware handshake is enabled"), the hardware handshake wasn't functional anymore on Atmel platforms (beside SAMA5D2). To understand why, one has to understand the flag ATMEL_US_USMODE_HWHS first: Before commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management when hardware handshake is enabled"), this flag was never set. Thus, the CTS/RTS where only handled by serial_core (and everything worked just fine). This commit introduced the use of the ATMEL_US_USMODE_HWHS flag, enabling it for all boards when the user space enables flow control. When the ATMEL_US_USMODE_HWHS is set, the Atmel USART controller handles a part of the flow control job: - disable the transmitter when the CTS pin gets high. - drive the RTS pin high when the DMA buffer transfer is completed or PDC RX buffer full or RX FIFO is beyond threshold. (depending on the controller version). NB: This feature is *not* mandatory for the flow control to work. (Nevertheless, it's very useful if low latencies are needed.) Now, the specifics of the ATMEL_US_USMODE_HWHS flag: - For platforms with DMAC and no FIFOs (sam9x25, sam9x35, sama5D3, sama5D4, sam9g15, sam9g25, sam9g35)* this feature simply doesn't work. ( source: https://lkml.org/lkml/2016/9/7/598 ) Tested it on sam9g35, the RTS pins always stays up, even when RXEN=1 or a new DMA transfer descriptor is set. => ATMEL_US_USMODE_HWHS must not be used for those platforms - For platforms with a PDC (sam926{0,1,3}, sam9g10, sam9g20, sam9g45, sam9g46)*, there's another kind of problem. Once the flag ATMEL_US_USMODE_HWHS is set, the RTS pin can't be driven anymore via RTSEN/RTSDIS in USART Control Register. The RTS pin can only be driven by enabling/disabling the receiver or setting RCR=RNCR=0 in the PDC (Receive (Next) Counter Register). => Doing this is beyond the scope of this patch and could add other bugs, so the original (and working) behaviour should be set for those platforms (meaning ATMEL_US_USMODE_HWHS flag should be unset). - For platforms with a FIFO (sama5d2)*, the RTS pin is driven according to the RX FIFO thresholds, and can be also driven by RTSEN/RTSDIS in USART Control Register. No problem here. (This was the use case of commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management when hardware handshake is enabled")) NB: If the CTS pin declared as a GPIO in the DTS, (for instance cts-gpios = <&pioA PIN_PB31 GPIO_ACTIVE_LOW>), the transmitter will be disabled. => ATMEL_US_USMODE_HWHS flag can be set for this platform ONLY IF the CTS pin is not a GPIO. So, the only case when ATMEL_US_USMODE_HWHS can be enabled is when (atmel_use_fifo(port) && !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) Tested on all Atmel USART controller flavours: AT91SAM9G35-CM (DMAC flavour), AT91SAM9G20-EK (PDC flavour), SAMA5D2xplained (FIFO flavour). * the list may not be exhaustive Cc: #4.4+ (beware, missing atmel_port variable) Fixes: 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management when hardware handshake is enabled") Signed-off-by: Richard Genoud Acked-by: Alexandre Belloni Acked-by: Cyrille Pitchen Acked-by: Uwe Kleine-König Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index fd8aa1f4ba782..168b10cad47b5 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2132,11 +2132,29 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, mode |= ATMEL_US_USMODE_RS485; } else if (termios->c_cflag & CRTSCTS) { /* RS232 with hardware handshake (RTS/CTS) */ - if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) { - dev_info(port->dev, "not enabling hardware flow control because DMA is used"); - termios->c_cflag &= ~CRTSCTS; - } else { + if (atmel_use_fifo(port) && + !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) { + /* + * with ATMEL_US_USMODE_HWHS set, the controller will + * be able to drive the RTS pin high/low when the RX + * FIFO is above RXFTHRES/below RXFTHRES2. + * It will also disable the transmitter when the CTS + * pin is high. + * This mode is not activated if CTS pin is a GPIO + * because in this case, the transmitter is always + * disabled (there must be an internal pull-up + * responsible for this behaviour). + * If the RTS pin is a GPIO, the controller won't be + * able to drive it according to the FIFO thresholds, + * but it will be handled by the driver. + */ mode |= ATMEL_US_USMODE_HWHS; + } else { + /* + * For platforms without FIFO, the flow control is + * handled by the driver. + */ + mode |= ATMEL_US_USMODE_NORMAL; } } else { /* RS232 without hadware handshake */ -- GitLab From 4dda864d73079a1eb01fab4ec29b97db150163bf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 28 Oct 2016 07:07:47 -0500 Subject: [PATCH 1100/1167] tty: serial_core: Fix serial console crash on port shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The port->console flag is always false, as uart_console() is called before the serial console has been registered. Hence for a serial port used as the console, uart_tty_port_shutdown() will still be called when userspace closes the port, powering it down. This may lead to a system lock up when the serial console driver writes to the serial port's registers. To fix this, move the setting of port->console after the call to uart_configure_port(), which registers the serial console. Fixes: 761ed4a94582ab29 ("tty: serial_core: convert uart_close to use tty_port_close") Reported-by: Niklas Söderlund Signed-off-by: Geert Uytterhoeven Acked-by: Rob Herring Tested-by: Mugunthan V N Tested-by: Niklas Söderlund [robh: rebased on tty-linus] Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 664c99aeeca58..ce8899c13af3d 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2759,6 +2759,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) uart_configure_port(drv, state, uport); + port->console = uart_console(uport); + num_groups = 2; if (uport->attr_group) num_groups++; -- GitLab From d0f4bce2bce7e998abc906f3590e9032af7a41ba Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Oct 2016 07:07:48 -0500 Subject: [PATCH 1101/1167] tty: serial_core: fix NULL struct tty pointer access in uart_write_wakeup Since commit 761ed4a94582ab29 ("tty: serial_core: convert uart_close to use tty_port_close"), the serial console is broken on various systems and typing "reboot" splats the following on the serial console: INIT: Sending p[ 427.863916] BUG: unable to handle kernel NULL pointer dereference at 00000000000001e0 [ 427.885156] IP: [] tty_wakeup+0xc/0x70 [ 427.898337] PGD 0 [ 427.902051] [ 427.907498] Oops: 0000 [#1] PREEMPT SMP [ 427.917635] Modules linked in: nfsv3 nfs_acl nfs fscache lockd sunrpc grace edd af_packet cpufreq_conservative cpufreq_userspace cpufreq_powersave fuse loop md_mod dm_mod joydev hid_generic usbhid ipmi_ssif ohci_pci ohci_hcd ehci_pci ehci_hcd e1000e ptp firewire_ohci edac_core pps_core tpm_infineon sp5100_tco firewire_core acpi_cpufreq serio_raw pcspkr fjes usbcore shpchp edac_mce_amd tpm_tis ipmi_si tpm_tis_core i2c_piix4 k10temp sg ipmi_msghandler tpm sr_mod button cdrom kvm_amd kvm irqbypass crc_itu_t ast ttm drm_kms_helper drm fb_sys_fops sysimgblt sysfillrect syscopyarea i2c_algo_bit scsi_dh_rdac scsi_dh_alua scsi_dh_emc scsi_dh_hp_sw ata_generic pata_atiixp [ 428.054179] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.9.0-rc1-1.g73e3f23-default #1 [ 428.072868] Hardware name: System manufacturer System Product Name/KGP(M)E-D16, BIOS 0902 12/03/2010 [ 428.094755] task: ffffffffa2c0d500 task.stack: ffffffffa2c00000 [ 428.109717] RIP: 0010:[] [] tty_wakeup+0xc/0x70 [ 428.128407] RSP: 0018:ffff9a1a5fc03df8 EFLAGS: 00010086 [ 428.142184] RAX: ffff9a1857258000 RBX: ffffffffa3050ea0 RCX: 0000000000000000 [ 428.159649] RDX: 000000000000001b RSI: 0000000000000000 RDI: 0000000000000000 [ 428.177109] RBP: ffff9a1a5fc03e08 R08: 0000000000000000 R09: 0000000000000000 [ 428.194547] R10: 0000000000021c77 R11: 0000000000000000 R12: ffff9a1857258000 [ 428.212002] R13: 0000000000000000 R14: 0000000000000020 R15: 0000000000000020 [ 428.229481] FS: 0000000000000000(0000) GS:ffff9a1a5fc00000(0000) knlGS:0000000000000000 [ 428.248938] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 428.263726] CR2: 00000000000001e0 CR3: 0000000390c06000 CR4: 00000000000006f0 [ 428.281331] Stack: [ 428.288696] ffffffffa3050ea0 ffff9a1857258000 ffff9a1a5fc03e18 ffffffffa24e0ab1 [ 428.307064] ffff9a1a5fc03e40 ffffffffa24e8865 ffffffffa3050ea0 00000000000000c2 [ 428.325456] 0000000000000046 ffff9a1a5fc03e78 ffffffffa24e8a5f ffffffffa3050ea0 [ 428.343905] Call Trace: [ 428.352319] [ 428.356216] [] uart_write_wakeup+0x21/0x30 The problem is for console ports, the serial port is not shutdown and interrupts may fire after the struct tty is gone. Simply calling the tty_port helper tty_port_tty_wakeup instead of tty_wakeup directly will ensure there is a valid struct tty. Fixes: 761ed4a94582ab29 ("tty: serial_core: convert uart_close to use tty_port_close") Reported-by: Borislav Petkov Reported-by: Mike Galbraith Cc: Jiri Slaby Cc: Greg Kroah-Hartman Cc: linux-serial@vger.kernel.org Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index ce8899c13af3d..f2303f390345e 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -111,7 +111,7 @@ void uart_write_wakeup(struct uart_port *port) * closed. No cookie for you. */ BUG_ON(!state); - tty_wakeup(state->port.tty); + tty_port_tty_wakeup(&state->port); } static void uart_stop(struct tty_struct *tty) @@ -632,7 +632,7 @@ static void uart_flush_buffer(struct tty_struct *tty) if (port->ops->flush_buffer) port->ops->flush_buffer(port); uart_port_unlock(port, flags); - tty_wakeup(tty); + tty_port_tty_wakeup(&state->port); } /* -- GitLab From 6ad37567b6b886121e250036e489d82cde5e5e94 Mon Sep 17 00:00:00 2001 From: Martyn Welch Date: Fri, 21 Oct 2016 17:36:19 +0100 Subject: [PATCH 1102/1167] vme: vme_get_size potentially returning incorrect value on failure The function vme_get_size returns the size of the window to the caller, however it doesn't check the return value of the call to vme_master_get. Return 0 on failure rather than anything else. Suggested-by: Dan Carpenter Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/vme/vme.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index 15b64076bc262..bdbadaa47ef3e 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c @@ -156,12 +156,16 @@ size_t vme_get_size(struct vme_resource *resource) case VME_MASTER: retval = vme_master_get(resource, &enabled, &base, &size, &aspace, &cycle, &dwidth); + if (retval) + return 0; return size; break; case VME_SLAVE: retval = vme_slave_get(resource, &enabled, &base, &size, &buf_base, &aspace, &cycle); + if (retval) + return 0; return size; break; -- GitLab From a7a7aeefbca2982586ba2c9fd7739b96416a6d1d Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Wed, 19 Oct 2016 12:29:41 +0200 Subject: [PATCH 1103/1167] GenWQE: Fix bad page access during abort of resource allocation When interrupting an application which was allocating DMAable memory, it was possible, that the DMA memory was deallocated twice, leading to the error symptoms below. Thanks to Gerald, who analyzed the problem and provided this patch. I agree with his analysis of the problem: ddcb_cmd_fixups() -> genwqe_alloc_sync_sgl() (fails in f/lpage, but sgl->sgl != NULL and f/lpage maybe also != NULL) -> ddcb_cmd_cleanup() -> genwqe_free_sync_sgl() (double free, because sgl->sgl != NULL and f/lpage maybe also != NULL) In this scenario we would have exactly the kind of double free that would explain the WARNING / Bad page state, and as expected it is caused by broken error handling (cleanup). Using the Ubuntu git source, tag Ubuntu-4.4.0-33.52, he was able to reproduce the "Bad page state" issue, and with the patch on top he could not reproduce it any more. ------------[ cut here ]------------ WARNING: at /build/linux-o03cxz/linux-4.4.0/arch/s390/include/asm/pci_dma.h:141 Modules linked in: qeth_l2 ghash_s390 prng aes_s390 des_s390 des_generic sha512_s390 sha256_s390 sha1_s390 sha_common genwqe_card qeth crc_itu_t qdio ccwgroup vmur dm_multipath dasd_eckd_mod dasd_mod CPU: 2 PID: 3293 Comm: genwqe_gunzip Not tainted 4.4.0-33-generic #52-Ubuntu task: 0000000032c7e270 ti: 00000000324e4000 task.ti: 00000000324e4000 Krnl PSW : 0404c00180000000 0000000000156346 (dma_update_cpu_trans+0x9e/0xa8) R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:0 PM:0 EA:3 Krnl GPRS: 00000000324e7bcd 0000000000c3c34a 0000000027628298 000000003215b400 0000000000000400 0000000000001fff 0000000000000400 0000000116853000 07000000324e7b1e 0000000000000001 0000000000000001 0000000000000001 0000000000001000 0000000116854000 0000000000156402 00000000324e7a38 Krnl Code: 000000000015633a: 95001000 cli 0(%r1),0 000000000015633e: a774ffc3 brc 7,1562c4 #0000000000156342: a7f40001 brc 15,156344 >0000000000156346: 92011000 mvi 0(%r1),1 000000000015634a: a7f4ffbd brc 15,1562c4 000000000015634e: 0707 bcr 0,%r7 0000000000156350: c00400000000 brcl 0,156350 0000000000156356: eb7ff0500024 stmg %r7,%r15,80(%r15) Call Trace: ([<00000000001563e0>] dma_update_trans+0x90/0x228) [<00000000001565dc>] s390_dma_unmap_pages+0x64/0x160 [<00000000001567c2>] s390_dma_free+0x62/0x98 [<000003ff801310ce>] __genwqe_free_consistent+0x56/0x70 [genwqe_card] [<000003ff801316d0>] genwqe_free_sync_sgl+0xf8/0x160 [genwqe_card] [<000003ff8012bd6e>] ddcb_cmd_cleanup+0x86/0xa8 [genwqe_card] [<000003ff8012c1c0>] do_execute_ddcb+0x110/0x348 [genwqe_card] [<000003ff8012c914>] genwqe_ioctl+0x51c/0xc20 [genwqe_card] [<000000000032513a>] do_vfs_ioctl+0x3b2/0x518 [<0000000000325344>] SyS_ioctl+0xa4/0xb8 [<00000000007b86c6>] system_call+0xd6/0x264 [<000003ff9e8e520a>] 0x3ff9e8e520a Last Breaking-Event-Address: [<0000000000156342>] dma_update_cpu_trans+0x9a/0xa8 ---[ end trace 35996336235145c8 ]--- BUG: Bad page state in process jbd2/dasdb1-8 pfn:3215b page:000003d100c856c0 count:-1 mapcount:0 mapping: (null) index:0x0 flags: 0x3fffc0000000000() page dumped because: nonzero _count Signed-off-by: Gerald Schaefer Signed-off-by: Frank Haverkamp Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_utils.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index 8a679ecc8fd10..fc2794b513faf 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c @@ -352,17 +352,27 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, if (copy_from_user(sgl->lpage, user_addr + user_size - sgl->lpage_size, sgl->lpage_size)) { rc = -EFAULT; - goto err_out1; + goto err_out2; } } return 0; + err_out2: + __genwqe_free_consistent(cd, PAGE_SIZE, sgl->lpage, + sgl->lpage_dma_addr); + sgl->lpage = NULL; + sgl->lpage_dma_addr = 0; err_out1: __genwqe_free_consistent(cd, PAGE_SIZE, sgl->fpage, sgl->fpage_dma_addr); + sgl->fpage = NULL; + sgl->fpage_dma_addr = 0; err_out: __genwqe_free_consistent(cd, sgl->sgl_size, sgl->sgl, sgl->sgl_dma_addr); + sgl->sgl = NULL; + sgl->sgl_dma_addr = 0; + sgl->sgl_size = 0; return -ENOMEM; } -- GitLab From eb94cd68abd9b7c92bf70ddc452d65f1a84c46e2 Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Thu, 6 Oct 2016 04:43:08 -0700 Subject: [PATCH 1104/1167] VMCI: Doorbell create and destroy fixes This change consists of two changes: 1) If vmci_doorbell_create is called when neither guest nor host personality as been initialized, vmci_get_context_id will return VMCI_INVALID_ID. In that case, we should fail the create call. 2) In doorbell destroy, we assume that vmci_guest_code_active() has the same return value on create and destroy. That may not be the case, so we may end up with the wrong refcount. Instead, destroy should check explicitly whether the doorbell is in the index table as an indicator of whether the guest code was active at create time. Reviewed-by: Adit Ranadive Signed-off-by: Jorgen Hansen Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_doorbell.c | 8 +++++++- drivers/misc/vmw_vmci/vmci_driver.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/misc/vmw_vmci/vmci_doorbell.c b/drivers/misc/vmw_vmci/vmci_doorbell.c index a8cee33ae8d2e..b3fa738ae0050 100644 --- a/drivers/misc/vmw_vmci/vmci_doorbell.c +++ b/drivers/misc/vmw_vmci/vmci_doorbell.c @@ -431,6 +431,12 @@ int vmci_doorbell_create(struct vmci_handle *handle, if (vmci_handle_is_invalid(*handle)) { u32 context_id = vmci_get_context_id(); + if (context_id == VMCI_INVALID_ID) { + pr_warn("Failed to get context ID\n"); + result = VMCI_ERROR_NO_RESOURCES; + goto free_mem; + } + /* Let resource code allocate a free ID for us */ new_handle = vmci_make_handle(context_id, VMCI_INVALID_ID); } else { @@ -525,7 +531,7 @@ int vmci_doorbell_destroy(struct vmci_handle handle) entry = container_of(resource, struct dbell_entry, resource); - if (vmci_guest_code_active()) { + if (!hlist_unhashed(&entry->node)) { int result; dbell_index_table_remove(entry); diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c index 896be150e28fa..d7eaf1eb11e7f 100644 --- a/drivers/misc/vmw_vmci/vmci_driver.c +++ b/drivers/misc/vmw_vmci/vmci_driver.c @@ -113,5 +113,5 @@ module_exit(vmci_drv_exit); MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface."); -MODULE_VERSION("1.1.4.0-k"); +MODULE_VERSION("1.1.5.0-k"); MODULE_LICENSE("GPL v2"); -- GitLab From a7d5afe82d4931289250d6e807e35db3885b3b12 Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Tue, 4 Oct 2016 15:26:48 -0300 Subject: [PATCH 1105/1167] MAINTAINERS: Add entry for genwqe driver Frank and I maintain this Signed-off-by: Gabriel Krisman Bertazi Cc: haver@linux.vnet.ibm.com Acked-by: Frank Haverkamp = Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index c447953063428..61f201b7cd956 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5287,6 +5287,12 @@ M: Joe Perches S: Maintained F: scripts/get_maintainer.pl +GENWQE (IBM Generic Workqueue Card) +M: Frank Haverkamp +M: Gabriel Krisman Bertazi +S: Supported +F: drivers/misc/genwqe/ + GFS2 FILE SYSTEM M: Steven Whitehouse M: Bob Peterson -- GitLab From 40b6e61ac72e99672e47cdb99c8d7d226004169b Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 28 Oct 2016 11:08:44 +0200 Subject: [PATCH 1106/1167] ubi: fastmap: Fix add_vol() return value test in ubi_attach_fastmap() Commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists") introduced a bug by changing the possible error codes returned by add_vol(): - this function no longer returns NULL in case of allocation failure but return ERR_PTR(-ENOMEM) - when a duplicate entry in the volume RB tree is found it returns ERR_PTR(-EEXIST) instead of ERR_PTR(-EINVAL) Fix the tests done on add_vol() return val to match this new behavior. Fixes: e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists") Reported-by: Dan Carpenter Signed-off-by: Boris Brezillon Acked-by: Sheng Yong Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/fastmap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 2ff62157d3bb0..c1f5c29e458ef 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -707,11 +707,11 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, fmvhdr->vol_type, be32_to_cpu(fmvhdr->last_eb_bytes)); - if (!av) - goto fail_bad; - if (PTR_ERR(av) == -EINVAL) { - ubi_err(ubi, "volume (ID %i) already exists", - fmvhdr->vol_id); + if (IS_ERR(av)) { + if (PTR_ERR(av) == -EEXIST) + ubi_err(ubi, "volume (ID %i) already exists", + fmvhdr->vol_id); + goto fail_bad; } -- GitLab From a00052a296e54205cf238c75bd98d17d5d02a6db Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Fri, 28 Oct 2016 11:49:03 +0200 Subject: [PATCH 1107/1167] ubifs: Fix regression in ubifs_readdir() Commit c83ed4c9dbb35 ("ubifs: Abort readdir upon error") broke overlayfs support because the fix exposed an internal error code to VFS. Reported-by: Peter Rosin Tested-by: Peter Rosin Reported-by: Ralph Sennhauser Tested-by: Ralph Sennhauser Fixes: c83ed4c9dbb35 ("ubifs: Abort readdir upon error") Cc: stable@vger.kernel.org Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index bd4a5e8ce4410..ca16c5d7bab17 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -543,6 +543,14 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) if (err != -ENOENT) ubifs_err(c, "cannot find next direntry, error %d", err); + else + /* + * -ENOENT is a non-fatal error in this context, the TNC uses + * it to indicate that the cursor moved past the current directory + * and readdir() has to stop. + */ + err = 0; + /* 2 is a special value indicating that there are no more direntries */ ctx->pos = 2; -- GitLab From 711c1f2671174c918045e2cb20aece976ac516cd Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 13 Oct 2016 15:53:02 -0700 Subject: [PATCH 1108/1167] ARCv2: boot log: print IOC exists as well as enabled status Previously we would not print the case when IOC existed but was not enabled. And while at it, reduce one line off boot printing by consolidating the Peripheral address space and IO-Coherency which in a way applies to them Signed-off-by: Vineet Gupta --- arch/arc/include/asm/setup.h | 1 + arch/arc/kernel/setup.c | 4 +--- arch/arc/mm/cache.c | 9 +++------ 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/arc/include/asm/setup.h b/arch/arc/include/asm/setup.h index 48b37c693db39..bdc43df922c9d 100644 --- a/arch/arc/include/asm/setup.h +++ b/arch/arc/include/asm/setup.h @@ -43,5 +43,6 @@ void __init setup_arch_memory(void); #define IS_USED_RUN(v) ((v) ? "" : "(not used) ") #define IS_USED_CFG(cfg) IS_USED_RUN(IS_ENABLED(cfg)) #define IS_AVAIL2(v, s, cfg) IS_AVAIL1(v, s), IS_AVAIL1(v, IS_USED_CFG(cfg)) +#define IS_AVAIL3(v, v2, s) IS_AVAIL1(v, s), IS_AVAIL1(v, IS_DISABLED_RUN(v2)) #endif /* __ASMARC_SETUP_H */ diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 75e5409721353..a77efa173df01 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -272,9 +272,7 @@ static char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len) FIX_PTR(cpu); - n += scnprintf(buf + n, len - n, - "Vector Table\t: %#x\nPeripherals\t: %#lx:%#lx\n", - cpu->vec_base, perip_base, perip_end); + n += scnprintf(buf + n, len - n, "Vector Table\t: %#x\n", cpu->vec_base); if (cpu->extn.fpu_sp || cpu->extn.fpu_dp) n += scnprintf(buf + n, len - n, "FPU\t\t: %s%s\n", diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c index 518ff76771f36..2b96cfc3be751 100644 --- a/arch/arc/mm/cache.c +++ b/arch/arc/mm/cache.c @@ -53,18 +53,15 @@ char *arc_cache_mumbojumbo(int c, char *buf, int len) PR_CACHE(&cpuinfo_arc700[c].icache, CONFIG_ARC_HAS_ICACHE, "I-Cache"); PR_CACHE(&cpuinfo_arc700[c].dcache, CONFIG_ARC_HAS_DCACHE, "D-Cache"); - if (!is_isa_arcv2()) - return buf; - p = &cpuinfo_arc700[c].slc; if (p->ver) n += scnprintf(buf + n, len - n, "SLC\t\t: %uK, %uB Line%s\n", p->sz_k, p->line_len, IS_USED_RUN(slc_enable)); - if (ioc_exists) - n += scnprintf(buf + n, len - n, "IOC\t\t:%s\n", - IS_DISABLED_RUN(ioc_enable)); + n += scnprintf(buf + n, len - n, "Peripherals\t: %#lx%s%s\n", + perip_base, + IS_AVAIL3(ioc_exists, ioc_enable, ", IO-Coherency ")); return buf; } -- GitLab From 73e284d2572581d848267c74552215f95f0f0996 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 20 Oct 2016 17:49:15 -0700 Subject: [PATCH 1109/1167] ARC: boot log: refactor printing abt features not captured in BCRs On older arc700 cores, some of the features configured were not present in Build config registers. To print about them at boot, we just use the Kconfig option i.e. whether linux is built to use them or not. So yes this seems bogus, but what else can be done. Moreover if linux is booting with these enabled, then the Kconfig info is a good indicator anyways. Over time these "hacks" accumulated in read_arc_build_cfg_regs() as well as arc_cpu_mumbojumbo(). so refactor and move all of those in a single place: read_arc_build_cfg_regs(). This causes some code redcution too: | bloat-o-meter2 arch/arc/kernel/setup.o.0 arch/arc/kernel/setup.o.1 | add/remove: 0/0 grow/shrink: 2/1 up/down: 64/-132 (-68) | function old new delta | setup_processor 610 670 +60 | cpuinfo_arc700 76 80 +4 | arc_cpu_mumbojumbo 752 620 -132 Signed-off-by: Vineet Gupta --- arch/arc/include/asm/arcregs.h | 1 + arch/arc/kernel/setup.c | 87 ++++++++++++++++------------------ 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index db25c65155cb8..819b44c1a719b 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -349,6 +349,7 @@ struct cpuinfo_arc { struct cpuinfo_arc_bpu bpu; struct bcr_identity core; struct bcr_isa isa; + const char *details; unsigned int vec_base; struct cpuinfo_arc_ccm iccm, dccm; struct { diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index a77efa173df01..0170d94f38602 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -40,6 +40,20 @@ struct task_struct *_current_task[NR_CPUS]; /* For stack switching */ struct cpuinfo_arc cpuinfo_arc700[NR_CPUS]; +static const struct cpuinfo_data arc_cpu_tbl[] = { +#ifdef CONFIG_ISA_ARCOMPACT + { {0x20, "ARC 600" }, 0x2F}, + { {0x30, "ARC 700" }, 0x33}, + { {0x34, "ARC 700 R4.10"}, 0x34}, + { {0x35, "ARC 700 R4.11"}, 0x35}, +#else + { {0x50, "ARC HS38 R2.0"}, 0x51}, + { {0x52, "ARC HS38 R2.1"}, 0x52}, + { {0x53, "ARC HS38 R3.0"}, 0x53}, +#endif + { {0x00, NULL } } +}; + static void read_decode_ccm_bcr(struct cpuinfo_arc *cpu) { if (is_isa_arcompact()) { @@ -92,11 +106,24 @@ static void read_arc_build_cfg_regs(void) struct bcr_timer timer; struct bcr_generic bcr; struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()]; + const struct cpuinfo_data *tbl; + FIX_PTR(cpu); READ_BCR(AUX_IDENTITY, cpu->core); READ_BCR(ARC_REG_ISA_CFG_BCR, cpu->isa); + for (tbl = &arc_cpu_tbl[0]; tbl->info.id != 0; tbl++) { + if ((cpu->core.family >= tbl->info.id) && + (cpu->core.family <= tbl->up_range)) { + cpu->details = tbl->info.str; + break; + } + } + + if (tbl->info.id == 0) + cpu->details = "UNKNOWN"; + READ_BCR(ARC_REG_TIMERS_BCR, timer); cpu->extn.timer0 = timer.t0; cpu->extn.timer1 = timer.t1; @@ -160,64 +187,34 @@ static void read_arc_build_cfg_regs(void) cpu->extn.rtt = bcr.ver ? 1 : 0; cpu->extn.debug = cpu->extn.ap | cpu->extn.smart | cpu->extn.rtt; -} -static const struct cpuinfo_data arc_cpu_tbl[] = { -#ifdef CONFIG_ISA_ARCOMPACT - { {0x20, "ARC 600" }, 0x2F}, - { {0x30, "ARC 700" }, 0x33}, - { {0x34, "ARC 700 R4.10"}, 0x34}, - { {0x35, "ARC 700 R4.11"}, 0x35}, -#else - { {0x50, "ARC HS38 R2.0"}, 0x51}, - { {0x52, "ARC HS38 R2.1"}, 0x52}, - { {0x53, "ARC HS38 R3.0"}, 0x53}, -#endif - { {0x00, NULL } } -}; + /* some hacks for lack of feature BCR info in old ARC700 cores */ + if (is_isa_arcompact()) { + if (!cpu->isa.ver) /* ISA BCR absent, use Kconfig info */ + cpu->isa.atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC); + else + cpu->isa.atomic = cpu->isa.atomic1; + cpu->isa.be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN); + } +} static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) { struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id]; struct bcr_identity *core = &cpu->core; - const struct cpuinfo_data *tbl; - char *isa_nm; - int i, be, atomic; - int n = 0; + int i, n = 0; FIX_PTR(cpu); - if (is_isa_arcompact()) { - isa_nm = "ARCompact"; - be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN); - - atomic = cpu->isa.atomic1; - if (!cpu->isa.ver) /* ISA BCR absent, use Kconfig info */ - atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC); - } else { - isa_nm = "ARCv2"; - be = cpu->isa.be; - atomic = cpu->isa.atomic; - } - n += scnprintf(buf + n, len - n, "\nIDENTITY\t: ARCVER [%#02x] ARCNUM [%#02x] CHIPID [%#4x]\n", core->family, core->cpu_id, core->chip_id); - for (tbl = &arc_cpu_tbl[0]; tbl->info.id != 0; tbl++) { - if ((core->family >= tbl->info.id) && - (core->family <= tbl->up_range)) { - n += scnprintf(buf + n, len - n, - "processor [%d]\t: %s (%s ISA) %s\n", - cpu_id, tbl->info.str, isa_nm, - IS_AVAIL1(be, "[Big-Endian]")); - break; - } - } - - if (tbl->info.id == 0) - n += scnprintf(buf + n, len - n, "UNKNOWN ARC Processor\n"); + n += scnprintf(buf + n, len - n, "processor [%d]\t: %s (%s ISA) %s\n", + cpu_id, cpu->details, + is_isa_arcompact() ? "ARCompact" : "ARCv2", + IS_AVAIL1(cpu->isa.be, "[Big-Endian]")); n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ", IS_AVAIL1(cpu->extn.timer0, "Timer0 "), @@ -226,7 +223,7 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) CONFIG_ARC_HAS_RTC)); n += i = scnprintf(buf + n, len - n, "%s%s%s%s%s", - IS_AVAIL2(atomic, "atomic ", CONFIG_ARC_HAS_LLSC), + IS_AVAIL2(cpu->isa.atomic, "atomic ", CONFIG_ARC_HAS_LLSC), IS_AVAIL2(cpu->isa.ldd, "ll64 ", CONFIG_ARC_HAS_LL64), IS_AVAIL1(cpu->isa.unalign, "unalign (not used)")); -- GitLab From a024fd9bc4d0b102b8aa66b8ecba678d2d32fdcf Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 20 Oct 2016 18:08:10 -0700 Subject: [PATCH 1110/1167] ARC: boot log: don't assume SWAPE instruction support This came to light when helping a customer with oldish ARC750 core who were getting instruction errors because of lack of SWAPE but boot log was incorrectly printing it as being present Signed-off-by: Vineet Gupta --- arch/arc/include/asm/arcregs.h | 2 +- arch/arc/kernel/setup.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 819b44c1a719b..b8d29b136b963 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -353,7 +353,7 @@ struct cpuinfo_arc { unsigned int vec_base; struct cpuinfo_arc_ccm iccm, dccm; struct { - unsigned int swap:1, norm:1, minmax:1, barrel:1, crc:1, pad1:3, + unsigned int swap:1, norm:1, minmax:1, barrel:1, crc:1, swape:1, pad1:2, fpu_sp:1, fpu_dp:1, pad2:6, debug:1, ap:1, smart:1, rtt:1, pad3:4, timer0:1, timer1:1, rtc:1, gfrc:1, pad4:4; diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 0170d94f38602..156981aecd744 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -138,6 +138,9 @@ static void read_arc_build_cfg_regs(void) cpu->extn.swap = read_aux_reg(ARC_REG_SWAP_BCR) ? 1 : 0; /* 1,3 */ cpu->extn.crc = read_aux_reg(ARC_REG_CRC_BCR) ? 1 : 0; cpu->extn.minmax = read_aux_reg(ARC_REG_MIXMAX_BCR) > 1 ? 1 : 0; /* 2 */ + cpu->extn.swape = (cpu->core.family >= 0x34) ? 1 : + IS_ENABLED(CONFIG_ARC_HAS_SWAPE); + READ_BCR(ARC_REG_XY_MEM_BCR, cpu->extn_xymem); /* Read CCM BCRs for boot reporting even if not enabled in Kconfig */ @@ -250,7 +253,7 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) IS_AVAIL1(cpu->extn.swap, "swap "), IS_AVAIL1(cpu->extn.minmax, "minmax "), IS_AVAIL1(cpu->extn.crc, "crc "), - IS_AVAIL2(1, "swape", CONFIG_ARC_HAS_SWAPE)); + IS_AVAIL2(cpu->extn.swape, "swape", CONFIG_ARC_HAS_SWAPE)); if (cpu->bpu.ver) n += scnprintf(buf + n, len - n, -- GitLab From d7c46114e356fe41b7291ebff70d7ca09c0f0ac9 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 25 Oct 2016 13:45:11 -0700 Subject: [PATCH 1111/1167] ARC: boot log: remove awkward space comma from MMU line Signed-off-by: Vineet Gupta --- arch/arc/mm/tlb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c index ec868a9081a11..bdb295e09160b 100644 --- a/arch/arc/mm/tlb.c +++ b/arch/arc/mm/tlb.c @@ -793,16 +793,16 @@ char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len) char super_pg[64] = ""; if (p_mmu->s_pg_sz_m) - scnprintf(super_pg, 64, "%dM Super Page%s, ", + scnprintf(super_pg, 64, "%dM Super Page %s", p_mmu->s_pg_sz_m, IS_USED_CFG(CONFIG_TRANSPARENT_HUGEPAGE)); n += scnprintf(buf + n, len - n, - "MMU [v%x]\t: %dk PAGE, %sJTLB %d (%dx%d), uDTLB %d, uITLB %d %s%s\n", + "MMU [v%x]\t: %dk PAGE, %sJTLB %d (%dx%d), uDTLB %d, uITLB %d%s%s\n", p_mmu->ver, p_mmu->pg_sz_k, super_pg, p_mmu->sets * p_mmu->ways, p_mmu->sets, p_mmu->ways, p_mmu->u_dtlb, p_mmu->u_itlb, - IS_AVAIL2(p_mmu->pae, "PAE40 ", CONFIG_ARC_HAS_PAE40)); + IS_AVAIL2(p_mmu->pae, ", PAE40 ", CONFIG_ARC_HAS_PAE40)); return buf; } -- GitLab From d975cbc8acb6f4a52ac46a57b13bd6a7f871b5e9 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 27 Oct 2016 14:33:19 -0700 Subject: [PATCH 1112/1167] ARC: boot log: refactor cpu name/release printing The motivation is to identify ARC750 vs. ARC770 (we currently print generic "ARC700"). A given ARC700 release could be 750 or 770, with same ARCNUM (or family identifier which is unfortunate). The existing arc_cpu_tbl[] kept a single concatenated string for core name and release which thus doesn't work for 750 vs. 770 identification. So split this into 2 tables, one with core names and other with release. And while we are at it, get rid of the range checking for family numbers. We just document the known to exist cores running Linux and ditch others. With this in place, we add detection of ARC750 which is - cores 0x33 and before - cores 0x34 and later with MMUv2 Signed-off-by: Vineet Gupta --- arch/arc/include/asm/arcregs.h | 2 +- arch/arc/include/asm/setup.h | 5 ---- arch/arc/kernel/setup.c | 51 ++++++++++++++++++++++------------ 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index b8d29b136b963..7f3f9f63708cf 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -349,7 +349,7 @@ struct cpuinfo_arc { struct cpuinfo_arc_bpu bpu; struct bcr_identity core; struct bcr_isa isa; - const char *details; + const char *details, *name; unsigned int vec_base; struct cpuinfo_arc_ccm iccm, dccm; struct { diff --git a/arch/arc/include/asm/setup.h b/arch/arc/include/asm/setup.h index bdc43df922c9d..cb954cdab0708 100644 --- a/arch/arc/include/asm/setup.h +++ b/arch/arc/include/asm/setup.h @@ -27,11 +27,6 @@ struct id_to_str { const char *str; }; -struct cpuinfo_data { - struct id_to_str info; - int up_range; -}; - extern int root_mountflags, end_mem; void setup_processor(void); diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 156981aecd744..0385df77a6973 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -40,18 +40,27 @@ struct task_struct *_current_task[NR_CPUS]; /* For stack switching */ struct cpuinfo_arc cpuinfo_arc700[NR_CPUS]; -static const struct cpuinfo_data arc_cpu_tbl[] = { +static const struct id_to_str arc_cpu_rel[] = { #ifdef CONFIG_ISA_ARCOMPACT - { {0x20, "ARC 600" }, 0x2F}, - { {0x30, "ARC 700" }, 0x33}, - { {0x34, "ARC 700 R4.10"}, 0x34}, - { {0x35, "ARC 700 R4.11"}, 0x35}, + { 0x34, "R4.10"}, + { 0x35, "R4.11"}, #else - { {0x50, "ARC HS38 R2.0"}, 0x51}, - { {0x52, "ARC HS38 R2.1"}, 0x52}, - { {0x53, "ARC HS38 R3.0"}, 0x53}, + { 0x51, "R2.0" }, + { 0x52, "R2.1" }, + { 0x53, "R3.0" }, #endif - { {0x00, NULL } } + { 0x00, NULL } +}; + +static const struct id_to_str arc_cpu_nm[] = { +#ifdef CONFIG_ISA_ARCOMPACT + { 0x20, "ARC 600" }, + { 0x30, "ARC 770" }, /* 750 identified seperately */ +#else + { 0x40, "ARC EM" }, + { 0x50, "ARC HS38" }, +#endif + { 0x00, "Unknown" } }; static void read_decode_ccm_bcr(struct cpuinfo_arc *cpu) @@ -106,23 +115,25 @@ static void read_arc_build_cfg_regs(void) struct bcr_timer timer; struct bcr_generic bcr; struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()]; - const struct cpuinfo_data *tbl; + const struct id_to_str *tbl; FIX_PTR(cpu); READ_BCR(AUX_IDENTITY, cpu->core); READ_BCR(ARC_REG_ISA_CFG_BCR, cpu->isa); - for (tbl = &arc_cpu_tbl[0]; tbl->info.id != 0; tbl++) { - if ((cpu->core.family >= tbl->info.id) && - (cpu->core.family <= tbl->up_range)) { - cpu->details = tbl->info.str; + for (tbl = &arc_cpu_rel[0]; tbl->id != 0; tbl++) { + if (cpu->core.family == tbl->id) { + cpu->details = tbl->str; break; } } - if (tbl->info.id == 0) - cpu->details = "UNKNOWN"; + for (tbl = &arc_cpu_nm[0]; tbl->id != 0; tbl++) { + if ((cpu->core.family & 0xF0) == tbl->id) + break; + } + cpu->name = tbl->str; READ_BCR(ARC_REG_TIMERS_BCR, timer); cpu->extn.timer0 = timer.t0; @@ -199,6 +210,10 @@ static void read_arc_build_cfg_regs(void) cpu->isa.atomic = cpu->isa.atomic1; cpu->isa.be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN); + + /* there's no direct way to distinguish 750 vs. 770 */ + if (unlikely(cpu->core.family < 0x34 || cpu->mmu.ver < 3)) + cpu->name = "ARC750"; } } @@ -214,8 +229,8 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) "\nIDENTITY\t: ARCVER [%#02x] ARCNUM [%#02x] CHIPID [%#4x]\n", core->family, core->cpu_id, core->chip_id); - n += scnprintf(buf + n, len - n, "processor [%d]\t: %s (%s ISA) %s\n", - cpu_id, cpu->details, + n += scnprintf(buf + n, len - n, "processor [%d]\t: %s %s (%s ISA) %s\n", + cpu_id, cpu->name, cpu->details, is_isa_arcompact() ? "ARCompact" : "ARCv2", IS_AVAIL1(cpu->isa.be, "[Big-Endian]")); -- GitLab From c3005475889c7c730638f95d13be3360f0b33e98 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Fri, 21 Oct 2016 16:04:37 -0700 Subject: [PATCH 1113/1167] ARC: build: retire old toggles These are really ancient toggles and tools no longer require them to be passed. This paves way for deprecating them in long run. Signed-off-by: Vineet Gupta --- arch/arc/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arc/Makefile b/arch/arc/Makefile index aa82d13d42138..864adad522803 100644 --- a/arch/arc/Makefile +++ b/arch/arc/Makefile @@ -50,9 +50,6 @@ atleast_gcc44 := $(call cc-ifversion, -ge, 0404, y) cflags-$(atleast_gcc44) += -fsection-anchors -cflags-$(CONFIG_ARC_HAS_LLSC) += -mlock -cflags-$(CONFIG_ARC_HAS_SWAPE) += -mswape - ifdef CONFIG_ISA_ARCV2 ifndef CONFIG_ARC_HAS_LL64 -- GitLab From f644e3688855902ad11549029098a62cbbc8f558 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 25 Oct 2016 08:58:17 -0700 Subject: [PATCH 1114/1167] ARC: mm: retire ARC_DBG_TLB_MISS_COUNT... ... given that we have perf counters abel to do the same thing non intrusively Signed-off-by: Vineet Gupta --- arch/arc/Kconfig | 8 --- arch/arc/kernel/troubleshoot.c | 110 --------------------------------- arch/arc/mm/tlbex.S | 21 ------- 3 files changed, 139 deletions(-) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index ac0b309aced59..bd204bfa29edd 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -540,14 +540,6 @@ config ARC_DBG_TLB_PARANOIA bool "Paranoia Checks in Low Level TLB Handlers" default n -config ARC_DBG_TLB_MISS_COUNT - bool "Profile TLB Misses" - default n - select DEBUG_FS - help - Counts number of I and D TLB Misses and exports them via Debugfs - The counters can be cleared via Debugfs as well - endif config ARC_UBOOT_SUPPORT diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c index 934150e7ac489..82f9bc819f4a2 100644 --- a/arch/arc/kernel/troubleshoot.c +++ b/arch/arc/kernel/troubleshoot.c @@ -237,113 +237,3 @@ void show_kernel_fault_diag(const char *str, struct pt_regs *regs, if (!user_mode(regs)) show_stacktrace(current, regs); } - -#ifdef CONFIG_DEBUG_FS - -#include -#include -#include -#include -#include -#include -#include - -static struct dentry *test_dentry; -static struct dentry *test_dir; -static struct dentry *test_u32_dentry; - -static u32 clr_on_read = 1; - -#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT -u32 numitlb, numdtlb, num_pte_not_present; - -static int fill_display_data(char *kbuf) -{ - size_t num = 0; - num += sprintf(kbuf + num, "I-TLB Miss %x\n", numitlb); - num += sprintf(kbuf + num, "D-TLB Miss %x\n", numdtlb); - num += sprintf(kbuf + num, "PTE not present %x\n", num_pte_not_present); - - if (clr_on_read) - numitlb = numdtlb = num_pte_not_present = 0; - - return num; -} - -static int tlb_stats_open(struct inode *inode, struct file *file) -{ - file->private_data = (void *)__get_free_page(GFP_KERNEL); - return 0; -} - -/* called on user read(): display the counters */ -static ssize_t tlb_stats_output(struct file *file, /* file descriptor */ - char __user *user_buf, /* user buffer */ - size_t len, /* length of buffer */ - loff_t *offset) /* offset in the file */ -{ - size_t num; - char *kbuf = (char *)file->private_data; - - /* All of the data can he shoved in one iteration */ - if (*offset != 0) - return 0; - - num = fill_display_data(kbuf); - - /* simple_read_from_buffer() is helper for copy to user space - It copies up to @2 (num) bytes from kernel buffer @4 (kbuf) at offset - @3 (offset) into the user space address starting at @1 (user_buf). - @5 (len) is max size of user buffer - */ - return simple_read_from_buffer(user_buf, num, offset, kbuf, len); -} - -/* called on user write : clears the counters */ -static ssize_t tlb_stats_clear(struct file *file, const char __user *user_buf, - size_t length, loff_t *offset) -{ - numitlb = numdtlb = num_pte_not_present = 0; - return length; -} - -static int tlb_stats_close(struct inode *inode, struct file *file) -{ - free_page((unsigned long)(file->private_data)); - return 0; -} - -static const struct file_operations tlb_stats_file_ops = { - .read = tlb_stats_output, - .write = tlb_stats_clear, - .open = tlb_stats_open, - .release = tlb_stats_close -}; -#endif - -static int __init arc_debugfs_init(void) -{ - test_dir = debugfs_create_dir("arc", NULL); - -#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT - test_dentry = debugfs_create_file("tlb_stats", 0444, test_dir, NULL, - &tlb_stats_file_ops); -#endif - - test_u32_dentry = - debugfs_create_u32("clr_on_read", 0444, test_dir, &clr_on_read); - - return 0; -} - -module_init(arc_debugfs_init); - -static void __exit arc_debugfs_exit(void) -{ - debugfs_remove(test_u32_dentry); - debugfs_remove(test_dentry); - debugfs_remove(test_dir); -} -module_exit(arc_debugfs_exit); - -#endif diff --git a/arch/arc/mm/tlbex.S b/arch/arc/mm/tlbex.S index f1967eeb32e75..b30e4e36bb00d 100644 --- a/arch/arc/mm/tlbex.S +++ b/arch/arc/mm/tlbex.S @@ -237,15 +237,6 @@ ex_saved_reg1: 2: -#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT - and.f 0, r0, _PAGE_PRESENT - bz 1f - ld r3, [num_pte_not_present] - add r3, r3, 1 - st r3, [num_pte_not_present] -1: -#endif - .endm ;----------------------------------------------------------------- @@ -309,12 +300,6 @@ ENTRY(EV_TLBMissI) TLBMISS_FREEUP_REGS -#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT - ld r0, [@numitlb] - add r0, r0, 1 - st r0, [@numitlb] -#endif - ;---------------------------------------------------------------- ; Get the PTE corresponding to V-addr accessed, r2 is setup with EFA LOAD_FAULT_PTE @@ -349,12 +334,6 @@ ENTRY(EV_TLBMissD) TLBMISS_FREEUP_REGS -#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT - ld r0, [@numdtlb] - add r0, r0, 1 - st r0, [@numdtlb] -#endif - ;---------------------------------------------------------------- ; Get the PTE corresponding to V-addr accessed ; If PTE exists, it will setup, r0 = PTE, r1 = Ptr to PTE, r2 = EFA -- GitLab From d65283f7b695b5d04ca1ab58b6bb41f443b96286 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 25 Oct 2016 10:43:20 -0700 Subject: [PATCH 1115/1167] ARC: module: elide loop to save reference to .eh_frame The loop was really needed in .debug_frame regime where wanted make it as SH_ALLOC so that apply_relocate_add() would process it. That's not needed for .eh_frame, so we check this in apply_relocate_add() which gets called for each section. Note that we need to save reference to "section name strings" section in module_frob_arch_sections() since apply_relocate_add() doesn't get that Signed-off-by: Vineet Gupta --- arch/arc/include/asm/module.h | 1 + arch/arc/kernel/module.c | 18 ++++++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/arc/include/asm/module.h b/arch/arc/include/asm/module.h index 518222bb3f8ef..6e91d8b339c36 100644 --- a/arch/arc/include/asm/module.h +++ b/arch/arc/include/asm/module.h @@ -18,6 +18,7 @@ struct mod_arch_specific { void *unw_info; int unw_sec_idx; + const char *secstr; }; #endif diff --git a/arch/arc/kernel/module.c b/arch/arc/kernel/module.c index 9a2849756022c..24bd2ffb90b7f 100644 --- a/arch/arc/kernel/module.c +++ b/arch/arc/kernel/module.c @@ -30,17 +30,9 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, char *secstr, struct module *mod) { #ifdef CONFIG_ARC_DW2_UNWIND - int i; - mod->arch.unw_sec_idx = 0; mod->arch.unw_info = NULL; - - for (i = 1; i < hdr->e_shnum; i++) { - if (strcmp(secstr+sechdrs[i].sh_name, ".eh_frame") == 0) { - mod->arch.unw_sec_idx = i; - break; - } - } + mod->arch.secstr = secstr; #endif return 0; } @@ -66,8 +58,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, Elf32_Addr location; Elf32_Addr sec_to_patch; int relo_type; + unsigned int tgtsec; - sec_to_patch = sechdrs[sechdrs[relsec].sh_info].sh_addr; + tgtsec = sechdrs[relsec].sh_info; + sec_to_patch = sechdrs[tgtsec].sh_addr; sym_sec = (Elf32_Sym *) sechdrs[symindex].sh_addr; n = sechdrs[relsec].sh_size / sizeof(*rel_entry); @@ -111,6 +105,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, goto relo_err; } + + if (strcmp(module->arch.secstr+sechdrs[tgtsec].sh_name, ".eh_frame") == 0) + module->arch.unw_sec_idx = tgtsec; + return 0; relo_err: -- GitLab From b75dcd9c7d352c7d9ea9010e95c708595094896a Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 25 Oct 2016 11:23:19 -0700 Subject: [PATCH 1116/1167] ARC: module: print pretty section names Now that we have referece to section name string table in apply_relocate_add(), use it to - print the name of section being relocated - print symbol with NULL name (since it refers to a section) before | Section to fixup 7000a060 | ========================================================= | rela->r_off | rela->addend | sym->st_value | ADDR | VALUE | ========================================================= | 1c 0 7000e000 7000a07c 7000e000 [] | 40 0 7000a000 7000a0a0 7000a000 [] after | Section to fixup .eh_frame @7000a060 | ========================================================= | r_off r_add st_value ADDRESS VALUE | ========================================================= | 1c 0 7000e000 7000a07c 7000e000 [.init.text] | 40 0 7000a000 7000a0a0 7000a000 [.exit.text] Signed-off-by: Vineet Gupta --- arch/arc/kernel/module.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/arch/arc/kernel/module.c b/arch/arc/kernel/module.c index 24bd2ffb90b7f..42e964db29677 100644 --- a/arch/arc/kernel/module.c +++ b/arch/arc/kernel/module.c @@ -51,31 +51,33 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, unsigned int relsec, /* sec index for relo sec */ struct module *module) { - int i, n; + int i, n, relo_type; Elf32_Rela *rel_entry = (void *)sechdrs[relsec].sh_addr; Elf32_Sym *sym_entry, *sym_sec; - Elf32_Addr relocation; - Elf32_Addr location; - Elf32_Addr sec_to_patch; - int relo_type; + Elf32_Addr relocation, location, tgt_addr; unsigned int tgtsec; + /* + * @relsec has relocations e.g. .rela.init.text + * @tgtsec is section to patch e.g. .init.text + */ tgtsec = sechdrs[relsec].sh_info; - sec_to_patch = sechdrs[tgtsec].sh_addr; + tgt_addr = sechdrs[tgtsec].sh_addr; sym_sec = (Elf32_Sym *) sechdrs[symindex].sh_addr; n = sechdrs[relsec].sh_size / sizeof(*rel_entry); - pr_debug("\n========== Module Sym reloc ===========================\n"); - pr_debug("Section to fixup %x\n", sec_to_patch); + pr_debug("\nSection to fixup %s @%x\n", + module->arch.secstr + sechdrs[tgtsec].sh_name, tgt_addr); pr_debug("=========================================================\n"); - pr_debug("rela->r_off | rela->addend | sym->st_value | ADDR | VALUE\n"); + pr_debug("r_off\tr_add\tst_value ADDRESS VALUE\n"); pr_debug("=========================================================\n"); /* Loop thru entries in relocation section */ for (i = 0; i < n; i++) { + const char *s; /* This is where to make the change */ - location = sec_to_patch + rel_entry[i].r_offset; + location = tgt_addr + rel_entry[i].r_offset; /* This is the symbol it is referring to. Note that all undefined symbols have been resolved. */ @@ -83,10 +85,15 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, relocation = sym_entry->st_value + rel_entry[i].r_addend; - pr_debug("\t%x\t\t%x\t\t%x %x %x [%s]\n", - rel_entry[i].r_offset, rel_entry[i].r_addend, - sym_entry->st_value, location, relocation, - strtab + sym_entry->st_name); + if (sym_entry->st_name == 0 && ELF_ST_TYPE (sym_entry->st_info) == STT_SECTION) { + s = module->arch.secstr + sechdrs[sym_entry->st_shndx].sh_name; + } else { + s = strtab + sym_entry->st_name; + } + + pr_debug(" %x\t%x\t%x %x %x [%s]\n", + rel_entry[i].r_offset, rel_entry[i].r_addend, + sym_entry->st_value, location, relocation, s); /* This assumes modules are built with -mlong-calls * so any branches/jumps are absolute 32 bit jmps -- GitLab From 2083d36790e328a364896a2833fbedbf6e1d2317 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 25 Oct 2016 11:25:56 +0200 Subject: [PATCH 1117/1167] mlxsw: spectrum_router: Save requested prefix bitlist when creating tree Currently, the prefix bitlist is not saved for LPM trees, causing the compare to always fail which causes the tree to be destroyed and created for every inserted and removed FIB entry. So fix this by saving the bitlist as it should have been done from the very beginning. Fixes: 53342023eed9 ("mlxsw: spectrum_router: Implement LPM trees management") Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index f3d50d369bbe8..4cff4c043d119 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -320,6 +320,8 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp, lpm_tree); if (err) goto err_left_struct_set; + memcpy(&lpm_tree->prefix_usage, prefix_usage, + sizeof(lpm_tree->prefix_usage)); return lpm_tree; err_left_struct_set: -- GitLab From 8b99becdc89ee7635137725e9fa76f304bb168f5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 25 Oct 2016 11:25:57 +0200 Subject: [PATCH 1118/1167] mlxsw: spectrum_router: Compare only trees which are in use during tree get Only trees which are in use should be compared to requested prefix usage. Fixes: 53342023eed9 ("mlxsw: spectrum_router: Implement LPM trees management") Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 4cff4c043d119..4573da2c55602 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -345,7 +345,8 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp, for (i = 0; i < MLXSW_SP_LPM_TREE_COUNT; i++) { lpm_tree = &mlxsw_sp->router.lpm_trees[i]; - if (lpm_tree->proto == proto && + if (lpm_tree->ref_count != 0 && + lpm_tree->proto == proto && mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage, prefix_usage)) goto inc_ref_count; -- GitLab From 25ccd2429fd0af5b9c2c136c8c593491aeabf162 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 26 Oct 2016 15:40:12 +0800 Subject: [PATCH 1119/1167] ACPICA: Dispatcher: Fix order issue of method termination The last step of the method termination should be the end of the method serialization. Otherwise, the steps happening after it will face the race issues that cannot be protected by the method serialization mechanism. This patch fixes this issue by moving the per-method-object deletion code prior than the end of the method serialization. Otherwise, the possible race issues may result in AE_ALREADY_EXISTS error in a parallel environment. Fixes: 74f51b80a0c4 (ACPICA: Namespace: Fix dynamic table loading issues) Reported-and-tested-by: Imre Deak Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsmethod.c | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 32e9ddc0cf2bb..c4028a8dacd59 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -730,26 +730,6 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, acpi_ds_method_data_delete_all(walk_state); - /* - * If method is serialized, release the mutex and restore the - * current sync level for this thread - */ - if (method_desc->method.mutex) { - - /* Acquisition Depth handles recursive calls */ - - method_desc->method.mutex->mutex.acquisition_depth--; - if (!method_desc->method.mutex->mutex.acquisition_depth) { - walk_state->thread->current_sync_level = - method_desc->method.mutex->mutex. - original_sync_level; - - acpi_os_release_mutex(method_desc->method. - mutex->mutex.os_mutex); - method_desc->method.mutex->mutex.thread_id = 0; - } - } - /* * Delete any namespace objects created anywhere within the * namespace by the execution of this method. Unless: @@ -786,6 +766,26 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, ~ACPI_METHOD_MODIFIED_NAMESPACE; } } + + /* + * If method is serialized, release the mutex and restore the + * current sync level for this thread + */ + if (method_desc->method.mutex) { + + /* Acquisition Depth handles recursive calls */ + + method_desc->method.mutex->mutex.acquisition_depth--; + if (!method_desc->method.mutex->mutex.acquisition_depth) { + walk_state->thread->current_sync_level = + method_desc->method.mutex->mutex. + original_sync_level; + + acpi_os_release_mutex(method_desc->method. + mutex->mutex.os_mutex); + method_desc->method.mutex->mutex.thread_id = 0; + } + } } /* Decrement the thread count on the method */ -- GitLab From 8121aa26e32012ca89afafa5e503b879950ac0fe Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 26 Oct 2016 15:40:20 +0800 Subject: [PATCH 1120/1167] ACPICA: Dispatcher: Fix an unbalanced lock exit path in acpi_ds_auto_serialize_method() There is a lock unbalanced exit path in acpi_ds_initialize_method(), this patch corrects it. Fixes: 441ad11d078f (ACPICA: Dispatcher: Fix a mutex issue for method auto serialization) Tested-by: Imre Deak Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsmethod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index c4028a8dacd59..5997e592e5a61 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -128,7 +128,7 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); acpi_ps_free_op(op); - return_ACPI_STATUS(status); + goto unlock; } walk_state->descending_callback = acpi_ds_detect_named_opcodes; -- GitLab From 8633db6b027952449e155a316f4ae3a530bbe18f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 26 Oct 2016 15:42:01 +0800 Subject: [PATCH 1121/1167] ACPICA: Dispatcher: Fix interpreter locking around acpi_ev_initialize_region() In the code path of acpi_ev_initialize_region(), there is namespace modification code unlocked. This patch tunes the code to make sure such modification are always locked. Fixes: 74f51b80a0c4 (ACPICA: Namespace: Fix dynamic table loading issues) Tested-by: Imre Deak Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsinit.c | 11 +++-------- drivers/acpi/acpica/dsmethod.c | 12 +++--------- drivers/acpi/acpica/dswload2.c | 2 -- drivers/acpi/acpica/evrgnini.c | 3 +++ drivers/acpi/acpica/nsload.c | 2 ++ 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index f1e6dcc7a8271..54d48b90de2cd 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -46,6 +46,7 @@ #include "acdispat.h" #include "acnamesp.h" #include "actables.h" +#include "acinterp.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsinit") @@ -214,23 +215,17 @@ acpi_ds_initialize_objects(u32 table_index, /* Walk entire namespace from the supplied root */ - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - /* * We don't use acpi_walk_namespace since we do not want to acquire * the namespace reader lock. */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, acpi_ds_init_one_object, - NULL, &info, NULL); + 0, acpi_ds_init_one_object, NULL, &info, + NULL); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); status = acpi_get_table_by_index(table_index, &table); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 5997e592e5a61..2b3210f42a469 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -99,14 +99,11 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, "Method auto-serialization parse [%4.4s] %p\n", acpi_ut_get_node_name(node), node)); - acpi_ex_enter_interpreter(); - /* Create/Init a root op for the method parse tree */ op = acpi_ps_alloc_op(AML_METHOD_OP, obj_desc->method.aml_start); if (!op) { - status = AE_NO_MEMORY; - goto unlock; + return_ACPI_STATUS(AE_NO_MEMORY); } acpi_ps_set_name(op, node->name.integer); @@ -118,8 +115,7 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL); if (!walk_state) { acpi_ps_free_op(op); - status = AE_NO_MEMORY; - goto unlock; + return_ACPI_STATUS(AE_NO_MEMORY); } status = acpi_ds_init_aml_walk(walk_state, op, node, @@ -128,7 +124,7 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); acpi_ps_free_op(op); - goto unlock; + return_ACPI_STATUS(status); } walk_state->descending_callback = acpi_ds_detect_named_opcodes; @@ -138,8 +134,6 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, status = acpi_ps_parse_aml(walk_state); acpi_ps_delete_parse_tree(op); -unlock: - acpi_ex_exit_interpreter(); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 028b22a3154eb..e36218206bb01 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -607,11 +607,9 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) } } - acpi_ex_exit_interpreter(); status = acpi_ev_initialize_region (acpi_ns_get_attached_object(node), FALSE); - acpi_ex_enter_interpreter(); if (ACPI_FAILURE(status)) { /* diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 3843f1fc5dbbd..75ddd160a716f 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -45,6 +45,7 @@ #include "accommon.h" #include "acevents.h" #include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evrgnini") @@ -597,9 +598,11 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, } } + acpi_ex_exit_interpreter(); status = acpi_ev_execute_reg_method(region_obj, ACPI_REG_CONNECT); + acpi_ex_enter_interpreter(); if (acpi_ns_locked) { status = diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 334d3c5ba617d..d1f20143bb113 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -137,7 +137,9 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Begin Table Object Initialization\n")); + acpi_ex_enter_interpreter(); status = acpi_ds_initialize_objects(table_index, node); + acpi_ex_exit_interpreter(); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Completed Table Object Initialization\n")); -- GitLab From 1e90a13d0c3dc94512af1ccb2b6563e8297838fa Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 29 Oct 2016 13:42:42 +0200 Subject: [PATCH 1122/1167] x86/smpboot: Init apic mapping before usage The recent changes, which forced the registration of the boot cpu on UP systems, which do not have ACPI tables, have been fixed for systems w/o local APIC, but left a wreckage for systems which have neither ACPI nor mptables, but the CPU has an APIC, e.g. virtualbox. The boot process crashes in prefill_possible_map() as it wants to register the boot cpu, which needs to access the local apic, but the local APIC is not yet mapped. There is no reason why init_apic_mapping() can't be invoked before prefill_possible_map(). So instead of playing another silly early mapping game, as the ACPI/mptables code does, we just move init_apic_mapping() before the call to prefill_possible_map(). In hindsight, I should have noticed that combination earlier. Sorry for the churn (also in stable)! Fixes: ff8560512b8d ("x86/boot/smp: Don't try to poke disabled/non-existent APIC") Reported-and-debugged-by: Michal Necasek Reported-and-tested-by: Wolfgang Bauer Cc: prarit@redhat.com Cc: ville.syrjala@linux.intel.com Cc: michael.thayer@oracle.com Cc: knut.osmundsen@oracle.com Cc: frank.mehnert@oracle.com Cc: Borislav Petkov Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1610282114380.5053@nanos Signed-off-by: Thomas Gleixner --- arch/x86/kernel/setup.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index bbfbca5fea0cd..9c337b0e8ba7c 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1221,11 +1221,16 @@ void __init setup_arch(char **cmdline_p) */ get_smp_config(); + /* + * Systems w/o ACPI and mptables might not have it mapped the local + * APIC yet, but prefill_possible_map() might need to access it. + */ + init_apic_mappings(); + prefill_possible_map(); init_cpu_to_node(); - init_apic_mappings(); io_apic_init_mappings(); kvm_guest_init(); -- GitLab From bf911e985d6bbaa328c20c3e05f4eb03de11fdd6 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Tue, 25 Oct 2016 14:27:39 -0200 Subject: [PATCH 1123/1167] sctp: validate chunk len before actually using it Andrey Konovalov reported that KASAN detected that SCTP was using a slab beyond the boundaries. It was caused because when handling out of the blue packets in function sctp_sf_ootb() it was checking the chunk len only after already processing the first chunk, validating only for the 2nd and subsequent ones. The fix is to just move the check upwards so it's also validated for the 1st chunk. Reported-by: Andrey Konovalov Tested-by: Andrey Konovalov Signed-off-by: Marcelo Ricardo Leitner Reviewed-by: Xin Long Acked-by: Neil Horman Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 026e3bca4a94b..8ec20a64a3f80 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3422,6 +3422,12 @@ sctp_disposition_t sctp_sf_ootb(struct net *net, return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); + /* Report violation if chunk len overflows */ + ch_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length)); + if (ch_end > skb_tail_pointer(skb)) + return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, + commands); + /* Now that we know we at least have a chunk header, * do things that are type appropriate. */ @@ -3453,12 +3459,6 @@ sctp_disposition_t sctp_sf_ootb(struct net *net, } } - /* Report violation if chunk len overflows */ - ch_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length)); - if (ch_end > skb_tail_pointer(skb)) - return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, - commands); - ch = (sctp_chunkhdr_t *) ch_end; } while (ch_end < skb_tail_pointer(skb)); -- GitLab From b47bd6ea40636362a8b6605de51207cc387ba0b8 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 25 Oct 2016 18:36:24 +0300 Subject: [PATCH 1124/1167] {net, ib}/mlx5: Make cache line size determination at runtime. ARM 64B cache line systems have L1_CACHE_BYTES set to 128. cache_line_size() will return the correct size. Fixes: cf50b5efa2fe('net/mlx5_core/ib: New device capabilities handling.') Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/main.c | 2 +- drivers/infiniband/hw/mlx5/qp.c | 1 - .../net/ethernet/mellanox/mlx5/core/alloc.c | 31 ++++++++++++++++--- include/linux/mlx5/driver.h | 11 ------- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 22174774dbb8c..63036c7316264 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1019,7 +1019,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, resp.qp_tab_size = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp); if (mlx5_core_is_pf(dev->mdev) && MLX5_CAP_GEN(dev->mdev, bf)) resp.bf_reg_size = 1 << MLX5_CAP_GEN(dev->mdev, log_bf_reg_size); - resp.cache_line_size = L1_CACHE_BYTES; + resp.cache_line_size = cache_line_size(); resp.max_sq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq); resp.max_rq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq); resp.max_send_wqebb = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 41f4c2afbcdd6..7ce97daf26c62 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -52,7 +52,6 @@ enum { enum { MLX5_IB_SQ_STRIDE = 6, - MLX5_IB_CACHE_LINE_SIZE = 64, }; static const u32 mlx5_ib_opcode[] = { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index 6cb38304669f6..2c6e3c7b74179 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -41,6 +41,13 @@ #include "mlx5_core.h" +struct mlx5_db_pgdir { + struct list_head list; + unsigned long *bitmap; + __be32 *db_page; + dma_addr_t db_dma; +}; + /* Handling for queue buffers -- we allocate a bunch of memory and * register it in a memory region at HCA virtual address 0. */ @@ -102,17 +109,28 @@ EXPORT_SYMBOL_GPL(mlx5_buf_free); static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev, int node) { + u32 db_per_page = PAGE_SIZE / cache_line_size(); struct mlx5_db_pgdir *pgdir; pgdir = kzalloc(sizeof(*pgdir), GFP_KERNEL); if (!pgdir) return NULL; - bitmap_fill(pgdir->bitmap, MLX5_DB_PER_PAGE); + pgdir->bitmap = kcalloc(BITS_TO_LONGS(db_per_page), + sizeof(unsigned long), + GFP_KERNEL); + + if (!pgdir->bitmap) { + kfree(pgdir); + return NULL; + } + + bitmap_fill(pgdir->bitmap, db_per_page); pgdir->db_page = mlx5_dma_zalloc_coherent_node(dev, PAGE_SIZE, &pgdir->db_dma, node); if (!pgdir->db_page) { + kfree(pgdir->bitmap); kfree(pgdir); return NULL; } @@ -123,18 +141,19 @@ static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev, static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir, struct mlx5_db *db) { + u32 db_per_page = PAGE_SIZE / cache_line_size(); int offset; int i; - i = find_first_bit(pgdir->bitmap, MLX5_DB_PER_PAGE); - if (i >= MLX5_DB_PER_PAGE) + i = find_first_bit(pgdir->bitmap, db_per_page); + if (i >= db_per_page) return -ENOMEM; __clear_bit(i, pgdir->bitmap); db->u.pgdir = pgdir; db->index = i; - offset = db->index * L1_CACHE_BYTES; + offset = db->index * cache_line_size(); db->db = pgdir->db_page + offset / sizeof(*pgdir->db_page); db->dma = pgdir->db_dma + offset; @@ -181,14 +200,16 @@ EXPORT_SYMBOL_GPL(mlx5_db_alloc); void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db) { + u32 db_per_page = PAGE_SIZE / cache_line_size(); mutex_lock(&dev->priv.pgdir_mutex); __set_bit(db->index, db->u.pgdir->bitmap); - if (bitmap_full(db->u.pgdir->bitmap, MLX5_DB_PER_PAGE)) { + if (bitmap_full(db->u.pgdir->bitmap, db_per_page)) { dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, db->u.pgdir->db_page, db->u.pgdir->db_dma); list_del(&db->u.pgdir->list); + kfree(db->u.pgdir->bitmap); kfree(db->u.pgdir); } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 85c4786427e49..5dbda60a09f4f 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -625,10 +625,6 @@ struct mlx5_db { int index; }; -enum { - MLX5_DB_PER_PAGE = PAGE_SIZE / L1_CACHE_BYTES, -}; - enum { MLX5_COMP_EQ_SIZE = 1024, }; @@ -638,13 +634,6 @@ enum { MLX5_PTYS_EN = 1 << 2, }; -struct mlx5_db_pgdir { - struct list_head list; - DECLARE_BITMAP(bitmap, MLX5_DB_PER_PAGE); - __be32 *db_page; - dma_addr_t db_dma; -}; - typedef void (*mlx5_cmd_cbk_t)(int status, void *context); struct mlx5_cmd_work_ent { -- GitLab From bba1574c2f11d674bf343f3cf307b33d19f73d9d Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 25 Oct 2016 18:36:25 +0300 Subject: [PATCH 1125/1167] net/mlx5: Always Query HCA caps after setting them Always query the HCA caps after setting them to update the capablities data structures. Not doing so results in incorrect capabilities being reported including max_dc, max_qp and several others. Fixes: 59211bd3b632 ("net/mlx5: Split the load/unload flow into hardware and software flows") Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index d9c3c70b29e47..8a63910bfccf8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -844,12 +844,6 @@ static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv) struct pci_dev *pdev = dev->pdev; int err; - err = mlx5_query_hca_caps(dev); - if (err) { - dev_err(&pdev->dev, "query hca failed\n"); - goto out; - } - err = mlx5_query_board_id(dev); if (err) { dev_err(&pdev->dev, "query board id failed\n"); @@ -1023,6 +1017,12 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, mlx5_start_health_poll(dev); + err = mlx5_query_hca_caps(dev); + if (err) { + dev_err(&pdev->dev, "query hca failed\n"); + goto err_stop_poll; + } + if (boot && mlx5_init_once(dev, priv)) { dev_err(&pdev->dev, "sw objs init failed\n"); goto err_stop_poll; -- GitLab From eccec8da3b4e6f403040c7187338a46d2ea27c20 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 25 Oct 2016 18:36:26 +0300 Subject: [PATCH 1126/1167] net/mlx5: Keep autogroups list ordered Finding a new autogroup range is done by going over a group list sorted by each group start index. The search is stopped after finding the first free range. Adding the newly created group to the list is wrongly added to the end of the list regardless of its start index as the parameter of where to insert it is ignored. This commit makes sure to use that unused parameter to insert it where requested. Fixes: f0d22d187473 ('net/mlx5_core: Introduce flow steering autogrouped flow table') Signed-off-by: Paul Blakey Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 5da2cc8785824..17559c8429055 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -879,7 +879,7 @@ static struct mlx5_flow_group *create_flow_group_common(struct mlx5_flow_table * tree_init_node(&fg->node, !is_auto_fg, del_flow_group); tree_add_node(&fg->node, &ft->node); /* Add node to group list */ - list_add(&fg->node.list, ft->node.children.prev); + list_add(&fg->node.list, prev_fg); return fg; } @@ -893,7 +893,7 @@ struct mlx5_flow_group *mlx5_create_flow_group(struct mlx5_flow_table *ft, return ERR_PTR(-EPERM); lock_ref_node(&ft->node); - fg = create_flow_group_common(ft, fg_in, &ft->node.children, false); + fg = create_flow_group_common(ft, fg_in, ft->node.children.prev, false); unlock_ref_node(&ft->node); return fg; @@ -1012,7 +1012,7 @@ static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft, u32 *match_criteria) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); - struct list_head *prev = &ft->node.children; + struct list_head *prev = ft->node.children.prev; unsigned int candidate_index = 0; struct mlx5_flow_group *fg; void *match_criteria_addr; -- GitLab From 32dba76a7a3104b2815f31b1755f4c0ba1f01a78 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 25 Oct 2016 18:36:27 +0300 Subject: [PATCH 1127/1167] net/mlx5: Fix autogroups groups num not decreasing Autogroups groups num is increased when creating a new flow group, but is never decreased. Now decreasing it when deleting a flow group. Fixes: f0d22d187473 ('net/mlx5_core: Introduce flow steering autogrouped flow table') Signed-off-by: Paul Blakey Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 17559c8429055..89696048b0454 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -436,6 +436,9 @@ static void del_flow_group(struct fs_node *node) fs_get_obj(ft, fg->node.parent); dev = get_dev(&ft->node); + if (ft->autogroup.active) + ft->autogroup.num_groups--; + if (mlx5_cmd_destroy_flow_group(dev, ft, fg->id)) mlx5_core_warn(dev, "flow steering can't destroy fg %d of ft %d\n", fg->id, ft->id); -- GitLab From e83d6955fe422f120b0e98e4f02496af89845eef Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 25 Oct 2016 18:36:28 +0300 Subject: [PATCH 1128/1167] net/mlx5: Correctly initialize last use of flow counters Currently, last use timestamp is initialized to zero. This is not the expected value by higher layers such as when we do TC action offloading. To fix that, set it to the current time, e.g when the counter/rule is offloaded. This is the same behaviour of non-offloaded TC actions. Fixes: 43a335e055bb ('mlx5_core: Flow counters infrastructure') Signed-off-by: Paul Blakey Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c index 3a9195b4169dc..3b026c151cf24 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c @@ -218,6 +218,7 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging) goto err_out; if (aging) { + counter->cache.lastuse = jiffies; counter->aging = true; spin_lock(&fc_stats->addlist_lock); -- GitLab From 2b029556667a7fc1aea731c5828e501656f87653 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Tue, 25 Oct 2016 18:36:29 +0300 Subject: [PATCH 1129/1167] net/mlx5e: Choose best nearest LRO timeout Instead of predicting the index of the wanted LRO timeout value from hardware capabilities, look for the nearest LRO timeout value. Fixes: 5c50368f3831 ('net/mlx5e: Light-weight netdev open/stop') Signed-off-by: Saeed Mahameed Signed-off-by: Mohamad Haj Yahia Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 5 +++++ .../net/ethernet/mellanox/mlx5/core/en_main.c | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 460363b66cb1c..7a43502a89cce 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -85,6 +85,9 @@ #define MLX5_MPWRQ_SMALL_PACKET_THRESHOLD (128) #define MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ (64 * 1024) +#define MLX5E_DEFAULT_LRO_TIMEOUT 32 +#define MLX5E_LRO_TIMEOUT_ARR_SIZE 4 + #define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC 0x10 #define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE 0x3 #define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS 0x20 @@ -221,6 +224,7 @@ struct mlx5e_params { struct ieee_ets ets; #endif bool rx_am_enabled; + u32 lro_timeout; }; struct mlx5e_tstamp { @@ -888,5 +892,6 @@ int mlx5e_attach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev); void mlx5e_detach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev); struct rtnl_link_stats64 * mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats); +u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeout); #endif /* __MLX5_EN_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 7eaf38020a8fe..5c8ab3eabe9c6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1971,9 +1971,7 @@ static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv) MLX5_SET(tirc, tirc, lro_max_ip_payload_size, (priv->params.lro_wqe_sz - ROUGH_MAX_L2_L3_HDR_SZ) >> 8); - MLX5_SET(tirc, tirc, lro_timeout_period_usecs, - MLX5_CAP_ETH(priv->mdev, - lro_timer_supported_periods[2])); + MLX5_SET(tirc, tirc, lro_timeout_period_usecs, priv->params.lro_timeout); } void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv) @@ -3401,6 +3399,18 @@ static void mlx5e_query_min_inline(struct mlx5_core_dev *mdev, } } +u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeout) +{ + int i; + + /* The supported periods are organized in ascending order */ + for (i = 0; i < MLX5E_LRO_TIMEOUT_ARR_SIZE - 1; i++) + if (MLX5_CAP_ETH(mdev, lro_timer_supported_periods[i]) >= wanted_timeout) + break; + + return MLX5_CAP_ETH(mdev, lro_timer_supported_periods[i]); +} + static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev, struct net_device *netdev, const struct mlx5e_profile *profile, @@ -3419,6 +3429,9 @@ static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev, priv->profile = profile; priv->ppriv = ppriv; + priv->params.lro_timeout = + mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT); + priv->params.log_sq_size = MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE; /* set CQE compression */ -- GitLab From 5e1e93c7047381b81236f82f60c15d49c510d1a7 Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Tue, 25 Oct 2016 18:36:30 +0300 Subject: [PATCH 1130/1167] net/mlx5e: Unregister netdev before detaching it Detaching the netdev before unregistering it cause some netdev cleanup ndos to fail because they check presence of the netdev, so we need to unregister the netdev first. Fixes: 26e59d8077a3 ('net/mlx5e: Implement mlx5e interface attach/detach callbacks') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 5c8ab3eabe9c6..f4c687ce4c598 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -4048,7 +4048,6 @@ void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv) const struct mlx5e_profile *profile = priv->profile; struct net_device *netdev = priv->netdev; - unregister_netdev(netdev); destroy_workqueue(priv->wq); if (profile->cleanup) profile->cleanup(priv); @@ -4065,6 +4064,7 @@ static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv) for (vport = 1; vport < total_vfs; vport++) mlx5_eswitch_unregister_vport_rep(esw, vport); + unregister_netdev(priv->netdev); mlx5e_detach(mdev, vpriv); mlx5e_destroy_netdev(mdev, priv); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 3c97da103d30e..7fe6559e4ab30 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -457,6 +457,7 @@ void mlx5e_vport_rep_unload(struct mlx5_eswitch *esw, struct mlx5e_priv *priv = rep->priv_data; struct net_device *netdev = priv->netdev; + unregister_netdev(netdev); mlx5e_detach_netdev(esw->dev, netdev); mlx5e_destroy_netdev(esw->dev, priv); } -- GitLab From 247f139cdae73b4f47bd348d05dff1afd40b84b6 Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Tue, 25 Oct 2016 18:36:31 +0300 Subject: [PATCH 1131/1167] net/mlx5: Change the acl enable prototype to return status The Ingress/Egress ACL enable function may fail and it should return status to its caller to avoid NULL pointer dereference. Fixes: f942380c1239 ('net/mlx5: E-Switch, Vport ingress/egress ACLs rules for spoofchk') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index abbf2c369923d..be1f7333ab7f6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -931,8 +931,8 @@ static void esw_vport_change_handler(struct work_struct *work) mutex_unlock(&esw->state_lock); } -static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_flow_group *vlan_grp = NULL; @@ -949,9 +949,11 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, int table_size = 2; int err = 0; - if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support) || - !IS_ERR_OR_NULL(vport->egress.acl)) - return; + if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) + return -EOPNOTSUPP; + + if (!IS_ERR_OR_NULL(vport->egress.acl)) + return 0; esw_debug(dev, "Create vport[%d] egress ACL log_max_size(%d)\n", vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size)); @@ -959,12 +961,12 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS); if (!root_ns) { esw_warn(dev, "Failed to get E-Switch egress flow namespace\n"); - return; + return -EIO; } flow_group_in = mlx5_vzalloc(inlen); if (!flow_group_in) - return; + return -ENOMEM; acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport); if (IS_ERR(acl)) { @@ -1009,6 +1011,7 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, mlx5_destroy_flow_group(vlan_grp); if (err && !IS_ERR_OR_NULL(acl)) mlx5_destroy_flow_table(acl); + return err; } static void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw, @@ -1041,8 +1044,8 @@ static void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw, vport->egress.acl = NULL; } -static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_core_dev *dev = esw->dev; @@ -1063,9 +1066,11 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, int table_size = 4; int err = 0; - if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support) || - !IS_ERR_OR_NULL(vport->ingress.acl)) - return; + if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) + return -EOPNOTSUPP; + + if (!IS_ERR_OR_NULL(vport->ingress.acl)) + return 0; esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n", vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size)); @@ -1073,12 +1078,12 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS); if (!root_ns) { esw_warn(dev, "Failed to get E-Switch ingress flow namespace\n"); - return; + return -EIO; } flow_group_in = mlx5_vzalloc(inlen); if (!flow_group_in) - return; + return -ENOMEM; acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport); if (IS_ERR(acl)) { @@ -1167,6 +1172,7 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, } kvfree(flow_group_in); + return err; } static void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw, @@ -1225,7 +1231,13 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, return 0; } - esw_vport_enable_ingress_acl(esw, vport); + err = esw_vport_enable_ingress_acl(esw, vport); + if (err) { + mlx5_core_warn(esw->dev, + "failed to enable ingress acl (%d) on vport[%d]\n", + err, vport->vport); + return err; + } esw_debug(esw->dev, "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n", @@ -1299,7 +1311,13 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, return 0; } - esw_vport_enable_egress_acl(esw, vport); + err = esw_vport_enable_egress_acl(esw, vport); + if (err) { + mlx5_core_warn(esw->dev, + "failed to enable egress acl (%d) on vport[%d]\n", + err, vport->vport); + return err; + } esw_debug(esw->dev, "vport[%d] configure egress rules, vlan(%d) qos(%d)\n", -- GitLab From 2241007b3d783cbdbaa78c30bdb1994278b6f9b9 Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Tue, 25 Oct 2016 18:36:32 +0300 Subject: [PATCH 1132/1167] net/mlx5: Clear health sick bit when starting health poll The health sick status should be cleared when we start the health poll. This is crucial for driver reload (unload + load) in order to behave right in case of health issue. Fixes: fd76ee4da55a ('net/mlx5_core: Fix internal error detection conditions') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/health.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 1a05fb965c8dd..2cb4094c9c496 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -281,6 +281,7 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev) struct mlx5_core_health *health = &dev->priv.health; init_timer(&health->timer); + health->sick = 0; health->health = &dev->iseg->health; health->health_counter = &dev->iseg->health_counter; -- GitLab From 05ac2c0b7438ea08c5d54b48797acf9b22cb2f6f Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Tue, 25 Oct 2016 18:36:33 +0300 Subject: [PATCH 1133/1167] net/mlx5: Fix race between PCI error handlers and health work Currently there is a race between the health care work and the kernel pci error handlers because both of them detect the error, the first one to be called will do the error handling. There is a chance that health care will disable the pci after resuming pci slot. Also create a separate WQ because now we will have two types of health works, one for the error detection and one for the recovery. Fixes: 89d44f0a6c73 ('net/mlx5_core: Add pci error handlers to mlx5_core driver') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx5/core/health.c | 30 +++++++++++++++++-- .../net/ethernet/mellanox/mlx5/core/main.c | 9 ++++-- include/linux/mlx5/driver.h | 4 +++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 2cb4094c9c496..2d00022c92d8f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -64,6 +64,10 @@ enum { MLX5_NIC_IFC_NO_DRAM_NIC = 2 }; +enum { + MLX5_DROP_NEW_HEALTH_WORK, +}; + static u8 get_nic_interface(struct mlx5_core_dev *dev) { return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3; @@ -272,7 +276,13 @@ static void poll_health(unsigned long data) if (in_fatal(dev) && !health->sick) { health->sick = true; print_health_info(dev); - schedule_work(&health->work); + spin_lock(&health->wq_lock); + if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) + queue_work(health->wq, &health->work); + else + dev_err(&dev->pdev->dev, + "new health works are not permitted at this stage\n"); + spin_unlock(&health->wq_lock); } } @@ -282,6 +292,7 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev) init_timer(&health->timer); health->sick = 0; + clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags); health->health = &dev->iseg->health; health->health_counter = &dev->iseg->health_counter; @@ -298,11 +309,21 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev) del_timer_sync(&health->timer); } +void mlx5_drain_health_wq(struct mlx5_core_dev *dev) +{ + struct mlx5_core_health *health = &dev->priv.health; + + spin_lock(&health->wq_lock); + set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags); + spin_unlock(&health->wq_lock); + cancel_work_sync(&health->work); +} + void mlx5_health_cleanup(struct mlx5_core_dev *dev) { struct mlx5_core_health *health = &dev->priv.health; - flush_work(&health->work); + destroy_workqueue(health->wq); } int mlx5_health_init(struct mlx5_core_dev *dev) @@ -317,8 +338,11 @@ int mlx5_health_init(struct mlx5_core_dev *dev) strcpy(name, "mlx5_health"); strcat(name, dev_name(&dev->pdev->dev)); + health->wq = create_singlethread_workqueue(name); kfree(name); - + if (!health->wq) + return -ENOMEM; + spin_lock_init(&health->wq_lock); INIT_WORK(&health->work, health_care); return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 8a63910bfccf8..9f90226bc1200 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1315,8 +1315,13 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev, dev_info(&pdev->dev, "%s was called\n", __func__); mlx5_enter_error_state(dev); mlx5_unload_one(dev, priv, false); - pci_save_state(pdev); - mlx5_pci_disable_device(dev); + /* In case of kernel call save the pci state and drain health wq */ + if (state) { + pci_save_state(pdev); + mlx5_drain_health_wq(dev); + mlx5_pci_disable_device(dev); + } + return state == pci_channel_io_perm_failure ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 5dbda60a09f4f..7d9a5d08eb596 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -418,7 +418,10 @@ struct mlx5_core_health { u32 prev; int miss_counter; bool sick; + /* wq spinlock to synchronize draining */ + spinlock_t wq_lock; struct workqueue_struct *wq; + unsigned long flags; struct work_struct work; }; @@ -778,6 +781,7 @@ void mlx5_health_cleanup(struct mlx5_core_dev *dev); int mlx5_health_init(struct mlx5_core_dev *dev); void mlx5_start_health_poll(struct mlx5_core_dev *dev); void mlx5_stop_health_poll(struct mlx5_core_dev *dev); +void mlx5_drain_health_wq(struct mlx5_core_dev *dev); int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf, int node); int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf); -- GitLab From 04c0c1ab38e95105d950db5b84e727637e149ce7 Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Tue, 25 Oct 2016 18:36:34 +0300 Subject: [PATCH 1134/1167] net/mlx5: PCI error recovery health care simulation In case that the kernel PCI error handlers are not called, we will trigger our own recovery flow. The health work will give priority to the kernel pci error handlers to recover the PCI by waiting for a small period, if the pci error handlers are not triggered the manual recovery flow will be executed. We don't save pci state in case of manual recovery because it will ruin the pci configuration space and we will lose dma sync. Fixes: 89d44f0a6c73 ('net/mlx5_core: Add pci error handlers to mlx5_core driver') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx5/core/health.c | 45 +++++++++++++++++-- .../net/ethernet/mellanox/mlx5/core/main.c | 18 +++++--- .../ethernet/mellanox/mlx5/core/mlx5_core.h | 1 + include/linux/mlx5/driver.h | 1 + 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 2d00022c92d8f..5bcf93422ee0b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -61,14 +61,15 @@ enum { enum { MLX5_NIC_IFC_FULL = 0, MLX5_NIC_IFC_DISABLED = 1, - MLX5_NIC_IFC_NO_DRAM_NIC = 2 + MLX5_NIC_IFC_NO_DRAM_NIC = 2, + MLX5_NIC_IFC_INVALID = 3 }; enum { MLX5_DROP_NEW_HEALTH_WORK, }; -static u8 get_nic_interface(struct mlx5_core_dev *dev) +static u8 get_nic_state(struct mlx5_core_dev *dev) { return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3; } @@ -101,7 +102,7 @@ static int in_fatal(struct mlx5_core_dev *dev) struct mlx5_core_health *health = &dev->priv.health; struct health_buffer __iomem *h = health->health; - if (get_nic_interface(dev) == MLX5_NIC_IFC_DISABLED) + if (get_nic_state(dev) == MLX5_NIC_IFC_DISABLED) return 1; if (ioread32be(&h->fw_ver) == 0xffffffff) @@ -131,7 +132,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev) static void mlx5_handle_bad_state(struct mlx5_core_dev *dev) { - u8 nic_interface = get_nic_interface(dev); + u8 nic_interface = get_nic_state(dev); switch (nic_interface) { case MLX5_NIC_IFC_FULL: @@ -153,8 +154,34 @@ static void mlx5_handle_bad_state(struct mlx5_core_dev *dev) mlx5_disable_device(dev); } +static void health_recover(struct work_struct *work) +{ + struct mlx5_core_health *health; + struct delayed_work *dwork; + struct mlx5_core_dev *dev; + struct mlx5_priv *priv; + u8 nic_state; + + dwork = container_of(work, struct delayed_work, work); + health = container_of(dwork, struct mlx5_core_health, recover_work); + priv = container_of(health, struct mlx5_priv, health); + dev = container_of(priv, struct mlx5_core_dev, priv); + + nic_state = get_nic_state(dev); + if (nic_state == MLX5_NIC_IFC_INVALID) { + dev_err(&dev->pdev->dev, "health recovery flow aborted since the nic state is invalid\n"); + return; + } + + dev_err(&dev->pdev->dev, "starting health recovery flow\n"); + mlx5_recover_device(dev); +} + +/* How much time to wait until health resetting the driver (in msecs) */ +#define MLX5_RECOVERY_DELAY_MSECS 60000 static void health_care(struct work_struct *work) { + unsigned long recover_delay = msecs_to_jiffies(MLX5_RECOVERY_DELAY_MSECS); struct mlx5_core_health *health; struct mlx5_core_dev *dev; struct mlx5_priv *priv; @@ -164,6 +191,14 @@ static void health_care(struct work_struct *work) dev = container_of(priv, struct mlx5_core_dev, priv); mlx5_core_warn(dev, "handling bad device here\n"); mlx5_handle_bad_state(dev); + + spin_lock(&health->wq_lock); + if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) + schedule_delayed_work(&health->recover_work, recover_delay); + else + dev_err(&dev->pdev->dev, + "new health works are not permitted at this stage\n"); + spin_unlock(&health->wq_lock); } static const char *hsynd_str(u8 synd) @@ -316,6 +351,7 @@ void mlx5_drain_health_wq(struct mlx5_core_dev *dev) spin_lock(&health->wq_lock); set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags); spin_unlock(&health->wq_lock); + cancel_delayed_work_sync(&health->recover_work); cancel_work_sync(&health->work); } @@ -344,6 +380,7 @@ int mlx5_health_init(struct mlx5_core_dev *dev) return -ENOMEM; spin_lock_init(&health->wq_lock); INIT_WORK(&health->work, health_care); + INIT_DELAYED_WORK(&health->recover_work, health_recover); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 9f90226bc1200..d5433c49b2b06 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1313,6 +1313,7 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev, struct mlx5_priv *priv = &dev->priv; dev_info(&pdev->dev, "%s was called\n", __func__); + mlx5_enter_error_state(dev); mlx5_unload_one(dev, priv, false); /* In case of kernel call save the pci state and drain health wq */ @@ -1378,11 +1379,6 @@ static pci_ers_result_t mlx5_pci_slot_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_RECOVERED; } -void mlx5_disable_device(struct mlx5_core_dev *dev) -{ - mlx5_pci_err_detected(dev->pdev, 0); -} - static void mlx5_pci_resume(struct pci_dev *pdev) { struct mlx5_core_dev *dev = pci_get_drvdata(pdev); @@ -1432,6 +1428,18 @@ static const struct pci_device_id mlx5_core_pci_table[] = { MODULE_DEVICE_TABLE(pci, mlx5_core_pci_table); +void mlx5_disable_device(struct mlx5_core_dev *dev) +{ + mlx5_pci_err_detected(dev->pdev, 0); +} + +void mlx5_recover_device(struct mlx5_core_dev *dev) +{ + mlx5_pci_disable_device(dev); + if (mlx5_pci_slot_reset(dev->pdev) == PCI_ERS_RESULT_RECOVERED) + mlx5_pci_resume(dev->pdev); +} + static struct pci_driver mlx5_core_driver = { .name = DRIVER_NAME, .id_table = mlx5_core_pci_table, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 3d0cfb9f18f99..187662c8ea96d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -83,6 +83,7 @@ void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, unsigned long param); void mlx5_enter_error_state(struct mlx5_core_dev *dev); void mlx5_disable_device(struct mlx5_core_dev *dev); +void mlx5_recover_device(struct mlx5_core_dev *dev); int mlx5_sriov_init(struct mlx5_core_dev *dev); void mlx5_sriov_cleanup(struct mlx5_core_dev *dev); int mlx5_sriov_attach(struct mlx5_core_dev *dev); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 7d9a5d08eb596..ecc451d89ccd8 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -423,6 +423,7 @@ struct mlx5_core_health { struct workqueue_struct *wq; unsigned long flags; struct work_struct work; + struct delayed_work recover_work; }; struct mlx5_cq_table { -- GitLab From 6b276190c50a12511d889d9079ffb901ff94a822 Mon Sep 17 00:00:00 2001 From: Noa Osherovich Date: Tue, 25 Oct 2016 18:36:35 +0300 Subject: [PATCH 1135/1167] net/mlx5: Avoid passing dma address 0 to firmware Currently the firmware can't work with a page with dma address 0. Passing such an address to the firmware will cause the give_pages command to fail. To avoid this, in case we get a 0 dma address of a page from the dma engine, we avoid passing it to FW by remapping to get an address other than 0. Fixes: bf0bf77f6519 ('mlx5: Support communicating arbitrary host...') Signed-off-by: Noa Osherovich Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlx5/core/pagealloc.c | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index cc4fd61914d30..a57d5a81eb05d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -209,6 +209,7 @@ static void free_4k(struct mlx5_core_dev *dev, u64 addr) static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id) { struct page *page; + u64 zero_addr = 1; u64 addr; int err; int nid = dev_to_node(&dev->pdev->dev); @@ -218,26 +219,35 @@ static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id) mlx5_core_warn(dev, "failed to allocate page\n"); return -ENOMEM; } +map: addr = dma_map_page(&dev->pdev->dev, page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); if (dma_mapping_error(&dev->pdev->dev, addr)) { mlx5_core_warn(dev, "failed dma mapping page\n"); err = -ENOMEM; - goto out_alloc; + goto err_mapping; } + + /* Firmware doesn't support page with physical address 0 */ + if (addr == 0) { + zero_addr = addr; + goto map; + } + err = insert_page(dev, addr, page, func_id); if (err) { mlx5_core_err(dev, "failed to track allocated page\n"); - goto out_mapping; + dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, + DMA_BIDIRECTIONAL); } - return 0; - -out_mapping: - dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL); +err_mapping: + if (err) + __free_page(page); -out_alloc: - __free_page(page); + if (zero_addr == 0) + dma_unmap_page(&dev->pdev->dev, zero_addr, PAGE_SIZE, + DMA_BIDIRECTIONAL); return err; } -- GitLab From e4cabca54911a6be6f2e80e48fa497c7e19019a5 Mon Sep 17 00:00:00 2001 From: Craig Gallek Date: Tue, 25 Oct 2016 18:08:49 -0400 Subject: [PATCH 1136/1167] inet: Fix missing return value in inet6_hash As part of a series to implement faster SO_REUSEPORT lookups, commit 086c653f5862 ("sock: struct proto hash function may error") added return values to protocol hash functions and commit 496611d7b5ea ("inet: create IPv6-equivalent inet_hash function") implemented a new hash function for IPv6. However, the latter does not respect the former's convention. This properly propagates the hash errors in the IPv6 case. Fixes: 496611d7b5ea ("inet: create IPv6-equivalent inet_hash function") Reported-by: Soheil Hassas Yeganeh Signed-off-by: Craig Gallek Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller --- net/ipv6/inet6_hashtables.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 2fd0374a35b17..02761c9fe43eb 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -264,13 +264,15 @@ EXPORT_SYMBOL_GPL(inet6_hash_connect); int inet6_hash(struct sock *sk) { + int err = 0; + if (sk->sk_state != TCP_CLOSE) { local_bh_disable(); - __inet_hash(sk, NULL, ipv6_rcv_saddr_equal); + err = __inet_hash(sk, NULL, ipv6_rcv_saddr_equal); local_bh_enable(); } - return 0; + return err; } EXPORT_SYMBOL_GPL(inet6_hash); -- GitLab From 96a8eb1eeed2c3485cdba198fab3a2faaec386d3 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 26 Oct 2016 00:37:53 +0200 Subject: [PATCH 1137/1167] bpf: fix samples to add fake KBUILD_MODNAME Some of the sample files are causing issues when they are loaded with tc and cls_bpf, meaning tc bails out while trying to parse the resulting ELF file as program/map/etc sections are not present, which can be easily spotted with readelf(1). Currently, BPF samples are including some of the kernel headers and mid term we should change them to refrain from this, really. When dynamic debugging is enabled, we bail out due to undeclared KBUILD_MODNAME, which is easily overlooked in the build as clang spills this along with other noisy warnings from various header includes, and llc still generates an ELF file with mentioned characteristics. For just playing around with BPF examples, this can be a bit of a hurdle to take. Just add a fake KBUILD_MODNAME as a band-aid to fix the issue, same is done in xdp*_kern samples already. Fixes: 65d472fb007d ("samples/bpf: add 'pointer to packet' tests") Fixes: 6afb1e28b859 ("samples/bpf: Add tunnel set/get tests.") Fixes: a3f74617340b ("cgroup: bpf: Add an example to do cgroup checking in BPF") Reported-by: Chandrasekar Kannan Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- samples/bpf/parse_ldabs.c | 1 + samples/bpf/parse_simple.c | 1 + samples/bpf/parse_varlen.c | 1 + samples/bpf/tcbpf1_kern.c | 1 + samples/bpf/tcbpf2_kern.c | 1 + samples/bpf/test_cgrp2_tc_kern.c | 1 + 6 files changed, 6 insertions(+) diff --git a/samples/bpf/parse_ldabs.c b/samples/bpf/parse_ldabs.c index d17550198d062..6db6b21fdc6dd 100644 --- a/samples/bpf/parse_ldabs.c +++ b/samples/bpf/parse_ldabs.c @@ -4,6 +4,7 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ +#define KBUILD_MODNAME "foo" #include #include #include diff --git a/samples/bpf/parse_simple.c b/samples/bpf/parse_simple.c index cf2511c339057..10af53d33cc29 100644 --- a/samples/bpf/parse_simple.c +++ b/samples/bpf/parse_simple.c @@ -4,6 +4,7 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ +#define KBUILD_MODNAME "foo" #include #include #include diff --git a/samples/bpf/parse_varlen.c b/samples/bpf/parse_varlen.c index edab34dce79b3..95c16324760c0 100644 --- a/samples/bpf/parse_varlen.c +++ b/samples/bpf/parse_varlen.c @@ -4,6 +4,7 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ +#define KBUILD_MODNAME "foo" #include #include #include diff --git a/samples/bpf/tcbpf1_kern.c b/samples/bpf/tcbpf1_kern.c index fa051b3d53ee0..274c884c87fe0 100644 --- a/samples/bpf/tcbpf1_kern.c +++ b/samples/bpf/tcbpf1_kern.c @@ -1,3 +1,4 @@ +#define KBUILD_MODNAME "foo" #include #include #include diff --git a/samples/bpf/tcbpf2_kern.c b/samples/bpf/tcbpf2_kern.c index 3303bb85593bc..9c823a609e75f 100644 --- a/samples/bpf/tcbpf2_kern.c +++ b/samples/bpf/tcbpf2_kern.c @@ -5,6 +5,7 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ +#define KBUILD_MODNAME "foo" #include #include #include diff --git a/samples/bpf/test_cgrp2_tc_kern.c b/samples/bpf/test_cgrp2_tc_kern.c index 10ff73404e3a8..1547b36a7b7b9 100644 --- a/samples/bpf/test_cgrp2_tc_kern.c +++ b/samples/bpf/test_cgrp2_tc_kern.c @@ -4,6 +4,7 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ +#define KBUILD_MODNAME "foo" #include #include #include -- GitLab From ae148b085876fa771d9ef2c05f85d4b4bf09ce0d Mon Sep 17 00:00:00 2001 From: Eli Cooper Date: Wed, 26 Oct 2016 10:11:09 +0800 Subject: [PATCH 1138/1167] ip6_tunnel: Update skb->protocol to ETH_P_IPV6 in ip6_tnl_xmit() This patch updates skb->protocol to ETH_P_IPV6 in ip6_tnl_xmit() when an IPv6 header is installed to a socket buffer. This is not a cosmetic change. Without updating this value, GSO packets transmitted through an ipip6 tunnel have the protocol of ETH_P_IP and skb_mac_gso_segment() will attempt to call gso_segment() for IPv4, which results in the packets being dropped. Fixes: b8921ca83eed ("ip4ip6: Support for GSO/GRO") Signed-off-by: Eli Cooper Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 5692d6b8da95a..87784560dc46b 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1172,6 +1172,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, if (err) return err; + skb->protocol = htons(ETH_P_IPV6); skb_push(skb, sizeof(struct ipv6hdr)); skb_reset_network_header(skb); ipv6h = ipv6_hdr(skb); -- GitLab From a4256bc9ec36159e84d710c7c44aaa244a6380a8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 25 Oct 2016 18:16:20 +0200 Subject: [PATCH 1139/1167] IB/mlx4: avoid a -Wmaybe-uninitialize warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is an old warning about mlx4_SW2HW_EQ_wrapper on x86: ethernet/mellanox/mlx4/resource_tracker.c: In function ‘mlx4_SW2HW_EQ_wrapper’: ethernet/mellanox/mlx4/resource_tracker.c:3071:10: error: ‘eq’ may be used uninitialized in this function [-Werror=maybe-uninitialized] The problem here is that gcc won't track the state of the variable across a spin_unlock. Moving the assignment out of the lock is safe here and avoids the warning. Signed-off-by: Arnd Bergmann Reviewed-by: Yishai Hadas Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 84d7857ccc271..c548beaaf9109 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -1605,13 +1605,14 @@ static int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, r->com.from_state = r->com.state; r->com.to_state = state; r->com.state = RES_EQ_BUSY; - if (eq) - *eq = r; } } spin_unlock_irq(mlx4_tlock(dev)); + if (!err && eq) + *eq = r; + return err; } -- GitLab From 166e6045cacccb3046883a1a4c977f173fec5ccd Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Wed, 26 Oct 2016 13:26:38 +0530 Subject: [PATCH 1140/1167] cxgb4: Fix error handling in alloc_uld_rxqs(). Fix to release resources properly in error handling path of alloc_uld_rxqs(), This patch also removes unwanted arguments and avoids calling the same function twice. Fixes: 94cdb8bb993a (cxgb4: Add support for dynamic allocation of resources for ULD Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- .../net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index 0945fa49a5dd8..2471ff465d5c6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -135,15 +135,17 @@ static int uldrx_handler(struct sge_rspq *q, const __be64 *rsp, } static int alloc_uld_rxqs(struct adapter *adap, - struct sge_uld_rxq_info *rxq_info, - unsigned int nq, unsigned int offset, bool lro) + struct sge_uld_rxq_info *rxq_info, bool lro) { struct sge *s = &adap->sge; - struct sge_ofld_rxq *q = rxq_info->uldrxq + offset; - unsigned short *ids = rxq_info->rspq_id + offset; - unsigned int per_chan = nq / adap->params.nports; + unsigned int nq = rxq_info->nrxq + rxq_info->nciq; + struct sge_ofld_rxq *q = rxq_info->uldrxq; + unsigned short *ids = rxq_info->rspq_id; unsigned int bmap_idx = 0; - int i, err, msi_idx; + unsigned int per_chan; + int i, err, msi_idx, que_idx = 0; + + per_chan = rxq_info->nrxq / adap->params.nports; if (adap->flags & USING_MSIX) msi_idx = 1; @@ -151,12 +153,18 @@ static int alloc_uld_rxqs(struct adapter *adap, msi_idx = -((int)s->intrq.abs_id + 1); for (i = 0; i < nq; i++, q++) { + if (i == rxq_info->nrxq) { + /* start allocation of concentrator queues */ + per_chan = rxq_info->nciq / adap->params.nports; + que_idx = 0; + } + if (msi_idx >= 0) { bmap_idx = get_msix_idx_from_bmap(adap); msi_idx = adap->msix_info_ulds[bmap_idx].idx; } err = t4_sge_alloc_rxq(adap, &q->rspq, false, - adap->port[i / per_chan], + adap->port[que_idx++ / per_chan], msi_idx, q->fl.size ? &q->fl : NULL, uldrx_handler, @@ -165,29 +173,19 @@ static int alloc_uld_rxqs(struct adapter *adap, if (err) goto freeout; if (msi_idx >= 0) - rxq_info->msix_tbl[i + offset] = bmap_idx; + rxq_info->msix_tbl[i] = bmap_idx; memset(&q->stats, 0, sizeof(q->stats)); if (ids) ids[i] = q->rspq.abs_id; } return 0; freeout: - q = rxq_info->uldrxq + offset; + q = rxq_info->uldrxq; for ( ; i; i--, q++) { if (q->rspq.desc) free_rspq_fl(adap, &q->rspq, q->fl.size ? &q->fl : NULL); } - - /* We need to free rxq also in case of ciq allocation failure */ - if (offset) { - q = rxq_info->uldrxq + offset; - for ( ; i; i--, q++) { - if (q->rspq.desc) - free_rspq_fl(adap, &q->rspq, - q->fl.size ? &q->fl : NULL); - } - } return err; } @@ -205,9 +203,7 @@ setup_sge_queues_uld(struct adapter *adap, unsigned int uld_type, bool lro) return -ENOMEM; } - ret = !(!alloc_uld_rxqs(adap, rxq_info, rxq_info->nrxq, 0, lro) && - !alloc_uld_rxqs(adap, rxq_info, rxq_info->nciq, - rxq_info->nrxq, lro)); + ret = !(!alloc_uld_rxqs(adap, rxq_info, lro)); /* Tell uP to route control queue completions to rdma rspq */ if (adap->flags & FULL_INIT_DONE && -- GitLab From 4700e9ce6ed8526a14e6cf9d7e319f675c16d0a7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Oct 2016 14:44:33 +0200 Subject: [PATCH 1141/1167] net_sched actions: use nla_parse_nested() Use nla_parse_nested instead of open-coding the call to nla_parse() with the attribute data/len. Signed-off-by: Johannes Berg Acked-by: Cong Wang Signed-off-by: David S. Miller --- net/sched/act_api.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index a512b18c00885..f893d180da1ca 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1028,8 +1028,7 @@ static struct nlattr *find_dump_kind(const struct nlmsghdr *n) if (tb[1] == NULL) return NULL; - if (nla_parse(tb2, TCA_ACT_MAX, nla_data(tb[1]), - nla_len(tb[1]), NULL) < 0) + if (nla_parse_nested(tb2, TCA_ACT_MAX, tb[1], NULL) < 0) return NULL; kind = tb2[TCA_ACT_KIND]; -- GitLab From 104ba78c98808ae837d1f63aae58c183db5505df Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Wed, 26 Oct 2016 11:23:07 -0400 Subject: [PATCH 1142/1167] packet: on direct_xmit, limit tso and csum to supported devices When transmitting on a packet socket with PACKET_VNET_HDR and PACKET_QDISC_BYPASS, validate device support for features requested in vnet_hdr. Drop TSO packets sent to devices that do not support TSO or have the feature disabled. Note that the latter currently do process those packets correctly, regardless of not advertising the feature. Because of SKB_GSO_DODGY, it is not sufficient to test device features with netif_needs_gso. Full validate_xmit_skb is needed. Switch to software checksum for non-TSO packets that request checksum offload if that device feature is unsupported or disabled. Note that similar to the TSO case, device drivers may perform checksum offload correctly even when not advertising it. When switching to software checksum, packets hit skb_checksum_help, which has two BUG_ON checksum not in linear segment. Packet sockets always allocate at least up to csum_start + csum_off + 2 as linear. Tested by running github.com/wdebruij/kerneltools/psock_txring_vnet.c ethtool -K eth0 tso off tx on psock_txring_vnet -d $dst -s $src -i eth0 -l 2000 -n 1 -q -v psock_txring_vnet -d $dst -s $src -i eth0 -l 2000 -n 1 -q -v -N ethtool -K eth0 tx off psock_txring_vnet -d $dst -s $src -i eth0 -l 1000 -n 1 -q -v -G psock_txring_vnet -d $dst -s $src -i eth0 -l 1000 -n 1 -q -v -G -N v2: - add EXPORT_SYMBOL_GPL(validate_xmit_skb_list) Fixes: d346a3fae3ff ("packet: introduce PACKET_QDISC_BYPASS socket option") Signed-off-by: Willem de Bruijn Acked-by: Eric Dumazet Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/core/dev.c | 1 + net/packet/af_packet.c | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index dbc8713069107..f745112f7efa4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3035,6 +3035,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d } return head; } +EXPORT_SYMBOL_GPL(validate_xmit_skb_list); static void qdisc_pkt_len_init(struct sk_buff *skb) { diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 11db0d619c007..d2238b204691b 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -250,7 +250,7 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po); static int packet_direct_xmit(struct sk_buff *skb) { struct net_device *dev = skb->dev; - netdev_features_t features; + struct sk_buff *orig_skb = skb; struct netdev_queue *txq; int ret = NETDEV_TX_BUSY; @@ -258,9 +258,8 @@ static int packet_direct_xmit(struct sk_buff *skb) !netif_carrier_ok(dev))) goto drop; - features = netif_skb_features(skb); - if (skb_needs_linearize(skb, features) && - __skb_linearize(skb)) + skb = validate_xmit_skb_list(skb, dev); + if (skb != orig_skb) goto drop; txq = skb_get_tx_queue(dev, skb); @@ -280,7 +279,7 @@ static int packet_direct_xmit(struct sk_buff *skb) return ret; drop: atomic_long_inc(&dev->tx_dropped); - kfree_skb(skb); + kfree_skb_list(skb); return NET_XMIT_DROP; } -- GitLab From e934f684856393a0b2aecc7fdd8357a48b79c535 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 26 Oct 2016 08:30:29 -0700 Subject: [PATCH 1143/1167] Revert "hv_netvsc: report vmbus name in ethtool" This reverts commit e3f74b841d48 ("hv_netvsc: report vmbus name in ethtool")' because of problem introduced by commit f9a56e5d6a0ba ("Drivers: hv: make VMBus bus ids persistent"). This changed the format of the vmbus name and this new format is too long to fit in the bus_info field of ethtool. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 4 ---- include/linux/hyperv.h | 7 ------- 2 files changed, 11 deletions(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index c71d966d905f8..f6382150b16a1 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -699,12 +699,8 @@ int netvsc_recv_callback(struct hv_device *device_obj, static void netvsc_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) { - struct net_device_context *net_device_ctx = netdev_priv(net); - struct hv_device *dev = net_device_ctx->device_ctx; - strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); strlcpy(info->fw_version, "N/A", sizeof(info->fw_version)); - strlcpy(info->bus_info, vmbus_dev_name(dev), sizeof(info->bus_info)); } static void netvsc_get_channels(struct net_device *net, diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 6824556d37ed2..cd184bdca58fd 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1169,13 +1169,6 @@ int __must_check __vmbus_driver_register(struct hv_driver *hv_driver, const char *mod_name); void vmbus_driver_unregister(struct hv_driver *hv_driver); -static inline const char *vmbus_dev_name(const struct hv_device *device_obj) -{ - const struct kobject *kobj = &device_obj->device.kobj; - - return kobj->name; -} - void vmbus_hvsock_device_unregister(struct vmbus_channel *channel); int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, -- GitLab From fd33b2447bec7926ceaf4a4b74b68ea2466f2ae0 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 26 Oct 2016 11:47:02 -0600 Subject: [PATCH 1144/1167] net: mv643xx_eth: Fetch the phy connection type from DT The MAC is capable of RGMII mode and that is probably a more typical connection type than GMII today (eg it is used by Marvell Reference designs for several SOCs). Let DT users specify the standard phy-connection-type = "rgmii-id"; On a phy node. Signed-off-by: Jason Gunthorpe Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../bindings/net/marvell-orion-net.txt | 1 + drivers/net/ethernet/marvell/mv643xx_eth.c | 23 +++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/net/marvell-orion-net.txt b/Documentation/devicetree/bindings/net/marvell-orion-net.txt index bce52b2ec55ec..6fd988c84c4f9 100644 --- a/Documentation/devicetree/bindings/net/marvell-orion-net.txt +++ b/Documentation/devicetree/bindings/net/marvell-orion-net.txt @@ -49,6 +49,7 @@ Optional port properties: and - phy-handle: See ethernet.txt file in the same directory. + - phy-mode: See ethernet.txt file in the same directory. or diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 55831188bc324..bf5cc55ba24cb 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -2968,6 +2968,22 @@ static void set_params(struct mv643xx_eth_private *mp, mp->txq_count = pd->tx_queue_count ? : 1; } +static int get_phy_mode(struct mv643xx_eth_private *mp) +{ + struct device *dev = mp->dev->dev.parent; + int iface = -1; + + if (dev->of_node) + iface = of_get_phy_mode(dev->of_node); + + /* Historical default if unspecified. We could also read/write + * the interface state in the PSC1 + */ + if (iface < 0) + iface = PHY_INTERFACE_MODE_GMII; + return iface; +} + static struct phy_device *phy_scan(struct mv643xx_eth_private *mp, int phy_addr) { @@ -2994,7 +3010,7 @@ static struct phy_device *phy_scan(struct mv643xx_eth_private *mp, "orion-mdio-mii", addr); phydev = phy_connect(mp->dev, phy_id, mv643xx_eth_adjust_link, - PHY_INTERFACE_MODE_GMII); + get_phy_mode(mp)); if (!IS_ERR(phydev)) { phy_addr_set(mp, addr); break; @@ -3090,6 +3106,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; + SET_NETDEV_DEV(dev, &pdev->dev); mp = netdev_priv(dev); platform_set_drvdata(pdev, mp); @@ -3129,7 +3146,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) if (pd->phy_node) { mp->phy = of_phy_connect(mp->dev, pd->phy_node, mv643xx_eth_adjust_link, 0, - PHY_INTERFACE_MODE_GMII); + get_phy_mode(mp)); if (!mp->phy) err = -ENODEV; else @@ -3187,8 +3204,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev->priv_flags |= IFF_UNICAST_FLT; dev->gso_max_segs = MV643XX_MAX_TSO_SEGS; - SET_NETDEV_DEV(dev, &pdev->dev); - if (mp->shared->win_protect) wrl(mp, WINDOW_PROTECT(mp->port_num), mp->shared->win_protect); -- GitLab From 8d7533e5aaad1c94386a8101a36b0617987966b7 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 26 Oct 2016 13:57:38 -0500 Subject: [PATCH 1145/1167] ibmvnic: Fix releasing of sub-CRQ IRQs in interrupt context Schedule these XPORT event tasks in the shared workqueue so that IRQs are not freed in an interrupt context when sub-CRQs are released. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 35 ++++++++++++++++++++---------- drivers/net/ethernet/ibm/ibmvnic.h | 1 + 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 213162df1a9bf..0459d19a5f163 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3232,6 +3232,27 @@ static void ibmvnic_free_inflight(struct ibmvnic_adapter *adapter) spin_unlock_irqrestore(&adapter->inflight_lock, flags); } +static void ibmvnic_xport_event(struct work_struct *work) +{ + struct ibmvnic_adapter *adapter = container_of(work, + struct ibmvnic_adapter, + ibmvnic_xport); + struct device *dev = &adapter->vdev->dev; + int rc; + + ibmvnic_free_inflight(adapter); + release_sub_crqs(adapter); + if (adapter->migrated) { + rc = ibmvnic_reenable_crq_queue(adapter); + if (rc) + dev_err(dev, "Error after enable rc=%ld\n", rc); + adapter->migrated = false; + rc = ibmvnic_send_crq_init(adapter); + if (rc) + dev_err(dev, "Error sending init rc=%ld\n", rc); + } +} + static void ibmvnic_handle_crq(union ibmvnic_crq *crq, struct ibmvnic_adapter *adapter) { @@ -3267,15 +3288,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) { dev_info(dev, "Re-enabling adapter\n"); adapter->migrated = true; - ibmvnic_free_inflight(adapter); - release_sub_crqs(adapter); - rc = ibmvnic_reenable_crq_queue(adapter); - if (rc) - dev_err(dev, "Error after enable rc=%ld\n", rc); - adapter->migrated = false; - rc = ibmvnic_send_crq_init(adapter); - if (rc) - dev_err(dev, "Error sending init rc=%ld\n", rc); + schedule_work(&adapter->ibmvnic_xport); } else if (gen_crq->cmd == IBMVNIC_DEVICE_FAILOVER) { dev_info(dev, "Backing device failover detected\n"); netif_carrier_off(netdev); @@ -3284,8 +3297,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, /* The adapter lost the connection */ dev_err(dev, "Virtual Adapter failed (rc=%d)\n", gen_crq->cmd); - ibmvnic_free_inflight(adapter); - release_sub_crqs(adapter); + schedule_work(&adapter->ibmvnic_xport); } return; case IBMVNIC_CRQ_CMD_RSP: @@ -3726,6 +3738,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) SET_NETDEV_DEV(netdev, &dev->dev); INIT_WORK(&adapter->vnic_crq_init, handle_crq_init_rsp); + INIT_WORK(&adapter->ibmvnic_xport, ibmvnic_xport_event); spin_lock_init(&adapter->stats_lock); diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 878e2c059f5c8..dd775d951b739 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1048,5 +1048,6 @@ struct ibmvnic_adapter { u8 map_id; struct work_struct vnic_crq_init; + struct work_struct ibmvnic_xport; bool failover; }; -- GitLab From ff57087f314be8d458dca6bdd41be5b4236482a0 Mon Sep 17 00:00:00 2001 From: shamir rabinovitch Date: Thu, 27 Oct 2016 05:46:38 -0400 Subject: [PATCH 1146/1167] rds: debug messages are enabled by default rds use Kconfig option called "RDS_DEBUG" to enable rds debug messages. This option cause the rds Makefile to add -DDEBUG to the rds gcc command line. When CONFIG_DYNAMIC_DEBUG is enabled, the "DEBUG" macro is used by include/linux/dynamic_debug.h to decide if dynamic debug prints should be sent by default to the kernel log. rds should not enable this macro for production builds. rds dynamic debug work as expected follow this fix. Signed-off-by: Shamir Rabinovitch Acked-by: Santosh Shilimkar Reviewed-by: Wengang Wang Signed-off-by: David S. Miller --- net/rds/Makefile | 2 +- net/rds/rds.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/rds/Makefile b/net/rds/Makefile index 0e72bec1529f5..56c7d27eefee7 100644 --- a/net/rds/Makefile +++ b/net/rds/Makefile @@ -13,5 +13,5 @@ obj-$(CONFIG_RDS_TCP) += rds_tcp.o rds_tcp-y := tcp.o tcp_connect.o tcp_listen.o tcp_recv.o \ tcp_send.o tcp_stats.o -ccflags-$(CONFIG_RDS_DEBUG) := -DDEBUG +ccflags-$(CONFIG_RDS_DEBUG) := -DRDS_DEBUG diff --git a/net/rds/rds.h b/net/rds/rds.h index fd0bccb2f9f9d..67ba67c058b1b 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -33,7 +33,7 @@ #define KERNEL_HAS_ATOMIC64 #endif -#ifdef DEBUG +#ifdef RDS_DEBUG #define rdsdebug(fmt, args...) pr_debug("%s(): " fmt, __func__ , ##args) #else /* sigh, pr_debug() causes unused variable warnings */ -- GitLab From aa0c08feae8161b945520ada753d0dfe62b14fe7 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 27 Oct 2016 16:27:13 +0300 Subject: [PATCH 1147/1167] net/mlx4_core: Fix the resource-type enum in res tracker to conform to FW spec The resource type enum in the resource tracker was incorrect. RES_EQ was put in the position of RES_NPORT_ID (a FC resource). Since the remaining resources maintain their current values, and RES_EQ is not passed from slaves to the hypervisor in any FW command, this change affects only the hypervisor. Therefore, there is no backwards-compatibility issue. Fixes: 623ed84b1f95 ("mlx4_core: initial header-file changes for SRIOV support") Signed-off-by: Jack Morgenstein Signed-off-by: Moshe Shemesh Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index e4878f31e45d7..7aad07644289b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -145,9 +145,10 @@ enum mlx4_resource { RES_MTT, RES_MAC, RES_VLAN, - RES_EQ, + RES_NPORT_ID, RES_COUNTER, RES_FS_RULE, + RES_EQ, MLX4_NUM_OF_RESOURCE_TYPE }; -- GitLab From 33a1f8b196dca933313c001866c4df3f3ca11f78 Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Thu, 27 Oct 2016 16:27:14 +0300 Subject: [PATCH 1148/1167] net/mlx4_core: Avoid setting ports to auto when only one port type is supported When only one port type is supported, it should be read only. We reject changing requests, even to the auto sense mode. Fixes: 27bf91d6a0d5 ("mlx4_core: Add link type autosensing") Signed-off-by: Maor Gottlieb Signed-off-by: Moshe Shemesh Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 7183ac4135d2f..6f4e67bc35382 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -1102,6 +1102,14 @@ static int __set_port_type(struct mlx4_port_info *info, int i; int err = 0; + if ((port_type & mdev->caps.supported_type[info->port]) != port_type) { + mlx4_err(mdev, + "Requested port type for port %d is not supported on this HCA\n", + info->port); + err = -EINVAL; + goto err_sup; + } + mlx4_stop_sense(mdev); mutex_lock(&priv->port_mutex); info->tmp_type = port_type; @@ -1147,7 +1155,7 @@ static int __set_port_type(struct mlx4_port_info *info, out: mlx4_start_sense(mdev); mutex_unlock(&priv->port_mutex); - +err_sup: return err; } -- GitLab From 72da2e911f79d4c7132d7431a97d46659ee862be Mon Sep 17 00:00:00 2001 From: Moshe Lazer Date: Thu, 27 Oct 2016 16:27:15 +0300 Subject: [PATCH 1149/1167] net/mlx4_core: Change the default value of enable_qos Change the default status of quality of service back to disabled, as it hurts performance in some cases. Fixes: 38438f7c7e8c ("net/mlx4: Set enhanced QoS support by default when ...") Signed-off-by: Moshe Lazer Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index c41ab31a39f8c..84bab9f0732ea 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -49,9 +49,9 @@ enum { extern void __buggy_use_of_MLX4_GET(void); extern void __buggy_use_of_MLX4_PUT(void); -static bool enable_qos = true; +static bool enable_qos; module_param(enable_qos, bool, 0444); -MODULE_PARM_DESC(enable_qos, "Enable Enhanced QoS support (default: on)"); +MODULE_PARM_DESC(enable_qos, "Enable Enhanced QoS support (default: off)"); #define MLX4_GET(dest, source, offset) \ do { \ -- GitLab From 4850cf4581578216468b7b3c3d06cc5abb0a697d Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Thu, 27 Oct 2016 16:27:16 +0300 Subject: [PATCH 1150/1167] net/mlx4_en: Resolve dividing by zero in 32-bit system When doing roundup_pow_of_two for large enough number with bit 31, an overflow will occur and a value equal to 1 will be returned. In this case 1 will be subtracted from the return value and division by zero will be reached. Fixes: 31c128b66e5b ("net/mlx4_en: Choose time-stamping shift value according to HW frequency") Signed-off-by: Eugenia Emantayev Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_clock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c index 08fc5fc56d43b..a5fc46bbcbe22 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c @@ -245,8 +245,11 @@ static u32 freq_to_shift(u16 freq) { u32 freq_khz = freq * 1000; u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC; + u64 tmp_rounded = + roundup_pow_of_two(max_val_cycles) > max_val_cycles ? + roundup_pow_of_two(max_val_cycles) - 1 : UINT_MAX; u64 max_val_cycles_rounded = is_power_of_2(max_val_cycles + 1) ? - max_val_cycles : roundup_pow_of_two(max_val_cycles) - 1; + max_val_cycles : tmp_rounded; /* calculate max possible multiplier in order to fit in 64bit */ u64 max_mul = div_u64(0xffffffffffffffffULL, max_val_cycles_rounded); -- GitLab From 8d59de8f7bb3db296331c665779c653b0c8d13ba Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Thu, 27 Oct 2016 16:27:17 +0300 Subject: [PATCH 1151/1167] net/mlx4_en: Process all completions in RX rings after port goes up Currently there is a race between incoming traffic and initialization flow. HW is able to receive the packets after INIT_PORT is done and unicast steering is configured. Before we set priv->port_up NAPI is not scheduled and receive queues become full. Therefore we never get new interrupts about the completions. This issue could happen if running heavy traffic during bringing port up. The resolution is to schedule NAPI once port_up is set. If receive queues were full this will process all cqes and release them. Fixes: c27a02cd94d6 ("mlx4_en: Add driver for Mellanox ConnectX 10GbE NIC") Signed-off-by: Erez Shitrit Signed-off-by: Eugenia Emantayev Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 7e703bed7b820..e25c11dff525d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1733,6 +1733,13 @@ int mlx4_en_start_port(struct net_device *dev) udp_tunnel_get_rx_info(dev); priv->port_up = true; + + /* Process all completions if exist to prevent + * the queues freezing if they are full + */ + for (i = 0; i < priv->rx_ring_num; i++) + napi_schedule(&priv->rx_cq[i]->napi); + netif_tx_start_all_queues(dev); netif_device_attach(dev); -- GitLab From 9d2afba058722d40cc02f430229c91611c0e8d16 Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Thu, 27 Oct 2016 16:27:18 +0300 Subject: [PATCH 1152/1167] net/mlx4_en: Fix panic during reboot Fix a kernel panic that occurs as a result of an asynchronous event handled in roce_gid_mgmt: mlx4_en_get_drvinfo is called and accesses freed resources. This happens in a shutdown flow only, since pci device is destroyed while netdevice is still alive. Fixes: c27a02cd94d6 ("mlx4_en: Add driver for Mellanox ConnectX 10GbE NIC") Signed-off-by: Eugenia Emantayev Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index e25c11dff525d..314f54c8dbede 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2201,6 +2201,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) if (!shutdown) free_netdev(dev); + dev->ethtool_ops = NULL; } static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) -- GitLab From 81d184199e328fdad5633da139a10337327154e0 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 27 Oct 2016 16:27:19 +0300 Subject: [PATCH 1153/1167] net/mlx4_core: Do not access comm channel if it has not yet been initialized In the Hypervisor, there are several FW commands which are invoked before the comm channel is initialized (in mlx4_multi_func_init). These include MOD_STAT_CONFIG, QUERY_DEV_CAP, INIT_HCA, and others. If any of these commands fails, say with a timeout, the Hypervisor driver enters the internal error reset flow. In this flow, the driver attempts to notify all slaves via the comm channel that an internal error has occurred. Since the comm channel has not yet been initialized (i.e., mapped via ioremap), this will cause dereferencing a NULL pointer. To fix this, do not access the comm channel in the internal error flow if it has not yet been initialized. Fixes: 55ad359225b2 ("net/mlx4_core: Enable device recovery flow with SRIOV") Fixes: ab9c17a009ee ("mlx4_core: Modify driver initialization flow to accommodate SRIOV for Ethernet") Signed-off-by: Jack Morgenstein Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index b1cef7a0f7ca6..e36bebcab3f22 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -2469,6 +2469,7 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) kfree(priv->mfunc.master.slave_state); err_comm: iounmap(priv->mfunc.comm); + priv->mfunc.comm = NULL; err_vhcr: dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, priv->mfunc.vhcr, @@ -2537,6 +2538,13 @@ void mlx4_report_internal_err_comm_event(struct mlx4_dev *dev) int slave; u32 slave_read; + /* If the comm channel has not yet been initialized, + * skip reporting the internal error event to all + * the communication channels. + */ + if (!priv->mfunc.comm) + return; + /* Report an internal error event to all * communication channels. */ @@ -2571,6 +2579,7 @@ void mlx4_multi_func_cleanup(struct mlx4_dev *dev) } iounmap(priv->mfunc.comm); + priv->mfunc.comm = NULL; } void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask) -- GitLab From 6f2e0d2c3bf0f8d322ab7516c57340c7189cca02 Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Thu, 27 Oct 2016 16:27:20 +0300 Subject: [PATCH 1154/1167] net/mlx4: Fix firmware command timeout during interrupt test Currently interrupt test that is part of ethtool selftest runs the check over all interrupt vectors of the device. In mlx4_en package part of interrupt vectors are uninitialized since mlx4_ib doesn't exist. This causes NOP FW command to time out. Change logic to test current port interrupt vectors only. Signed-off-by: Eugenia Emantayev Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx4/en_selftest.c | 26 +++++++- drivers/net/ethernet/mellanox/mlx4/eq.c | 62 +++++++++---------- include/linux/mlx4/device.h | 3 +- 3 files changed, 55 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c index b66e03d9711f9..c06346a824968 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c @@ -118,6 +118,29 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv) return !loopback_ok; } +static int mlx4_en_test_interrupts(struct mlx4_en_priv *priv) +{ + struct mlx4_en_dev *mdev = priv->mdev; + int err = 0; + int i = 0; + + err = mlx4_test_async(mdev->dev); + /* When not in MSI_X or slave, test only async */ + if (!(mdev->dev->flags & MLX4_FLAG_MSI_X) || mlx4_is_slave(mdev->dev)) + return err; + + /* A loop over all completion vectors of current port, + * for each vector check whether it works by mapping command + * completions to that vector and performing a NOP command + */ + for (i = 0; i < priv->rx_ring_num; i++) { + err = mlx4_test_interrupt(mdev->dev, priv->rx_cq[i]->vector); + if (err) + break; + } + + return err; +} static int mlx4_en_test_link(struct mlx4_en_priv *priv) { @@ -151,7 +174,6 @@ static int mlx4_en_test_speed(struct mlx4_en_priv *priv) void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; int i, carrier_ok; memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST); @@ -177,7 +199,7 @@ void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf) netif_carrier_on(dev); } - buf[0] = mlx4_test_interrupts(mdev->dev); + buf[0] = mlx4_en_test_interrupts(priv); buf[1] = mlx4_en_test_link(priv); buf[2] = mlx4_en_test_speed(priv); diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index cf8f8a72a8015..cd3638e6fe25b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -1361,53 +1361,49 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) kfree(priv->eq_table.uar_map); } -/* A test that verifies that we can accept interrupts on all - * the irq vectors of the device. +/* A test that verifies that we can accept interrupts + * on the vector allocated for asynchronous events + */ +int mlx4_test_async(struct mlx4_dev *dev) +{ + return mlx4_NOP(dev); +} +EXPORT_SYMBOL(mlx4_test_async); + +/* A test that verifies that we can accept interrupts + * on the given irq vector of the tested port. * Interrupts are checked using the NOP command. */ -int mlx4_test_interrupts(struct mlx4_dev *dev) +int mlx4_test_interrupt(struct mlx4_dev *dev, int vector) { struct mlx4_priv *priv = mlx4_priv(dev); - int i; int err; - err = mlx4_NOP(dev); - /* When not in MSI_X, there is only one irq to check */ - if (!(dev->flags & MLX4_FLAG_MSI_X) || mlx4_is_slave(dev)) - return err; - - /* A loop over all completion vectors, for each vector we will check - * whether it works by mapping command completions to that vector - * and performing a NOP command - */ - for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) { - /* Make sure request_irq was called */ - if (!priv->eq_table.eq[i].have_irq) - continue; - - /* Temporary use polling for command completions */ - mlx4_cmd_use_polling(dev); - - /* Map the new eq to handle all asynchronous events */ - err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, - priv->eq_table.eq[i].eqn); - if (err) { - mlx4_warn(dev, "Failed mapping eq for interrupt test\n"); - mlx4_cmd_use_events(dev); - break; - } + /* Temporary use polling for command completions */ + mlx4_cmd_use_polling(dev); - /* Go back to using events */ - mlx4_cmd_use_events(dev); - err = mlx4_NOP(dev); + /* Map the new eq to handle all asynchronous events */ + err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, + priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].eqn); + if (err) { + mlx4_warn(dev, "Failed mapping eq for interrupt test\n"); + goto out; } + /* Go back to using events */ + mlx4_cmd_use_events(dev); + err = mlx4_NOP(dev); + /* Return to default */ + mlx4_cmd_use_polling(dev); +out: mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); + mlx4_cmd_use_events(dev); + return err; } -EXPORT_SYMBOL(mlx4_test_interrupts); +EXPORT_SYMBOL(mlx4_test_interrupt); bool mlx4_is_eq_vector_valid(struct mlx4_dev *dev, u8 port, int vector) { diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index f6a1642973581..3be7abd6e722d 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -1399,7 +1399,8 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u32 *lkey, u32 *rkey); int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); int mlx4_SYNC_TPT(struct mlx4_dev *dev); -int mlx4_test_interrupts(struct mlx4_dev *dev); +int mlx4_test_interrupt(struct mlx4_dev *dev, int vector); +int mlx4_test_async(struct mlx4_dev *dev); int mlx4_query_diag_counters(struct mlx4_dev *dev, u8 op_modifier, const u32 offset[], u32 value[], size_t array_len, u8 port); -- GitLab From d2582a03939ed0a80ffcd3ea5345505bc8067c54 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 27 Oct 2016 16:27:21 +0300 Subject: [PATCH 1155/1167] net/mlx4_en: Fix potential deadlock in port statistics flow mlx4_en_DUMP_ETH_STATS took the *counter mutex* and then called the FW command, with WRAPPED attribute. As a result, the fw command is wrapped on the Hypervisor when it calls mlx4_en_DUMP_ETH_STATS. The FW command wrapper flow on the hypervisor takes the *slave_cmd_mutex* during processing. At the same time, a VF could be in the process of coming up, and could call mlx4_QUERY_FUNC_CAP. On the hypervisor, the command flow takes the *slave_cmd_mutex*, then executes mlx4_QUERY_FUNC_CAP_wrapper. mlx4_QUERY_FUNC_CAP wrapper calls mlx4_get_default_counter_index(), which takes the *counter mutex*. DEADLOCK. The fix is that the DUMP_ETH_STATS fw command should be called with the NATIVE attribute, so that on the hypervisor, this command does not enter the wrapper flow. Since the Hypervisor no longer goes through the wrapper code, we also simply return 0 in mlx4_DUMP_ETH_STATS_wrapper (i.e.the function succeeds, but the returned data will be all zeroes). No need to test if it is the Hypervisor going through the wrapper. Fixes: f9baff509f8a ("mlx4_core: Add "native" argument to mlx4_cmd ...") Signed-off-by: Jack Morgenstein Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_port.c | 4 ++-- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 2 -- drivers/net/ethernet/mellanox/mlx4/port.c | 13 +------------ 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c index 5aa8b751f4170..59473a0ebcdfe 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_port.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c @@ -166,7 +166,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) return PTR_ERR(mailbox); err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, in_mod, 0, MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); + MLX4_CMD_NATIVE); if (err) goto out; @@ -322,7 +322,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, in_mod | MLX4_DUMP_ETH_STATS_FLOW_CONTROL, 0, MLX4_CMD_DUMP_ETH_STATS, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); if (err) goto out; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 7aad07644289b..88ee7d8a59231 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -1330,8 +1330,6 @@ int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_cmd_info *cmd); int mlx4_common_set_vlan_fltr(struct mlx4_dev *dev, int function, int port, void *buf); -int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave, u32 in_mod, - struct mlx4_cmd_mailbox *outbox); int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index c5b2064297a19..b656dd5772e5b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -1728,24 +1728,13 @@ int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, return err; } -int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave, - u32 in_mod, struct mlx4_cmd_mailbox *outbox) -{ - return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0, - MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); -} - int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, struct mlx4_cmd_mailbox *outbox, struct mlx4_cmd_info *cmd) { - if (slave != dev->caps.function) - return 0; - return mlx4_common_dump_eth_stats(dev, slave, - vhcr->in_modifier, outbox); + return 0; } int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, -- GitLab From eb4b678825992aa434d32b2f615d2090281e0f88 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 27 Oct 2016 16:27:22 +0300 Subject: [PATCH 1156/1167] net/mlx4_en: Save slave ethtool stats command Following the previous patch, as an optimization, the slave will not even bother sending the DUMP_ETH_STATS command over the comm channel. Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 314f54c8dbede..12c99a2655f26 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1917,8 +1917,9 @@ static void mlx4_en_clear_stats(struct net_device *dev) struct mlx4_en_dev *mdev = priv->mdev; int i; - if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) - en_dbg(HW, priv, "Failed dumping statistics\n"); + if (!mlx4_is_slave(mdev->dev)) + if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) + en_dbg(HW, priv, "Failed dumping statistics\n"); memset(&priv->pstats, 0, sizeof(priv->pstats)); memset(&priv->pkstats, 0, sizeof(priv->pkstats)); -- GitLab From a909d3e636995ba7c349e2ca5dbb528154d4ac30 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 29 Oct 2016 13:52:02 -0700 Subject: [PATCH 1157/1167] Linux 4.9-rc3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 93beca4312c48..a2650f9c6a259 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 9 SUBLEVEL = 0 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Psychotic Stoned Sheep # *DOCUMENTATION* -- GitLab From f9d4286b9516b02e795214412d36885f572b57ad Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Thu, 27 Oct 2016 16:30:06 +0200 Subject: [PATCH 1158/1167] arch/powerpc: Update parameters for csum_tcpudp_magic & csum_tcpudp_nofold Commit 01cfbad "ipv4: Update parameters for csum_tcpudp_magic to their original types" changed parameters for csum_tcpudp_magic and csum_tcpudp_nofold for many platforms but not for PowerPC. Fixes: 01cfbad "ipv4: Update parameters for csum_tcpudp_magic to their original types" Cc: Alexander Duyck Signed-off-by: Ivan Vecera Acked-by: Alexander Duyck Signed-off-by: David S. Miller --- arch/powerpc/include/asm/checksum.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/include/asm/checksum.h b/arch/powerpc/include/asm/checksum.h index ee655ed1ff1bc..1e8fceb308a51 100644 --- a/arch/powerpc/include/asm/checksum.h +++ b/arch/powerpc/include/asm/checksum.h @@ -53,10 +53,8 @@ static inline __sum16 csum_fold(__wsum sum) return (__force __sum16)(~((__force u32)sum + tmp) >> 16); } -static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, - unsigned short len, - unsigned short proto, - __wsum sum) +static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, + __u8 proto, __wsum sum) { #ifdef __powerpc64__ unsigned long s = (__force u32)sum; @@ -83,10 +81,8 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, * computes the checksum of the TCP/UDP pseudo-header * returns a 16-bit checksum, already complemented */ -static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, - unsigned short len, - unsigned short proto, - __wsum sum) +static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len, + __u8 proto, __wsum sum) { return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); } -- GitLab From dbc34e73c2bee4ff66c3a6b0ea5d65c25a6b6994 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 29 Oct 2016 17:18:17 -0400 Subject: [PATCH 1159/1167] Revert "ibmvnic: Fix releasing of sub-CRQ IRQs in interrupt context" This reverts commit 8d7533e5aaad1c94386a8101a36b0617987966b7. It introduced kbuild failures, new version coming. Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 35 ++++++++++-------------------- drivers/net/ethernet/ibm/ibmvnic.h | 1 - 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 0459d19a5f163..213162df1a9bf 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3232,27 +3232,6 @@ static void ibmvnic_free_inflight(struct ibmvnic_adapter *adapter) spin_unlock_irqrestore(&adapter->inflight_lock, flags); } -static void ibmvnic_xport_event(struct work_struct *work) -{ - struct ibmvnic_adapter *adapter = container_of(work, - struct ibmvnic_adapter, - ibmvnic_xport); - struct device *dev = &adapter->vdev->dev; - int rc; - - ibmvnic_free_inflight(adapter); - release_sub_crqs(adapter); - if (adapter->migrated) { - rc = ibmvnic_reenable_crq_queue(adapter); - if (rc) - dev_err(dev, "Error after enable rc=%ld\n", rc); - adapter->migrated = false; - rc = ibmvnic_send_crq_init(adapter); - if (rc) - dev_err(dev, "Error sending init rc=%ld\n", rc); - } -} - static void ibmvnic_handle_crq(union ibmvnic_crq *crq, struct ibmvnic_adapter *adapter) { @@ -3288,7 +3267,15 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) { dev_info(dev, "Re-enabling adapter\n"); adapter->migrated = true; - schedule_work(&adapter->ibmvnic_xport); + ibmvnic_free_inflight(adapter); + release_sub_crqs(adapter); + rc = ibmvnic_reenable_crq_queue(adapter); + if (rc) + dev_err(dev, "Error after enable rc=%ld\n", rc); + adapter->migrated = false; + rc = ibmvnic_send_crq_init(adapter); + if (rc) + dev_err(dev, "Error sending init rc=%ld\n", rc); } else if (gen_crq->cmd == IBMVNIC_DEVICE_FAILOVER) { dev_info(dev, "Backing device failover detected\n"); netif_carrier_off(netdev); @@ -3297,7 +3284,8 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, /* The adapter lost the connection */ dev_err(dev, "Virtual Adapter failed (rc=%d)\n", gen_crq->cmd); - schedule_work(&adapter->ibmvnic_xport); + ibmvnic_free_inflight(adapter); + release_sub_crqs(adapter); } return; case IBMVNIC_CRQ_CMD_RSP: @@ -3738,7 +3726,6 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) SET_NETDEV_DEV(netdev, &dev->dev); INIT_WORK(&adapter->vnic_crq_init, handle_crq_init_rsp); - INIT_WORK(&adapter->ibmvnic_xport, ibmvnic_xport_event); spin_lock_init(&adapter->stats_lock); diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index dd775d951b739..878e2c059f5c8 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1048,6 +1048,5 @@ struct ibmvnic_adapter { u8 map_id; struct work_struct vnic_crq_init; - struct work_struct ibmvnic_xport; bool failover; }; -- GitLab From 9888d7b02c7793cbbcbdd05dd9e14cc0e78d1db7 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Thu, 27 Oct 2016 12:28:51 -0500 Subject: [PATCH 1160/1167] ibmvnic: Fix releasing of sub-CRQ IRQs in interrupt context Schedule these XPORT event tasks in the shared workqueue so that IRQs are not freed in an interrupt context when sub-CRQs are released. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 35 ++++++++++++++++++++---------- drivers/net/ethernet/ibm/ibmvnic.h | 1 + 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 213162df1a9bf..a922fb94fcebe 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3232,6 +3232,27 @@ static void ibmvnic_free_inflight(struct ibmvnic_adapter *adapter) spin_unlock_irqrestore(&adapter->inflight_lock, flags); } +static void ibmvnic_xport_event(struct work_struct *work) +{ + struct ibmvnic_adapter *adapter = container_of(work, + struct ibmvnic_adapter, + ibmvnic_xport); + struct device *dev = &adapter->vdev->dev; + long rc; + + ibmvnic_free_inflight(adapter); + release_sub_crqs(adapter); + if (adapter->migrated) { + rc = ibmvnic_reenable_crq_queue(adapter); + if (rc) + dev_err(dev, "Error after enable rc=%ld\n", rc); + adapter->migrated = false; + rc = ibmvnic_send_crq_init(adapter); + if (rc) + dev_err(dev, "Error sending init rc=%ld\n", rc); + } +} + static void ibmvnic_handle_crq(union ibmvnic_crq *crq, struct ibmvnic_adapter *adapter) { @@ -3267,15 +3288,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) { dev_info(dev, "Re-enabling adapter\n"); adapter->migrated = true; - ibmvnic_free_inflight(adapter); - release_sub_crqs(adapter); - rc = ibmvnic_reenable_crq_queue(adapter); - if (rc) - dev_err(dev, "Error after enable rc=%ld\n", rc); - adapter->migrated = false; - rc = ibmvnic_send_crq_init(adapter); - if (rc) - dev_err(dev, "Error sending init rc=%ld\n", rc); + schedule_work(&adapter->ibmvnic_xport); } else if (gen_crq->cmd == IBMVNIC_DEVICE_FAILOVER) { dev_info(dev, "Backing device failover detected\n"); netif_carrier_off(netdev); @@ -3284,8 +3297,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, /* The adapter lost the connection */ dev_err(dev, "Virtual Adapter failed (rc=%d)\n", gen_crq->cmd); - ibmvnic_free_inflight(adapter); - release_sub_crqs(adapter); + schedule_work(&adapter->ibmvnic_xport); } return; case IBMVNIC_CRQ_CMD_RSP: @@ -3726,6 +3738,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) SET_NETDEV_DEV(netdev, &dev->dev); INIT_WORK(&adapter->vnic_crq_init, handle_crq_init_rsp); + INIT_WORK(&adapter->ibmvnic_xport, ibmvnic_xport_event); spin_lock_init(&adapter->stats_lock); diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 878e2c059f5c8..dd775d951b739 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1048,5 +1048,6 @@ struct ibmvnic_adapter { u8 map_id; struct work_struct vnic_crq_init; + struct work_struct ibmvnic_xport; bool failover; }; -- GitLab From 8bf371e6adff29758cc3c57c17df4486513081f8 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Thu, 27 Oct 2016 12:28:52 -0500 Subject: [PATCH 1161/1167] ibmvnic: Fix missing brackets in init_sub_crq_irqs Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index a922fb94fcebe..5f44c5520fbc8 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1461,14 +1461,16 @@ static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter) return rc; req_rx_irq_failed: - for (j = 0; j < i; j++) + for (j = 0; j < i; j++) { free_irq(adapter->rx_scrq[j]->irq, adapter->rx_scrq[j]); irq_dispose_mapping(adapter->rx_scrq[j]->irq); + } i = adapter->req_tx_queues; req_tx_irq_failed: - for (j = 0; j < i; j++) + for (j = 0; j < i; j++) { free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]); irq_dispose_mapping(adapter->rx_scrq[j]->irq); + } release_sub_crqs_no_irqs(adapter); return rc; } -- GitLab From 06bd2b1ed04ca9fdbc767859885944a1e8b86b40 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 27 Oct 2016 18:51:55 -0400 Subject: [PATCH 1162/1167] tipc: fix broadcast link synchronization problem In commit 2d18ac4ba745 ("tipc: extend broadcast link initialization criteria") we tried to fix a problem with the initial synchronization of broadcast link acknowledge values. Unfortunately that solution is not sufficient to solve the issue. We have seen it happen that LINK_PROTOCOL/STATE packets with a valid non-zero unicast acknowledge number may bypass BCAST_PROTOCOL initialization, NAME_DISTRIBUTOR and other STATE packets with invalid broadcast acknowledge numbers, leading to premature opening of the broadcast link. When the bypassed packets finally arrive, they are inadvertently accepted, and the already correctly initialized acknowledge number in the broadcast receive link is overwritten by the invalid (zero) value of the said packets. After this the broadcast link goes stale. We now fix this by marking the packets where we know the acknowledge value is or may be invalid, and then ignoring the acks from those. To this purpose, we claim an unused bit in the header to indicate that the value is invalid. We set the bit to 1 in the initial BCAST_PROTOCOL synchronization packet and all initial ("bulk") NAME_DISTRIBUTOR packets, plus those LINK_PROTOCOL packets sent out before the broadcast links are fully synchronized. This minor protocol update is fully backwards compatible. Reported-by: John Thompson Tested-by: John Thompson Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bcast.c | 14 ++++++++++---- net/tipc/bcast.h | 3 ++- net/tipc/link.c | 2 ++ net/tipc/msg.h | 17 +++++++++++++++++ net/tipc/name_distr.c | 1 + net/tipc/node.c | 2 +- 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 753f774cb46f3..aa1babbea3853 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -247,11 +247,17 @@ int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb) * * RCU is locked, no other locks set */ -void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, u32 acked) +void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, + struct tipc_msg *hdr) { struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq; + u16 acked = msg_bcast_ack(hdr); struct sk_buff_head xmitq; + /* Ignore bc acks sent by peer before bcast synch point was received */ + if (msg_bc_ack_invalid(hdr)) + return; + __skb_queue_head_init(&xmitq); tipc_bcast_lock(net); @@ -279,11 +285,11 @@ int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l, __skb_queue_head_init(&xmitq); tipc_bcast_lock(net); - if (msg_type(hdr) == STATE_MSG) { + if (msg_type(hdr) != STATE_MSG) { + tipc_link_bc_init_rcv(l, hdr); + } else if (!msg_bc_ack_invalid(hdr)) { tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), &xmitq); rc = tipc_link_bc_sync_rcv(l, hdr, &xmitq); - } else { - tipc_link_bc_init_rcv(l, hdr); } tipc_bcast_unlock(net); diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index 5ffe34472ccd0..855d53c64ab34 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -55,7 +55,8 @@ void tipc_bcast_dec_bearer_dst_cnt(struct net *net, int bearer_id); int tipc_bcast_get_mtu(struct net *net); int tipc_bcast_xmit(struct net *net, struct sk_buff_head *list); int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb); -void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, u32 acked); +void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, + struct tipc_msg *hdr); int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l, struct tipc_msg *hdr); int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg); diff --git a/net/tipc/link.c b/net/tipc/link.c index b36e16cdc9452..1055164c6232d 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1312,6 +1312,7 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, msg_set_next_sent(hdr, l->snd_nxt); msg_set_ack(hdr, l->rcv_nxt - 1); msg_set_bcast_ack(hdr, bcl->rcv_nxt - 1); + msg_set_bc_ack_invalid(hdr, !node_up); msg_set_last_bcast(hdr, l->bc_sndlink->snd_nxt - 1); msg_set_link_tolerance(hdr, tolerance); msg_set_linkprio(hdr, priority); @@ -1574,6 +1575,7 @@ static void tipc_link_build_bc_init_msg(struct tipc_link *l, __skb_queue_head_init(&list); if (!tipc_link_build_bc_proto_msg(l->bc_rcvlink, false, 0, &list)) return; + msg_set_bc_ack_invalid(buf_msg(skb_peek(&list)), true); tipc_link_xmit(l, &list, xmitq); } diff --git a/net/tipc/msg.h b/net/tipc/msg.h index c3832cdf2278a..50a739860d379 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -714,6 +714,23 @@ static inline void msg_set_peer_stopping(struct tipc_msg *m, u32 s) msg_set_bits(m, 5, 13, 0x1, s); } +static inline bool msg_bc_ack_invalid(struct tipc_msg *m) +{ + switch (msg_user(m)) { + case BCAST_PROTOCOL: + case NAME_DISTRIBUTOR: + case LINK_PROTOCOL: + return msg_bits(m, 5, 14, 0x1); + default: + return false; + } +} + +static inline void msg_set_bc_ack_invalid(struct tipc_msg *m, bool invalid) +{ + msg_set_bits(m, 5, 14, 0x1, invalid); +} + static inline char *msg_media_addr(struct tipc_msg *m) { return (char *)&m->hdr[TIPC_MEDIA_INFO_OFFSET]; diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index a04fe9be1c60e..c1cfd92de17ae 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -156,6 +156,7 @@ static void named_distribute(struct net *net, struct sk_buff_head *list, pr_warn("Bulk publication failure\n"); return; } + msg_set_bc_ack_invalid(buf_msg(skb), true); item = (struct distr_item *)msg_data(buf_msg(skb)); } diff --git a/net/tipc/node.c b/net/tipc/node.c index 7ef14e2d23565..9d2f4c2b08abc 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -1535,7 +1535,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b) if (unlikely(usr == LINK_PROTOCOL)) tipc_node_bc_sync_rcv(n, hdr, bearer_id, &xmitq); else if (unlikely(tipc_link_acked(n->bc_entry.link) != bc_ack)) - tipc_bcast_ack_rcv(net, n->bc_entry.link, bc_ack); + tipc_bcast_ack_rcv(net, n->bc_entry.link, hdr); /* Receive packet directly if conditions permit */ tipc_node_read_lock(n); -- GitLab From 9fe1c98ac90023842ae7cd921badfa1029e45bd1 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan Date: Thu, 27 Oct 2016 16:01:03 -0700 Subject: [PATCH 1163/1167] enic: fix rq disable When MTU is changed from 9000 to 1500 while there is burst of inbound 9000 bytes packets, adaptor sometimes delivers 9000 bytes packets to 1500 bytes buffers. This causes memory corruption and sometimes crash. This is because of a race condition in adaptor between "RQ disable" clearing descriptor mini-cache and mini-cache valid bit being set by completion of descriptor fetch. This can result in stale RQ desc being cached and used when packets arrive. In this case, the stale descriptor have old MTU value. Solution is to write RQ->disable twice. The first write will stop any further desc fetches, allowing the second disable to clear the mini-cache valid bit without danger of a race. Also, the check for rq->running becoming 0 after writing rq->enable to 0 is not done properly. When incoming packets are flooding the interface, rq->running will pulse high for each dropped packet. Since the driver was waiting for 10us between each poll, it is possible to see rq->running = 1 1000 times in a row, even though it is not actually stuck running. This results in false failure of vnic_rq_disable(). Fix is to try more than 1000 time without delay between polls to ensure we do not miss when running goes low. In old adaptors rq->enable needs to be re-written to 0 when posted_index is reset in vnic_rq_clean() in order to keep rq->prefetch_index in sync. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/vnic_rq.c | 32 ++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/vnic_rq.c b/drivers/net/ethernet/cisco/enic/vnic_rq.c index e572a527b18dd..36bc2c71fba98 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_rq.c +++ b/drivers/net/ethernet/cisco/enic/vnic_rq.c @@ -169,19 +169,28 @@ int vnic_rq_disable(struct vnic_rq *rq) { unsigned int wait; struct vnic_dev *vdev = rq->vdev; + int i; - iowrite32(0, &rq->ctrl->enable); + /* Due to a race condition with clearing RQ "mini-cache" in hw, we need + * to disable the RQ twice to guarantee that stale descriptors are not + * used when this RQ is re-enabled. + */ + for (i = 0; i < 2; i++) { + iowrite32(0, &rq->ctrl->enable); - /* Wait for HW to ACK disable request */ - for (wait = 0; wait < 1000; wait++) { - if (!(ioread32(&rq->ctrl->running))) - return 0; - udelay(10); - } + /* Wait for HW to ACK disable request */ + for (wait = 20000; wait > 0; wait--) + if (!ioread32(&rq->ctrl->running)) + break; + if (!wait) { + vdev_neterr(vdev, "Failed to disable RQ[%d]\n", + rq->index); - vdev_neterr(vdev, "Failed to disable RQ[%d]\n", rq->index); + return -ETIMEDOUT; + } + } - return -ETIMEDOUT; + return 0; } void vnic_rq_clean(struct vnic_rq *rq, @@ -212,6 +221,11 @@ void vnic_rq_clean(struct vnic_rq *rq, [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES(count)]; iowrite32(fetch_index, &rq->ctrl->posted_index); + /* Anytime we write fetch_index, we need to re-write 0 to rq->enable + * to re-sync internal VIC state. + */ + iowrite32(0, &rq->ctrl->enable); + vnic_dev_clear_desc_ring(&rq->ring); } -- GitLab From 3034783472f5353f71af44ed52ad9ee65f9f6d17 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 28 Oct 2016 12:40:20 +0300 Subject: [PATCH 1164/1167] net: phy: dp83848: add dp83822 PHY support This PHY has a compatible register set with DP83848x so add support for it. Acked-by: Andrew F. Davis Signed-off-by: Roger Quadros Signed-off-by: David S. Miller --- drivers/net/phy/dp83848.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/phy/dp83848.c b/drivers/net/phy/dp83848.c index 03d54c4adc881..800b39f062794 100644 --- a/drivers/net/phy/dp83848.c +++ b/drivers/net/phy/dp83848.c @@ -19,6 +19,7 @@ #define TI_DP83848C_PHY_ID 0x20005ca0 #define NS_DP83848C_PHY_ID 0x20005c90 #define TLK10X_PHY_ID 0x2000a210 +#define TI_DP83822_PHY_ID 0x2000a240 /* Registers */ #define DP83848_MICR 0x11 /* MII Interrupt Control Register */ @@ -77,6 +78,7 @@ static struct mdio_device_id __maybe_unused dp83848_tbl[] = { { TI_DP83848C_PHY_ID, 0xfffffff0 }, { NS_DP83848C_PHY_ID, 0xfffffff0 }, { TLK10X_PHY_ID, 0xfffffff0 }, + { TI_DP83822_PHY_ID, 0xfffffff0 }, { } }; MODULE_DEVICE_TABLE(mdio, dp83848_tbl); @@ -105,6 +107,7 @@ static struct phy_driver dp83848_driver[] = { DP83848_PHY_DRIVER(TI_DP83848C_PHY_ID, "TI DP83848C 10/100 Mbps PHY"), DP83848_PHY_DRIVER(NS_DP83848C_PHY_ID, "NS DP83848C 10/100 Mbps PHY"), DP83848_PHY_DRIVER(TLK10X_PHY_ID, "TI TLK10X 10/100 Mbps PHY"), + DP83848_PHY_DRIVER(TI_DP83822_PHY_ID, "TI DP83822 10/100 Mbps PHY"), }; module_phy_driver(dp83848_driver); -- GitLab From 087892d29b75c025086d99b29d385a3dac0169fc Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sat, 29 Oct 2016 17:04:35 +0300 Subject: [PATCH 1165/1167] qede: Fix out-of-bound fastpath memory access Driver allocates a shadow array for transmitted SKBs with X entries; That means valid indices are {0,...,X - 1}. [X == 8191] Problem is the driver also uses X as a mask for a producer/consumer in order to choose the right entry in the array which allows access to entry X which is out of bounds. To fix this, simply allocate X + 1 entries in the shadow array. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 444b271059b22..7def29aaf65c9 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -2940,7 +2940,7 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) txq->num_tx_buffers = edev->q_num_tx_buffers; /* Allocate the parallel driver ring for Tx buffers */ - size = sizeof(*txq->sw_tx_ring) * NUM_TX_BDS_MAX; + size = sizeof(*txq->sw_tx_ring) * TX_RING_SIZE; txq->sw_tx_ring = kzalloc(size, GFP_KERNEL); if (!txq->sw_tx_ring) { DP_NOTICE(edev, "Tx buffers ring allocation failed\n"); @@ -2951,7 +2951,7 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) QED_CHAIN_USE_TO_CONSUME_PRODUCE, QED_CHAIN_MODE_PBL, QED_CHAIN_CNT_TYPE_U16, - NUM_TX_BDS_MAX, + TX_RING_SIZE, sizeof(*p_virt), &txq->tx_pbl); if (rc) goto err; -- GitLab From c6fcc4fc5f8b592600c7409e769ab68da0fb1eca Mon Sep 17 00:00:00 2001 From: pravin shelar Date: Fri, 28 Oct 2016 09:59:15 -0700 Subject: [PATCH 1166/1167] vxlan: avoid using stale vxlan socket. When vxlan device is closed vxlan socket is freed. This operation can race with vxlan-xmit function which dereferences vxlan socket. Following patch uses RCU mechanism to avoid this situation. Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 80 ++++++++++++++++++++++++++++----------------- include/net/vxlan.h | 4 +-- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index c1639a3e95a44..f3c2fa3ab0d54 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -943,17 +943,20 @@ static bool vxlan_snoop(struct net_device *dev, static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev) { struct vxlan_dev *vxlan; + struct vxlan_sock *sock4; + struct vxlan_sock *sock6 = NULL; unsigned short family = dev->default_dst.remote_ip.sa.sa_family; + sock4 = rtnl_dereference(dev->vn4_sock); + /* The vxlan_sock is only used by dev, leaving group has * no effect on other vxlan devices. */ - if (family == AF_INET && dev->vn4_sock && - atomic_read(&dev->vn4_sock->refcnt) == 1) + if (family == AF_INET && sock4 && atomic_read(&sock4->refcnt) == 1) return false; #if IS_ENABLED(CONFIG_IPV6) - if (family == AF_INET6 && dev->vn6_sock && - atomic_read(&dev->vn6_sock->refcnt) == 1) + sock6 = rtnl_dereference(dev->vn6_sock); + if (family == AF_INET6 && sock6 && atomic_read(&sock6->refcnt) == 1) return false; #endif @@ -961,10 +964,12 @@ static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev) if (!netif_running(vxlan->dev) || vxlan == dev) continue; - if (family == AF_INET && vxlan->vn4_sock != dev->vn4_sock) + if (family == AF_INET && + rtnl_dereference(vxlan->vn4_sock) != sock4) continue; #if IS_ENABLED(CONFIG_IPV6) - if (family == AF_INET6 && vxlan->vn6_sock != dev->vn6_sock) + if (family == AF_INET6 && + rtnl_dereference(vxlan->vn6_sock) != sock6) continue; #endif @@ -1005,22 +1010,25 @@ static bool __vxlan_sock_release_prep(struct vxlan_sock *vs) static void vxlan_sock_release(struct vxlan_dev *vxlan) { - bool ipv4 = __vxlan_sock_release_prep(vxlan->vn4_sock); + struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock); #if IS_ENABLED(CONFIG_IPV6) - bool ipv6 = __vxlan_sock_release_prep(vxlan->vn6_sock); + struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock); + + rcu_assign_pointer(vxlan->vn6_sock, NULL); #endif + rcu_assign_pointer(vxlan->vn4_sock, NULL); synchronize_net(); - if (ipv4) { - udp_tunnel_sock_release(vxlan->vn4_sock->sock); - kfree(vxlan->vn4_sock); + if (__vxlan_sock_release_prep(sock4)) { + udp_tunnel_sock_release(sock4->sock); + kfree(sock4); } #if IS_ENABLED(CONFIG_IPV6) - if (ipv6) { - udp_tunnel_sock_release(vxlan->vn6_sock->sock); - kfree(vxlan->vn6_sock); + if (__vxlan_sock_release_prep(sock6)) { + udp_tunnel_sock_release(sock6->sock); + kfree(sock6); } #endif } @@ -1036,18 +1044,21 @@ static int vxlan_igmp_join(struct vxlan_dev *vxlan) int ret = -EINVAL; if (ip->sa.sa_family == AF_INET) { + struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock); struct ip_mreqn mreq = { .imr_multiaddr.s_addr = ip->sin.sin_addr.s_addr, .imr_ifindex = ifindex, }; - sk = vxlan->vn4_sock->sock->sk; + sk = sock4->sock->sk; lock_sock(sk); ret = ip_mc_join_group(sk, &mreq); release_sock(sk); #if IS_ENABLED(CONFIG_IPV6) } else { - sk = vxlan->vn6_sock->sock->sk; + struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock); + + sk = sock6->sock->sk; lock_sock(sk); ret = ipv6_stub->ipv6_sock_mc_join(sk, ifindex, &ip->sin6.sin6_addr); @@ -1067,18 +1078,21 @@ static int vxlan_igmp_leave(struct vxlan_dev *vxlan) int ret = -EINVAL; if (ip->sa.sa_family == AF_INET) { + struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock); struct ip_mreqn mreq = { .imr_multiaddr.s_addr = ip->sin.sin_addr.s_addr, .imr_ifindex = ifindex, }; - sk = vxlan->vn4_sock->sock->sk; + sk = sock4->sock->sk; lock_sock(sk); ret = ip_mc_leave_group(sk, &mreq); release_sock(sk); #if IS_ENABLED(CONFIG_IPV6) } else { - sk = vxlan->vn6_sock->sock->sk; + struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock); + + sk = sock6->sock->sk; lock_sock(sk); ret = ipv6_stub->ipv6_sock_mc_drop(sk, ifindex, &ip->sin6.sin6_addr); @@ -1828,11 +1842,15 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan, struct dst_cache *dst_cache, const struct ip_tunnel_info *info) { + struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock); bool use_cache = ip_tunnel_dst_cache_usable(skb, info); struct dst_entry *ndst; struct flowi6 fl6; int err; + if (!sock6) + return ERR_PTR(-EIO); + if (tos && !info) use_cache = false; if (use_cache) { @@ -1850,7 +1868,7 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan, fl6.flowi6_proto = IPPROTO_UDP; err = ipv6_stub->ipv6_dst_lookup(vxlan->net, - vxlan->vn6_sock->sock->sk, + sock6->sock->sk, &ndst, &fl6); if (err < 0) return ERR_PTR(err); @@ -1995,9 +2013,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } if (dst->sa.sa_family == AF_INET) { - if (!vxlan->vn4_sock) + struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock); + + if (!sock4) goto drop; - sk = vxlan->vn4_sock->sock->sk; + sk = sock4->sock->sk; rt = vxlan_get_route(vxlan, skb, rdst ? rdst->remote_ifindex : 0, tos, @@ -2050,12 +2070,13 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, src_port, dst_port, xnet, !udp_sum); #if IS_ENABLED(CONFIG_IPV6) } else { + struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock); struct dst_entry *ndst; u32 rt6i_flags; - if (!vxlan->vn6_sock) + if (!sock6) goto drop; - sk = vxlan->vn6_sock->sock->sk; + sk = sock6->sock->sk; ndst = vxlan6_get_route(vxlan, skb, rdst ? rdst->remote_ifindex : 0, tos, @@ -2415,9 +2436,10 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) dport = info->key.tp_dst ? : vxlan->cfg.dst_port; if (ip_tunnel_info_af(info) == AF_INET) { + struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock); struct rtable *rt; - if (!vxlan->vn4_sock) + if (!sock4) return -EINVAL; rt = vxlan_get_route(vxlan, skb, 0, info->key.tos, info->key.u.ipv4.dst, @@ -2429,8 +2451,6 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) #if IS_ENABLED(CONFIG_IPV6) struct dst_entry *ndst; - if (!vxlan->vn6_sock) - return -EINVAL; ndst = vxlan6_get_route(vxlan, skb, 0, info->key.tos, info->key.label, &info->key.u.ipv6.dst, &info->key.u.ipv6.src, NULL, info); @@ -2740,10 +2760,10 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) return PTR_ERR(vs); #if IS_ENABLED(CONFIG_IPV6) if (ipv6) - vxlan->vn6_sock = vs; + rcu_assign_pointer(vxlan->vn6_sock, vs); else #endif - vxlan->vn4_sock = vs; + rcu_assign_pointer(vxlan->vn4_sock, vs); vxlan_vs_add_dev(vs, vxlan); return 0; } @@ -2754,9 +2774,9 @@ static int vxlan_sock_add(struct vxlan_dev *vxlan) bool metadata = vxlan->flags & VXLAN_F_COLLECT_METADATA; int ret = 0; - vxlan->vn4_sock = NULL; + RCU_INIT_POINTER(vxlan->vn4_sock, NULL); #if IS_ENABLED(CONFIG_IPV6) - vxlan->vn6_sock = NULL; + RCU_INIT_POINTER(vxlan->vn6_sock, NULL); if (ipv6 || metadata) ret = __vxlan_sock_add(vxlan, true); #endif diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 0255613a54a40..308adc4154f43 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -225,9 +225,9 @@ struct vxlan_config { struct vxlan_dev { struct hlist_node hlist; /* vni hash table */ struct list_head next; /* vxlan's per namespace list */ - struct vxlan_sock *vn4_sock; /* listening socket for IPv4 */ + struct vxlan_sock __rcu *vn4_sock; /* listening socket for IPv4 */ #if IS_ENABLED(CONFIG_IPV6) - struct vxlan_sock *vn6_sock; /* listening socket for IPv6 */ + struct vxlan_sock __rcu *vn6_sock; /* listening socket for IPv6 */ #endif struct net_device *dev; struct net *net; /* netns for packet i/o */ -- GitLab From fceb9c3e38252992bbf1a3028cc2f7b871211533 Mon Sep 17 00:00:00 2001 From: pravin shelar Date: Fri, 28 Oct 2016 09:59:16 -0700 Subject: [PATCH 1167/1167] geneve: avoid using stale geneve socket. This patch is similar to earlier vxlan patch. Geneve device close operation frees geneve socket. This operation can race with geneve-xmit function which dereferences geneve socket. Following patch uses RCU mechanism to avoid this situation. Signed-off-by: Pravin B Shelar Acked-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/geneve.c | 45 +++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 16af1ce99233a..42edd7b7902f1 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -58,9 +58,9 @@ struct geneve_dev { struct hlist_node hlist; /* vni hash table */ struct net *net; /* netns for packet i/o */ struct net_device *dev; /* netdev for geneve tunnel */ - struct geneve_sock *sock4; /* IPv4 socket used for geneve tunnel */ + struct geneve_sock __rcu *sock4; /* IPv4 socket used for geneve tunnel */ #if IS_ENABLED(CONFIG_IPV6) - struct geneve_sock *sock6; /* IPv6 socket used for geneve tunnel */ + struct geneve_sock __rcu *sock6; /* IPv6 socket used for geneve tunnel */ #endif u8 vni[3]; /* virtual network ID for tunnel */ u8 ttl; /* TTL override */ @@ -543,9 +543,19 @@ static void __geneve_sock_release(struct geneve_sock *gs) static void geneve_sock_release(struct geneve_dev *geneve) { - __geneve_sock_release(geneve->sock4); + struct geneve_sock *gs4 = rtnl_dereference(geneve->sock4); #if IS_ENABLED(CONFIG_IPV6) - __geneve_sock_release(geneve->sock6); + struct geneve_sock *gs6 = rtnl_dereference(geneve->sock6); + + rcu_assign_pointer(geneve->sock6, NULL); +#endif + + rcu_assign_pointer(geneve->sock4, NULL); + synchronize_net(); + + __geneve_sock_release(gs4); +#if IS_ENABLED(CONFIG_IPV6) + __geneve_sock_release(gs6); #endif } @@ -586,10 +596,10 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6) gs->flags = geneve->flags; #if IS_ENABLED(CONFIG_IPV6) if (ipv6) - geneve->sock6 = gs; + rcu_assign_pointer(geneve->sock6, gs); else #endif - geneve->sock4 = gs; + rcu_assign_pointer(geneve->sock4, gs); hash = geneve_net_vni_hash(geneve->vni); hlist_add_head_rcu(&geneve->hlist, &gs->vni_list[hash]); @@ -603,9 +613,7 @@ static int geneve_open(struct net_device *dev) bool metadata = geneve->collect_md; int ret = 0; - geneve->sock4 = NULL; #if IS_ENABLED(CONFIG_IPV6) - geneve->sock6 = NULL; if (ipv6 || metadata) ret = geneve_sock_add(geneve, true); #endif @@ -720,6 +728,9 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb, struct rtable *rt = NULL; __u8 tos; + if (!rcu_dereference(geneve->sock4)) + return ERR_PTR(-EIO); + memset(fl4, 0, sizeof(*fl4)); fl4->flowi4_mark = skb->mark; fl4->flowi4_proto = IPPROTO_UDP; @@ -772,11 +783,15 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb, { bool use_cache = ip_tunnel_dst_cache_usable(skb, info); struct geneve_dev *geneve = netdev_priv(dev); - struct geneve_sock *gs6 = geneve->sock6; struct dst_entry *dst = NULL; struct dst_cache *dst_cache; + struct geneve_sock *gs6; __u8 prio; + gs6 = rcu_dereference(geneve->sock6); + if (!gs6) + return ERR_PTR(-EIO); + memset(fl6, 0, sizeof(*fl6)); fl6->flowi6_mark = skb->mark; fl6->flowi6_proto = IPPROTO_UDP; @@ -842,7 +857,7 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, struct ip_tunnel_info *info) { struct geneve_dev *geneve = netdev_priv(dev); - struct geneve_sock *gs4 = geneve->sock4; + struct geneve_sock *gs4; struct rtable *rt = NULL; const struct iphdr *iip; /* interior IP header */ int err = -EINVAL; @@ -853,6 +868,10 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, bool xnet = !net_eq(geneve->net, dev_net(geneve->dev)); u32 flags = geneve->flags; + gs4 = rcu_dereference(geneve->sock4); + if (!gs4) + goto tx_error; + if (geneve->collect_md) { if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) { netdev_dbg(dev, "no tunnel metadata\n"); @@ -932,9 +951,9 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, struct ip_tunnel_info *info) { struct geneve_dev *geneve = netdev_priv(dev); - struct geneve_sock *gs6 = geneve->sock6; struct dst_entry *dst = NULL; const struct iphdr *iip; /* interior IP header */ + struct geneve_sock *gs6; int err = -EINVAL; struct flowi6 fl6; __u8 prio, ttl; @@ -943,6 +962,10 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, bool xnet = !net_eq(geneve->net, dev_net(geneve->dev)); u32 flags = geneve->flags; + gs6 = rcu_dereference(geneve->sock6); + if (!gs6) + goto tx_error; + if (geneve->collect_md) { if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) { netdev_dbg(dev, "no tunnel metadata\n"); -- GitLab