Merge 4.14.38 into android-4.14
authorGreg Kroah-Hartman <gregkh@google.com>
Mon, 30 Apr 2018 13:18:45 +0000 (06:18 -0700)
committerGreg Kroah-Hartman <gregkh@google.com>
Mon, 30 Apr 2018 13:18:45 +0000 (06:18 -0700)
Changes in 4.14.38
Revert "pinctrl: intel: Initialize GPIO properly when used through irqchip"
drm: bridge: dw-hdmi: Fix overflow workaround for Amlogic Meson GX SoCs
i40e: Fix attach VF to VM issue
tpm: cmd_ready command can be issued only after granting locality
tpm: tpm-interface: fix tpm_transmit/_cmd kdoc
tpm: add retry logic
Revert "ath10k: send (re)assoc peer command when NSS changed"
bonding: do not set slave_dev npinfo before slave_enable_netpoll in bond_enslave
ipv6: add RTA_TABLE and RTA_PREFSRC to rtm_ipv6_policy
ipv6: sr: fix NULL pointer dereference in seg6_do_srh_encap()- v4 pkts
KEYS: DNS: limit the length of option strings
l2tp: check sockaddr length in pppol2tp_connect()
net: validate attribute sizes in neigh_dump_table()
llc: delete timers synchronously in llc_sk_free()
tcp: don't read out-of-bounds opsize
net: af_packet: fix race in PACKET_{R|T}X_RING
tcp: md5: reject TCP_MD5SIG or TCP_MD5SIG_EXT on established sockets
net: fix deadlock while clearing neighbor proxy table
team: avoid adding twice the same option to the event list
net/smc: fix shutdown in state SMC_LISTEN
team: fix netconsole setup over team
packet: fix bitfield update race
tipc: add policy for TIPC_NLA_NET_ADDR
pppoe: check sockaddr length in pppoe_connect()
vlan: Fix reading memory beyond skb->tail in skb_vlan_tagged_multi
amd-xgbe: Add pre/post auto-negotiation phy hooks
sctp: do not check port in sctp_inet6_cmp_addr
amd-xgbe: Improve KR auto-negotiation and training
strparser: Do not call mod_delayed_work with a timeout of LONG_MAX
amd-xgbe: Only use the SFP supported transceiver signals
strparser: Fix incorrect strp->need_bytes value.
net: sched: ife: signal not finding metaid
tcp: clear tp->packets_out when purging write queue
net: sched: ife: handle malformed tlv length
net: sched: ife: check on metadata length
llc: hold llc_sap before release_sock()
llc: fix NULL pointer deref for SOCK_ZAPPED
net: ethernet: ti: cpsw: fix tx vlan priority mapping
virtio_net: split out ctrl buffer
virtio_net: fix adding vids on big-endian
s390: introduce CPU alternatives
s390: enable CPU alternatives unconditionally
KVM: s390: wire up bpb feature
s390: scrub registers on kernel entry and KVM exit
s390: add optimized array_index_mask_nospec
s390/alternative: use a copy of the facility bit mask
s390: add options to change branch prediction behaviour for the kernel
s390: run user space and KVM guests with modified branch prediction
s390: introduce execute-trampolines for branches
KVM: s390: force bp isolation for VSIE
s390: Replace IS_ENABLED(EXPOLINE_*) with IS_ENABLED(CONFIG_EXPOLINE_*)
s390: do not bypass BPENTER for interrupt system calls
s390/entry.S: fix spurious zeroing of r0
s390: move nobp parameter functions to nospec-branch.c
s390: add automatic detection of the spectre defense
s390: report spectre mitigation via syslog
s390: add sysfs attributes for spectre
s390: correct nospec auto detection init order
s390: correct module section names for expoline code revert
microblaze: Setup dependencies for ASM optimized lib functions
arm64: dts: rockchip: remove vdd_log from rk3399-puma
Revert "mm/hmm: fix header file if/else/endif maze"
commoncap: Handle memory allocation failure.
scsi: mptsas: Disable WRITE SAME
cdrom: information leak in cdrom_ioctl_media_changed()
fsnotify: Fix fsnotify_mark_connector race
m68k/mac: Don't remap SWIM MMIO region
block/swim: Check drive type
block/swim: Don't log an error message for an invalid ioctl
block/swim: Remove extra put_disk() call from error path
block/swim: Rename macros to avoid inconsistent inverted logic
block/swim: Select appropriate drive on device open
block/swim: Fix array bounds check
block/swim: Fix IO error at end of medium
tracing: Fix missing tab for hwlat_detector print format
s390/cio: update chpid descriptor after resource accessibility event
s390/dasd: fix IO error for newly defined devices
s390/uprobes: implement arch_uretprobe_is_alive()
ACPI / video: Only default only_lcd to true on Win8-ready _desktops_
Linux 4.14.38

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
87 files changed:
Documentation/admin-guide/kernel-parameters.txt
Makefile
arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
arch/microblaze/Kconfig.platform
arch/microblaze/lib/fastcopy.S
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/include/asm/alternative.h [new file with mode: 0644]
arch/s390/include/asm/barrier.h
arch/s390/include/asm/facility.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/nospec-branch.h [new file with mode: 0644]
arch/s390/include/asm/processor.h
arch/s390/include/asm/thread_info.h
arch/s390/include/uapi/asm/kvm.h
arch/s390/kernel/Makefile
arch/s390/kernel/alternative.c [new file with mode: 0644]
arch/s390/kernel/early.c
arch/s390/kernel/entry.S
arch/s390/kernel/ipl.c
arch/s390/kernel/module.c
arch/s390/kernel/nospec-branch.c [new file with mode: 0644]
arch/s390/kernel/processor.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/uprobes.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/vsie.c
drivers/acpi/acpi_video.c
drivers/block/swim.c
drivers/block/swim3.c
drivers/cdrom/cdrom.c
drivers/char/tpm/tpm-interface.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_crb.c
drivers/char/tpm/tpm_tis_core.c
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
drivers/message/fusion/mptsas.c
drivers/net/bonding/bond_main.c
drivers/net/ethernet/amd/xgbe/xgbe-common.h
drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
drivers/net/ethernet/amd/xgbe/xgbe-main.c
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
drivers/net/ethernet/amd/xgbe/xgbe-pci.c
drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
drivers/net/ethernet/amd/xgbe/xgbe.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ppp/pppoe.c
drivers/net/team/team.c
drivers/net/virtio_net.c
drivers/net/wireless/ath/ath10k/mac.c
drivers/pinctrl/intel/pinctrl-intel.c
drivers/s390/block/dasd_alias.c
drivers/s390/char/Makefile
drivers/s390/cio/chsc.c
include/linux/fsnotify_backend.h
include/linux/hmm.h
include/linux/if_vlan.h
include/linux/tpm.h
include/net/ife.h
include/net/llc_conn.h
include/net/tcp.h
include/uapi/linux/kvm.h
kernel/trace/trace_entries.h
net/core/dev.c
net/core/neighbour.c
net/dns_resolver/dns_key.c
net/ife/ife.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv6/route.c
net/ipv6/seg6_iptunnel.c
net/l2tp/l2tp_ppp.c
net/llc/af_llc.c
net/llc/llc_c_ac.c
net/llc/llc_conn.c
net/packet/af_packet.c
net/packet/internal.h
net/sched/act_ife.c
net/sctp/ipv6.c
net/smc/af_smc.c
net/strparser/strparser.c
net/tipc/netlink.c
security/commoncap.c

index 4d07fd93f9c120bbe4fe5ad85ef03a3941fedff9..90008a2b834c9737e6202bae65e6dd9e2a5f5cd1 100644 (file)
 
        noalign         [KNL,ARM]
 
+       noaltinstr      [S390] Disables alternative instructions patching
+                       (CPU alternatives feature).
+
        noapic          [SMP,APIC] Tells the kernel to not make use of any
                        IOAPICs that may be present in the system.
 
index 064c38ebb20923120a15b471d753ede9755bc5bd..19b7aba91f98a686216256bf91858e403d8ada48 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 VERSION = 4
 PATCHLEVEL = 14
-SUBLEVEL = 37
+SUBLEVEL = 38
 EXTRAVERSION =
 NAME = Petit Gorille
 
index 910628d18add07d9a39974bc6ce2ac4a403adb81..1fc5060d7027e6e4b852c6cd71d430d2e7ab3990 100644 (file)
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
        };
-
-       vdd_log: vdd-log {
-               compatible = "pwm-regulator";
-               pwms = <&pwm2 0 25000 0>;
-               regulator-name = "vdd_log";
-               regulator-min-microvolt = <800000>;
-               regulator-max-microvolt = <1400000>;
-               regulator-always-on;
-               regulator-boot-on;
-               status = "okay";
-       };
 };
 
 &cpu_b0 {
index 1b3d8c8491018734b3cca9f5ecd5441e52f8c8b2..f7f1739c11b9fef091b1176c0120c4613232cfeb 100644 (file)
@@ -20,6 +20,7 @@ config OPT_LIB_FUNCTION
 config OPT_LIB_ASM
        bool "Optimalized lib function ASM"
        depends on OPT_LIB_FUNCTION && (XILINX_MICROBLAZE0_USE_BARREL = 1)
+       depends on CPU_BIG_ENDIAN
        default n
        help
          Allows turn on optimalized library function (memcpy and memmove).
index 62021d7e249e0665cd6a1483c12de5b8b0bf5739..fdc48bb065d89fe3b2443ef054d1a6ece3744b54 100644 (file)
  *     between mem locations with size of xfer spec'd in bytes
  */
 
-#ifdef __MICROBLAZEEL__
-#error Microblaze LE not support ASM optimized lib func. Disable OPT_LIB_ASM.
-#endif
-
 #include <linux/linkage.h>
        .text
        .globl  memcpy
index ae55e715cc748e0148601c9cd05de1f969f60560..49fb6614ea8c79a2cd5cfdf291c40b9ff35684ea 100644 (file)
@@ -121,6 +121,7 @@ config S390
        select GENERIC_CLOCKEVENTS
        select GENERIC_CPU_AUTOPROBE
        select GENERIC_CPU_DEVICES if !SMP
+       select GENERIC_CPU_VULNERABILITIES
        select GENERIC_FIND_FIRST_BIT
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_TIME_VSYSCALL
@@ -538,6 +539,51 @@ config ARCH_RANDOM
 
          If unsure, say Y.
 
+config KERNEL_NOBP
+       def_bool n
+       prompt "Enable modified branch prediction for the kernel by default"
+       help
+         If this option is selected the kernel will switch to a modified
+         branch prediction mode if the firmware interface is available.
+         The modified branch prediction mode improves the behaviour in
+         regard to speculative execution.
+
+         With the option enabled the kernel parameter "nobp=0" or "nospec"
+         can be used to run the kernel in the normal branch prediction mode.
+
+         With the option disabled the modified branch prediction mode is
+         enabled with the "nobp=1" kernel parameter.
+
+         If unsure, say N.
+
+config EXPOLINE
+       def_bool n
+       prompt "Avoid speculative indirect branches in the kernel"
+       help
+         Compile the kernel with the expoline compiler options to guard
+         against kernel-to-user data leaks by avoiding speculative indirect
+         branches.
+         Requires a compiler with -mindirect-branch=thunk support for full
+         protection. The kernel may run slower.
+
+         If unsure, say N.
+
+choice
+       prompt "Expoline default"
+       depends on EXPOLINE
+       default EXPOLINE_FULL
+
+config EXPOLINE_OFF
+       bool "spectre_v2=off"
+
+config EXPOLINE_AUTO
+       bool "spectre_v2=auto"
+
+config EXPOLINE_FULL
+       bool "spectre_v2=on"
+
+endchoice
+
 endmenu
 
 menu "Memory setup"
@@ -812,6 +858,7 @@ config PFAULT
 config SHARED_KERNEL
        bool "VM shared kernel support"
        depends on !JUMP_LABEL
+       depends on !ALTERNATIVES
        help
          Select this option, if you want to share the text segment of the
          Linux kernel between different VM guests. This reduces memory
index dac821cfcd430310a95624754d7dd814bcd7705b..ec3fa105f4481f4b08a910f36cbac215c492f81a 100644 (file)
@@ -81,6 +81,16 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
 cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack
 endif
 
+ifdef CONFIG_EXPOLINE
+  ifeq ($(call cc-option-yn,$(CC_FLAGS_MARCH) -mindirect-branch=thunk),y)
+    CC_FLAGS_EXPOLINE := -mindirect-branch=thunk
+    CC_FLAGS_EXPOLINE += -mfunction-return=thunk
+    CC_FLAGS_EXPOLINE += -mindirect-branch-table
+    export CC_FLAGS_EXPOLINE
+    cflags-y += $(CC_FLAGS_EXPOLINE) -DCC_USING_EXPOLINE
+  endif
+endif
+
 ifdef CONFIG_FUNCTION_TRACER
 # make use of hotpatch feature if the compiler supports it
 cc_hotpatch    := -mhotpatch=0,3
diff --git a/arch/s390/include/asm/alternative.h b/arch/s390/include/asm/alternative.h
new file mode 100644 (file)
index 0000000..a720020
--- /dev/null
@@ -0,0 +1,149 @@
+#ifndef _ASM_S390_ALTERNATIVE_H
+#define _ASM_S390_ALTERNATIVE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/stringify.h>
+
+struct alt_instr {
+       s32 instr_offset;       /* original instruction */
+       s32 repl_offset;        /* offset to replacement instruction */
+       u16 facility;           /* facility bit set for replacement */
+       u8  instrlen;           /* length of original instruction */
+       u8  replacementlen;     /* length of new instruction */
+} __packed;
+
+void apply_alternative_instructions(void);
+void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
+
+/*
+ * |661:       |662:     |6620      |663:
+ * +-----------+---------------------+
+ * | oldinstr  | oldinstr_padding    |
+ * |          +----------+----------+
+ * |          |          |          |
+ * |          | >6 bytes |6/4/2 nops|
+ * |          |6 bytes jg----------->
+ * +-----------+---------------------+
+ *              ^^ static padding ^^
+ *
+ * .altinstr_replacement section
+ * +---------------------+-----------+
+ * |6641:                           |6651:
+ * | alternative instr 1            |
+ * +-----------+---------+- - - - - -+
+ * |6642:               |6652:      |
+ * | alternative instr 2 | padding
+ * +---------------------+- - - - - -+
+ *                       ^ runtime ^
+ *
+ * .altinstructions section
+ * +---------------------------------+
+ * | alt_instr entries for each      |
+ * | alternative instr              |
+ * +---------------------------------+
+ */
+
+#define b_altinstr(num)        "664"#num
+#define e_altinstr(num)        "665"#num
+
+#define e_oldinstr_pad_end     "663"
+#define oldinstr_len           "662b-661b"
+#define oldinstr_total_len     e_oldinstr_pad_end"b-661b"
+#define altinstr_len(num)      e_altinstr(num)"b-"b_altinstr(num)"b"
+#define oldinstr_pad_len(num) \
+       "-(((" altinstr_len(num) ")-(" oldinstr_len ")) > 0) * " \
+       "((" altinstr_len(num) ")-(" oldinstr_len "))"
+
+#define INSTR_LEN_SANITY_CHECK(len)                                    \
+       ".if " len " > 254\n"                                           \
+       "\t.error \"cpu alternatives does not support instructions "    \
+               "blocks > 254 bytes\"\n"                                \
+       ".endif\n"                                                      \
+       ".if (" len ") %% 2\n"                                          \
+       "\t.error \"cpu alternatives instructions length is odd\"\n"    \
+       ".endif\n"
+
+#define OLDINSTR_PADDING(oldinstr, num)                                        \
+       ".if " oldinstr_pad_len(num) " > 6\n"                           \
+       "\tjg " e_oldinstr_pad_end "f\n"                                \
+       "6620:\n"                                                       \
+       "\t.fill (" oldinstr_pad_len(num) " - (6620b-662b)) / 2, 2, 0x0700\n" \
+       ".else\n"                                                       \
+       "\t.fill " oldinstr_pad_len(num) " / 6, 6, 0xc0040000\n"        \
+       "\t.fill " oldinstr_pad_len(num) " %% 6 / 4, 4, 0x47000000\n"   \
+       "\t.fill " oldinstr_pad_len(num) " %% 6 %% 4 / 2, 2, 0x0700\n"  \
+       ".endif\n"
+
+#define OLDINSTR(oldinstr, num)                                                \
+       "661:\n\t" oldinstr "\n662:\n"                                  \
+       OLDINSTR_PADDING(oldinstr, num)                                 \
+       e_oldinstr_pad_end ":\n"                                        \
+       INSTR_LEN_SANITY_CHECK(oldinstr_len)
+
+#define OLDINSTR_2(oldinstr, num1, num2)                               \
+       "661:\n\t" oldinstr "\n662:\n"                                  \
+       ".if " altinstr_len(num1) " < " altinstr_len(num2) "\n"         \
+       OLDINSTR_PADDING(oldinstr, num2)                                \
+       ".else\n"                                                       \
+       OLDINSTR_PADDING(oldinstr, num1)                                \
+       ".endif\n"                                                      \
+       e_oldinstr_pad_end ":\n"                                        \
+       INSTR_LEN_SANITY_CHECK(oldinstr_len)
+
+#define ALTINSTR_ENTRY(facility, num)                                  \
+       "\t.long 661b - .\n"                    /* old instruction */   \
+       "\t.long " b_altinstr(num)"b - .\n"     /* alt instruction */   \
+       "\t.word " __stringify(facility) "\n"   /* facility bit    */   \
+       "\t.byte " oldinstr_total_len "\n"      /* source len      */   \
+       "\t.byte " altinstr_len(num) "\n"       /* alt instruction len */
+
+#define ALTINSTR_REPLACEMENT(altinstr, num)    /* replacement */       \
+       b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n"      \
+       INSTR_LEN_SANITY_CHECK(altinstr_len(num))
+
+/* alternative assembly primitive: */
+#define ALTERNATIVE(oldinstr, altinstr, facility) \
+       ".pushsection .altinstr_replacement, \"ax\"\n"                  \
+       ALTINSTR_REPLACEMENT(altinstr, 1)                               \
+       ".popsection\n"                                                 \
+       OLDINSTR(oldinstr, 1)                                           \
+       ".pushsection .altinstructions,\"a\"\n"                         \
+       ALTINSTR_ENTRY(facility, 1)                                     \
+       ".popsection\n"
+
+#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2)\
+       ".pushsection .altinstr_replacement, \"ax\"\n"                  \
+       ALTINSTR_REPLACEMENT(altinstr1, 1)                              \
+       ALTINSTR_REPLACEMENT(altinstr2, 2)                              \
+       ".popsection\n"                                                 \
+       OLDINSTR_2(oldinstr, 1, 2)                                      \
+       ".pushsection .altinstructions,\"a\"\n"                         \
+       ALTINSTR_ENTRY(facility1, 1)                                    \
+       ALTINSTR_ENTRY(facility2, 2)                                    \
+       ".popsection\n"
+
+/*
+ * Alternative instructions for different CPU types or capabilities.
+ *
+ * This allows to use optimized instructions even on generic binary
+ * kernels.
+ *
+ * oldinstr is padded with jump and nops at compile time if altinstr is
+ * longer. altinstr is padded with jump and nops at run-time during patching.
+ *
+ * For non barrier like inlines please define new variants
+ * without volatile and memory clobber.
+ */
+#define alternative(oldinstr, altinstr, facility)                      \
+       asm volatile(ALTERNATIVE(oldinstr, altinstr, facility) : : : "memory")
+
+#define alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \
+       asm volatile(ALTERNATIVE_2(oldinstr, altinstr1, facility1,          \
+                                  altinstr2, facility2) ::: "memory")
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_S390_ALTERNATIVE_H */
index 10432607a573625be45d23e6263c05e378a0bdfe..f9eddbca79d2859f856454a2a0dbce68ab9eca36 100644 (file)
@@ -49,6 +49,30 @@ do {                                                                 \
 #define __smp_mb__before_atomic()      barrier()
 #define __smp_mb__after_atomic()       barrier()
 
+/**
+ * array_index_mask_nospec - generate a mask for array_idx() that is
+ * ~0UL when the bounds check succeeds and 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ */
+#define array_index_mask_nospec array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+                                                   unsigned long size)
+{
+       unsigned long mask;
+
+       if (__builtin_constant_p(size) && size > 0) {
+               asm("   clgr    %2,%1\n"
+                   "   slbgr   %0,%0\n"
+                   :"=d" (mask) : "d" (size-1), "d" (index) :"cc");
+               return mask;
+       }
+       asm("   clgr    %1,%2\n"
+           "   slbgr   %0,%0\n"
+           :"=d" (mask) : "d" (size), "d" (index) :"cc");
+       return ~mask;
+}
+
 #include <asm-generic/barrier.h>
 
 #endif /* __ASM_BARRIER_H */
index f040644575b7104c27d770e4f5b42ca85134be1b..2d58478c2745b202cd0a1b4572528b727f7b5c80 100644 (file)
 
 #define MAX_FACILITY_BIT (sizeof(((struct lowcore *)0)->stfle_fac_list) * 8)
 
+static inline void __set_facility(unsigned long nr, void *facilities)
+{
+       unsigned char *ptr = (unsigned char *) facilities;
+
+       if (nr >= MAX_FACILITY_BIT)
+               return;
+       ptr[nr >> 3] |= 0x80 >> (nr & 7);
+}
+
+static inline void __clear_facility(unsigned long nr, void *facilities)
+{
+       unsigned char *ptr = (unsigned char *) facilities;
+
+       if (nr >= MAX_FACILITY_BIT)
+               return;
+       ptr[nr >> 3] &= ~(0x80 >> (nr & 7));
+}
+
 static inline int __test_facility(unsigned long nr, void *facilities)
 {
        unsigned char *ptr;
index 51375e766e905a955a4df21fa185c669bfaa9544..d660e784e4454ec5635fd20f8ac1a342f3b52ccf 100644 (file)
@@ -210,7 +210,8 @@ struct kvm_s390_sie_block {
        __u16   ipa;                    /* 0x0056 */
        __u32   ipb;                    /* 0x0058 */
        __u32   scaoh;                  /* 0x005c */
-       __u8    reserved60;             /* 0x0060 */
+#define FPF_BPBC       0x20
+       __u8    fpf;                    /* 0x0060 */
 #define ECB_GS         0x40
 #define ECB_TE         0x10
 #define ECB_SRSI       0x04
index 917f7344cab6fbf627ee29f788f1de467b0690e0..88a212df0dbcdb5997b6a5025e4fb2063ba214e1 100644 (file)
@@ -140,7 +140,9 @@ struct lowcore {
        /* Per cpu primary space access list */
        __u32   paste[16];                      /* 0x0400 */
 
-       __u8    pad_0x04c0[0x0e00-0x0440];      /* 0x0440 */
+       /* br %r1 trampoline */
+       __u16   br_r1_trampoline;               /* 0x0440 */
+       __u8    pad_0x0442[0x0e00-0x0442];      /* 0x0442 */
 
        /*
         * 0xe00 contains the address of the IPL Parameter Information
@@ -155,7 +157,8 @@ struct lowcore {
        __u8    pad_0x0e20[0x0f00-0x0e20];      /* 0x0e20 */
 
        /* Extended facility list */
-       __u64   stfle_fac_list[32];             /* 0x0f00 */
+       __u64   stfle_fac_list[16];             /* 0x0f00 */
+       __u64   alt_stfle_fac_list[16];         /* 0x0f80 */
        __u8    pad_0x1000[0x11b0-0x1000];      /* 0x1000 */
 
        /* Pointer to the machine check extended save area */
diff --git a/arch/s390/include/asm/nospec-branch.h b/arch/s390/include/asm/nospec-branch.h
new file mode 100644 (file)
index 0000000..b4bd8c4
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_S390_EXPOLINE_H
+#define _ASM_S390_EXPOLINE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+extern int nospec_disable;
+
+void nospec_init_branches(void);
+void nospec_auto_detect(void);
+void nospec_revert(s32 *start, s32 *end);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_S390_EXPOLINE_H */
index 9cf92abe23c32ab495b5e4640f7904ab37cd0d54..0a39cd102c49263903ed43f269c32690738dd418 100644 (file)
@@ -89,6 +89,7 @@ void cpu_detect_mhz_feature(void);
 extern const struct seq_operations cpuinfo_op;
 extern int sysctl_ieee_emulation_warnings;
 extern void execve_tail(void);
+extern void __bpon(void);
 
 /*
  * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit.
@@ -377,6 +378,9 @@ extern void memcpy_absolute(void *, void *, size_t);
        memcpy_absolute(&(dest), &__tmp, sizeof(__tmp));        \
 } while (0)
 
+extern int s390_isolate_bp(void);
+extern int s390_isolate_bp_guest(void);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_S390_PROCESSOR_H */
index 0880a37b6d3befe6baf5afbf345c3a4b19397897..301b4f70bf313b8a482a48877085f10e98d29f3c 100644 (file)
@@ -60,6 +60,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
 #define TIF_GUARDED_STORAGE    4       /* load guarded storage control block */
 #define TIF_PATCH_PENDING      5       /* pending live patching update */
 #define TIF_PGSTE              6       /* New mm's will use 4K page tables */
+#define TIF_ISOLATE_BP         8       /* Run process with isolated BP */
+#define TIF_ISOLATE_BP_GUEST   9       /* Run KVM guests with isolated BP */
 
 #define TIF_31BIT              16      /* 32bit process */
 #define TIF_MEMDIE             17      /* is terminating due to OOM killer */
@@ -80,6 +82,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
 #define _TIF_UPROBE            _BITUL(TIF_UPROBE)
 #define _TIF_GUARDED_STORAGE   _BITUL(TIF_GUARDED_STORAGE)
 #define _TIF_PATCH_PENDING     _BITUL(TIF_PATCH_PENDING)
+#define _TIF_ISOLATE_BP                _BITUL(TIF_ISOLATE_BP)
+#define _TIF_ISOLATE_BP_GUEST  _BITUL(TIF_ISOLATE_BP_GUEST)
 
 #define _TIF_31BIT             _BITUL(TIF_31BIT)
 #define _TIF_SINGLE_STEP       _BITUL(TIF_SINGLE_STEP)
index 9ad172dcd912d5763b0bf954617c9e398ad31aa8..a3938db010f77a69b53924e7bf9252e8a12fb0a4 100644 (file)
@@ -228,6 +228,7 @@ struct kvm_guest_debug_arch {
 #define KVM_SYNC_RICCB  (1UL << 7)
 #define KVM_SYNC_FPRS   (1UL << 8)
 #define KVM_SYNC_GSCB   (1UL << 9)
+#define KVM_SYNC_BPBC   (1UL << 10)
 /* length and alignment of the sdnx as a power of two */
 #define SDNXC 8
 #define SDNXL (1UL << SDNXC)
@@ -251,7 +252,9 @@ struct kvm_sync_regs {
        };
        __u8  reserved[512];    /* for future vector expansion */
        __u32 fpc;              /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */
-       __u8 padding1[52];      /* riccb needs to be 64byte aligned */
+       __u8 bpbc : 1;          /* bp mode */
+       __u8 reserved2 : 7;
+       __u8 padding1[51];      /* riccb needs to be 64byte aligned */
        __u8 riccb[64];         /* runtime instrumentation controls block */
        __u8 padding2[192];     /* sdnx needs to be 256byte aligned */
        union {
index 4ce2d05929a7a21853e15d10d317fa0a31591d7d..a3a4cafb6080ff526575cd81aedc0df9088c87a0 100644 (file)
@@ -29,6 +29,7 @@ UBSAN_SANITIZE_early.o        := n
 #
 ifneq ($(CC_FLAGS_MARCH),-march=z900)
 CFLAGS_REMOVE_als.o    += $(CC_FLAGS_MARCH)
+CFLAGS_REMOVE_als.o    += $(CC_FLAGS_EXPOLINE)
 CFLAGS_als.o           += -march=z900
 AFLAGS_REMOVE_head.o   += $(CC_FLAGS_MARCH)
 AFLAGS_head.o          += -march=z900
@@ -57,10 +58,13 @@ obj-y       += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
 obj-y  += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o
 obj-y  += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
 obj-y  += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o
-obj-y  += entry.o reipl.o relocate_kernel.o kdebugfs.o
+obj-y  += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o
+obj-y  += nospec-branch.o
 
 extra-y                                += head.o head64.o vmlinux.lds
 
+CFLAGS_REMOVE_nospec-branch.o  += $(CC_FLAGS_EXPOLINE)
+
 obj-$(CONFIG_MODULES)          += module.o
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_SCHED_TOPOLOGY)   += topology.o
diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c
new file mode 100644 (file)
index 0000000..b57b293
--- /dev/null
@@ -0,0 +1,112 @@
+#include <linux/module.h>
+#include <asm/alternative.h>
+#include <asm/facility.h>
+#include <asm/nospec-branch.h>
+
+#define MAX_PATCH_LEN (255 - 1)
+
+static int __initdata_or_module alt_instr_disabled;
+
+static int __init disable_alternative_instructions(char *str)
+{
+       alt_instr_disabled = 1;
+       return 0;
+}
+
+early_param("noaltinstr", disable_alternative_instructions);
+
+struct brcl_insn {
+       u16 opc;
+       s32 disp;
+} __packed;
+
+static u16 __initdata_or_module nop16 = 0x0700;
+static u32 __initdata_or_module nop32 = 0x47000000;
+static struct brcl_insn __initdata_or_module nop48 = {
+       0xc004, 0
+};
+
+static const void *nops[] __initdata_or_module = {
+       &nop16,
+       &nop32,
+       &nop48
+};
+
+static void __init_or_module add_jump_padding(void *insns, unsigned int len)
+{
+       struct brcl_insn brcl = {
+               0xc0f4,
+               len / 2
+       };
+
+       memcpy(insns, &brcl, sizeof(brcl));
+       insns += sizeof(brcl);
+       len -= sizeof(brcl);
+
+       while (len > 0) {
+               memcpy(insns, &nop16, 2);
+               insns += 2;
+               len -= 2;
+       }
+}
+
+static void __init_or_module add_padding(void *insns, unsigned int len)
+{
+       if (len > 6)
+               add_jump_padding(insns, len);
+       else if (len >= 2)
+               memcpy(insns, nops[len / 2 - 1], len);
+}
+
+static void __init_or_module __apply_alternatives(struct alt_instr *start,
+                                                 struct alt_instr *end)
+{
+       struct alt_instr *a;
+       u8 *instr, *replacement;
+       u8 insnbuf[MAX_PATCH_LEN];
+
+       /*
+        * The scan order should be from start to end. A later scanned
+        * alternative code can overwrite previously scanned alternative code.
+        */
+       for (a = start; a < end; a++) {
+               int insnbuf_sz = 0;
+
+               instr = (u8 *)&a->instr_offset + a->instr_offset;
+               replacement = (u8 *)&a->repl_offset + a->repl_offset;
+
+               if (!__test_facility(a->facility,
+                                    S390_lowcore.alt_stfle_fac_list))
+                       continue;
+
+               if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) {
+                       WARN_ONCE(1, "cpu alternatives instructions length is "
+                                    "odd, skipping patching\n");
+                       continue;
+               }
+
+               memcpy(insnbuf, replacement, a->replacementlen);
+               insnbuf_sz = a->replacementlen;
+
+               if (a->instrlen > a->replacementlen) {
+                       add_padding(insnbuf + a->replacementlen,
+                                   a->instrlen - a->replacementlen);
+                       insnbuf_sz += a->instrlen - a->replacementlen;
+               }
+
+               s390_kernel_write(instr, insnbuf, insnbuf_sz);
+       }
+}
+
+void __init_or_module apply_alternatives(struct alt_instr *start,
+                                        struct alt_instr *end)
+{
+       if (!alt_instr_disabled)
+               __apply_alternatives(start, end);
+}
+
+extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
+void __init apply_alternative_instructions(void)
+{
+       apply_alternatives(__alt_instructions, __alt_instructions_end);
+}
index f7b280f0ab1682004a545199905c779abaac3ffe..a3219837fa702212e918e187ccd12c4eab824d55 100644 (file)
@@ -329,6 +329,11 @@ static noinline __init void setup_facility_list(void)
 {
        stfle(S390_lowcore.stfle_fac_list,
              ARRAY_SIZE(S390_lowcore.stfle_fac_list));
+       memcpy(S390_lowcore.alt_stfle_fac_list,
+              S390_lowcore.stfle_fac_list,
+              sizeof(S390_lowcore.alt_stfle_fac_list));
+       if (!IS_ENABLED(CONFIG_KERNEL_NOBP))
+               __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
 }
 
 static __init void detect_diag9c(void)
index 7c6904d616d877330ae5768a9ad348e298a1562e..ed9aaa212d4a10495964d9349affc256ce1ffe05 100644 (file)
@@ -106,6 +106,7 @@ _PIF_WORK   = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
        aghi    %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        j       3f
 1:     UPDATE_VTIME %r14,%r15,\timer
+       BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
 2:     lg      %r15,__LC_ASYNC_STACK   # load async stack
 3:     la      %r11,STACK_FRAME_OVERHEAD(%r15)
        .endm
@@ -158,6 +159,130 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
                tm      off+\addr, \mask
        .endm
 
+       .macro BPOFF
+       .pushsection .altinstr_replacement, "ax"
+660:   .long   0xb2e8c000
+       .popsection
+661:   .long   0x47000000
+       .pushsection .altinstructions, "a"
+       .long 661b - .
+       .long 660b - .
+       .word 82
+       .byte 4
+       .byte 4
+       .popsection
+       .endm
+
+       .macro BPON
+       .pushsection .altinstr_replacement, "ax"
+662:   .long   0xb2e8d000
+       .popsection
+663:   .long   0x47000000
+       .pushsection .altinstructions, "a"
+       .long 663b - .
+       .long 662b - .
+       .word 82
+       .byte 4
+       .byte 4
+       .popsection
+       .endm
+
+       .macro BPENTER tif_ptr,tif_mask
+       .pushsection .altinstr_replacement, "ax"
+662:   .word   0xc004, 0x0000, 0x0000  # 6 byte nop
+       .word   0xc004, 0x0000, 0x0000  # 6 byte nop
+       .popsection
+664:   TSTMSK  \tif_ptr,\tif_mask
+       jz      . + 8
+       .long   0xb2e8d000
+       .pushsection .altinstructions, "a"
+       .long 664b - .
+       .long 662b - .
+       .word 82
+       .byte 12
+       .byte 12
+       .popsection
+       .endm
+
+       .macro BPEXIT tif_ptr,tif_mask
+       TSTMSK  \tif_ptr,\tif_mask
+       .pushsection .altinstr_replacement, "ax"
+662:   jnz     . + 8
+       .long   0xb2e8d000
+       .popsection
+664:   jz      . + 8
+       .long   0xb2e8c000
+       .pushsection .altinstructions, "a"
+       .long 664b - .
+       .long 662b - .
+       .word 82
+       .byte 8
+       .byte 8
+       .popsection
+       .endm
+
+#ifdef CONFIG_EXPOLINE
+
+       .macro GEN_BR_THUNK name,reg,tmp
+       .section .text.\name,"axG",@progbits,\name,comdat
+       .globl \name
+       .hidden \name
+       .type \name,@function
+\name:
+       .cfi_startproc
+#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
+       exrl    0,0f
+#else
+       larl    \tmp,0f
+       ex      0,0(\tmp)
+#endif
+       j       .
+0:     br      \reg
+       .cfi_endproc
+       .endm
+
+       GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1
+       GEN_BR_THUNK __s390x_indirect_jump_r1use_r14,%r14,%r1
+       GEN_BR_THUNK __s390x_indirect_jump_r11use_r14,%r14,%r11
+
+       .macro BASR_R14_R9
+0:     brasl   %r14,__s390x_indirect_jump_r1use_r9
+       .pushsection .s390_indirect_branches,"a",@progbits
+       .long   0b-.
+       .popsection
+       .endm
+
+       .macro BR_R1USE_R14
+0:     jg      __s390x_indirect_jump_r1use_r14
+       .pushsection .s390_indirect_branches,"a",@progbits
+       .long   0b-.
+       .popsection
+       .endm
+
+       .macro BR_R11USE_R14
+0:     jg      __s390x_indirect_jump_r11use_r14
+       .pushsection .s390_indirect_branches,"a",@progbits
+       .long   0b-.
+       .popsection
+       .endm
+
+#else  /* CONFIG_EXPOLINE */
+
+       .macro BASR_R14_R9
+       basr    %r14,%r9
+       .endm
+
+       .macro BR_R1USE_R14
+       br      %r14
+       .endm
+
+       .macro BR_R11USE_R14
+       br      %r14
+       .endm
+
+#endif /* CONFIG_EXPOLINE */
+
+
        .section .kprobes.text, "ax"
 .Ldummy:
        /*
@@ -170,6 +295,11 @@ _PIF_WORK  = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
         */
        nop     0
 
+ENTRY(__bpon)
+       .globl __bpon
+       BPON
+       BR_R1USE_R14
+
 /*
  * Scheduler resume function, called by switch_to
  *  gpr2 = (task_struct *) prev
@@ -193,9 +323,9 @@ ENTRY(__switch_to)
        mvc     __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
        lmg     %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        TSTMSK  __LC_MACHINE_FLAGS,MACHINE_FLAG_LPP
-       bzr     %r14
+       jz      0f
        .insn   s,0xb2800000,__LC_LPP           # set program parameter
-       br      %r14
+0:     BR_R1USE_R14
 
 .L__critical_start:
 
@@ -207,9 +337,11 @@ ENTRY(__switch_to)
  */
 ENTRY(sie64a)
        stmg    %r6,%r14,__SF_GPRS(%r15)        # save kernel registers
+       lg      %r12,__LC_CURRENT
        stg     %r2,__SF_EMPTY(%r15)            # save control block pointer
        stg     %r3,__SF_EMPTY+8(%r15)          # save guest register save area
        xc      __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # reason code = 0
+       mvc     __SF_EMPTY+24(8,%r15),__TI_flags(%r12) # copy thread flags
        TSTMSK  __LC_CPU_FLAGS,_CIF_FPU         # load guest fp/vx registers ?
        jno     .Lsie_load_guest_gprs
        brasl   %r14,load_fpu_regs              # load guest fp/vx regs
@@ -226,8 +358,12 @@ ENTRY(sie64a)
        jnz     .Lsie_skip
        TSTMSK  __LC_CPU_FLAGS,_CIF_FPU
        jo      .Lsie_skip                      # exit if fp/vx regs changed
+       BPEXIT  __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
 .Lsie_entry:
        sie     0(%r14)
+.Lsie_exit:
+       BPOFF
+       BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
 .Lsie_skip:
        ni      __SIE_PROG0C+3(%r14),0xfe       # no longer in SIE
        lctlg   %c1,%c1,__LC_USER_ASCE          # load primary asce
@@ -248,9 +384,15 @@ ENTRY(sie64a)
 sie_exit:
        lg      %r14,__SF_EMPTY+8(%r15)         # load guest register save area
        stmg    %r0,%r13,0(%r14)                # save guest gprs 0-13
+       xgr     %r0,%r0                         # clear guest registers to
+       xgr     %r1,%r1                         # prevent speculative use
+       xgr     %r2,%r2
+       xgr     %r3,%r3
+       xgr     %r4,%r4
+       xgr     %r5,%r5
        lmg     %r6,%r14,__SF_GPRS(%r15)        # restore kernel registers
        lg      %r2,__SF_EMPTY+16(%r15)         # return exit reason code
-       br      %r14
+       BR_R1USE_R14
 .Lsie_fault:
        lghi    %r14,-EFAULT
        stg     %r14,__SF_EMPTY+16(%r15)        # set exit reason code
@@ -273,6 +415,7 @@ ENTRY(system_call)
        stpt    __LC_SYNC_ENTER_TIMER
 .Lsysc_stmg:
        stmg    %r8,%r15,__LC_SAVE_AREA_SYNC
+       BPOFF
        lg      %r12,__LC_CURRENT
        lghi    %r13,__TASK_thread
        lghi    %r14,_PIF_SYSCALL
@@ -281,12 +424,15 @@ ENTRY(system_call)
        la      %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
 .Lsysc_vtime:
        UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER
+       BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
        stmg    %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
        mvc     __PT_PSW(16,%r11),__LC_SVC_OLD_PSW
        mvc     __PT_INT_CODE(4,%r11),__LC_SVC_ILC
        stg     %r14,__PT_FLAGS(%r11)
 .Lsysc_do_svc:
+       # clear user controlled register to prevent speculative use
+       xgr     %r0,%r0
        # load address of system call table
        lg      %r10,__THREAD_sysc_table(%r13,%r12)
        llgh    %r8,__PT_INT_CODE+2(%r11)
@@ -305,7 +451,7 @@ ENTRY(system_call)
        lgf     %r9,0(%r8,%r10)                 # get system call add.
        TSTMSK  __TI_flags(%r12),_TIF_TRACE
        jnz     .Lsysc_tracesys
-       basr    %r14,%r9                        # call sys_xxxx
+       BASR_R14_R9                             # call sys_xxxx
        stg     %r2,__PT_R2(%r11)               # store return value
 
 .Lsysc_return:
@@ -317,6 +463,7 @@ ENTRY(system_call)
        jnz     .Lsysc_work                     # check for work
        TSTMSK  __LC_CPU_FLAGS,_CIF_WORK
        jnz     .Lsysc_work
+       BPEXIT  __TI_flags(%r12),_TIF_ISOLATE_BP
 .Lsysc_restore:
        lg      %r14,__LC_VDSO_PER_CPU
        lmg     %r0,%r10,__PT_R0(%r11)
@@ -481,7 +628,7 @@ ENTRY(system_call)
        lmg     %r3,%r7,__PT_R3(%r11)
        stg     %r7,STACK_FRAME_OVERHEAD(%r15)
        lg      %r2,__PT_ORIG_GPR2(%r11)
-       basr    %r14,%r9                # call sys_xxx
+       BASR_R14_R9                     # call sys_xxx
        stg     %r2,__PT_R2(%r11)       # store return value
 .Lsysc_tracenogo:
        TSTMSK  __TI_flags(%r12),_TIF_TRACE
@@ -505,7 +652,7 @@ ENTRY(ret_from_fork)
        lmg     %r9,%r10,__PT_R9(%r11)  # load gprs
 ENTRY(kernel_thread_starter)
        la      %r2,0(%r10)
-       basr    %r14,%r9
+       BASR_R14_R9
        j       .Lsysc_tracenogo
 
 /*
@@ -514,6 +661,7 @@ ENTRY(kernel_thread_starter)
 
 ENTRY(pgm_check_handler)
        stpt    __LC_SYNC_ENTER_TIMER
+       BPOFF
        stmg    %r8,%r15,__LC_SAVE_AREA_SYNC
        lg      %r10,__LC_LAST_BREAK
        lg      %r12,__LC_CURRENT
@@ -540,6 +688,7 @@ ENTRY(pgm_check_handler)
        aghi    %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        j       4f
 2:     UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
+       BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
        lg      %r15,__LC_KERNEL_STACK
        lgr     %r14,%r12
        aghi    %r14,__TASK_thread      # pointer to thread_struct
@@ -550,6 +699,15 @@ ENTRY(pgm_check_handler)
 3:     stg     %r10,__THREAD_last_break(%r14)
 4:     la      %r11,STACK_FRAME_OVERHEAD(%r15)
        stmg    %r0,%r7,__PT_R0(%r11)
+       # clear user controlled registers to prevent speculative use
+       xgr     %r0,%r0
+       xgr     %r1,%r1
+       xgr     %r2,%r2
+       xgr     %r3,%r3
+       xgr     %r4,%r4
+       xgr     %r5,%r5
+       xgr     %r6,%r6
+       xgr     %r7,%r7
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
        stmg    %r8,%r9,__PT_PSW(%r11)
        mvc     __PT_INT_CODE(4,%r11),__LC_PGM_ILC
@@ -571,9 +729,9 @@ ENTRY(pgm_check_handler)
        nill    %r10,0x007f
        sll     %r10,2
        je      .Lpgm_return
-       lgf     %r1,0(%r10,%r1)         # load address of handler routine
+       lgf     %r9,0(%r10,%r1)         # load address of handler routine
        lgr     %r2,%r11                # pass pointer to pt_regs
-       basr    %r14,%r1                # branch to interrupt-handler
+       BASR_R14_R9                     # branch to interrupt-handler
 .Lpgm_return:
        LOCKDEP_SYS_EXIT
        tm      __PT_PSW+1(%r11),0x01   # returning to user ?
@@ -609,12 +767,23 @@ ENTRY(pgm_check_handler)
 ENTRY(io_int_handler)
        STCK    __LC_INT_CLOCK
        stpt    __LC_ASYNC_ENTER_TIMER
+       BPOFF
        stmg    %r8,%r15,__LC_SAVE_AREA_ASYNC
        lg      %r12,__LC_CURRENT
        larl    %r13,cleanup_critical
        lmg     %r8,%r9,__LC_IO_OLD_PSW
        SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER
        stmg    %r0,%r7,__PT_R0(%r11)
+       # clear user controlled registers to prevent speculative use
+       xgr     %r0,%r0
+       xgr     %r1,%r1
+       xgr     %r2,%r2
+       xgr     %r3,%r3
+       xgr     %r4,%r4
+       xgr     %r5,%r5
+       xgr     %r6,%r6
+       xgr     %r7,%r7
+       xgr     %r10,%r10
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
        stmg    %r8,%r9,__PT_PSW(%r11)
        mvc     __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
@@ -649,9 +818,13 @@ ENTRY(io_int_handler)
        lg      %r14,__LC_VDSO_PER_CPU
        lmg     %r0,%r10,__PT_R0(%r11)
        mvc     __LC_RETURN_PSW(16),__PT_PSW(%r11)
+       tm      __PT_PSW+1(%r11),0x01   # returning to user ?
+       jno     .Lio_exit_kernel
+       BPEXIT  __TI_flags(%r12),_TIF_ISOLATE_BP
 .Lio_exit_timer:
        stpt    __LC_EXIT_TIMER
        mvc     __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
+.Lio_exit_kernel:
        lmg     %r11,%r15,__PT_R11(%r11)
        lpswe   __LC_RETURN_PSW
 .Lio_done:
@@ -814,12 +987,23 @@ ENTRY(io_int_handler)
 ENTRY(ext_int_handler)
        STCK    __LC_INT_CLOCK
        stpt    __LC_ASYNC_ENTER_TIMER
+       BPOFF
        stmg    %r8,%r15,__LC_SAVE_AREA_ASYNC
        lg      %r12,__LC_CURRENT
        larl    %r13,cleanup_critical
        lmg     %r8,%r9,__LC_EXT_OLD_PSW
        SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER
        stmg    %r0,%r7,__PT_R0(%r11)
+       # clear user controlled registers to prevent speculative use
+       xgr     %r0,%r0
+       xgr     %r1,%r1
+       xgr     %r2,%r2
+       xgr     %r3,%r3
+       xgr     %r4,%r4
+       xgr     %r5,%r5
+       xgr     %r6,%r6
+       xgr     %r7,%r7
+       xgr     %r10,%r10
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
        stmg    %r8,%r9,__PT_PSW(%r11)
        lghi    %r1,__LC_EXT_PARAMS2
@@ -852,11 +1036,12 @@ ENTRY(psw_idle)
 .Lpsw_idle_stcctm:
 #endif
        oi      __LC_CPU_FLAGS+7,_CIF_ENABLED_WAIT
+       BPON
        STCK    __CLOCK_IDLE_ENTER(%r2)
        stpt    __TIMER_IDLE_ENTER(%r2)
 .Lpsw_idle_lpsw:
        lpswe   __SF_EMPTY(%r15)
-       br      %r14
+       BR_R1USE_R14
 .Lpsw_idle_end:
 
 /*
@@ -870,7 +1055,7 @@ ENTRY(save_fpu_regs)
        lg      %r2,__LC_CURRENT
        aghi    %r2,__TASK_thread
        TSTMSK  __LC_CPU_FLAGS,_CIF_FPU
-       bor     %r14
+       jo      .Lsave_fpu_regs_exit
        stfpc   __THREAD_FPU_fpc(%r2)
        lg      %r3,__THREAD_FPU_regs(%r2)
        TSTMSK  __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
@@ -897,7 +1082,8 @@ ENTRY(save_fpu_regs)
        std     15,120(%r3)
 .Lsave_fpu_regs_done:
        oi      __LC_CPU_FLAGS+7,_CIF_FPU
-       br      %r14
+.Lsave_fpu_regs_exit:
+       BR_R1USE_R14
 .Lsave_fpu_regs_end:
 EXPORT_SYMBOL(save_fpu_regs)
 
@@ -915,7 +1101,7 @@ load_fpu_regs:
        lg      %r4,__LC_CURRENT
        aghi    %r4,__TASK_thread
        TSTMSK  __LC_CPU_FLAGS,_CIF_FPU
-       bnor    %r14
+       jno     .Lload_fpu_regs_exit
        lfpc    __THREAD_FPU_fpc(%r4)
        TSTMSK  __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
        lg      %r4,__THREAD_FPU_regs(%r4)      # %r4 <- reg save area
@@ -942,7 +1128,8 @@ load_fpu_regs:
        ld      15,120(%r4)
 .Lload_fpu_regs_done:
        ni      __LC_CPU_FLAGS+7,255-_CIF_FPU
-       br      %r14
+.Lload_fpu_regs_exit:
+       BR_R1USE_R14
 .Lload_fpu_regs_end:
 
 .L__critical_end:
@@ -952,6 +1139,7 @@ load_fpu_regs:
  */
 ENTRY(mcck_int_handler)
        STCK    __LC_MCCK_CLOCK
+       BPOFF
        la      %r1,4095                # revalidate r1
        spt     __LC_CPU_TIMER_SAVE_AREA-4095(%r1)      # revalidate cpu timer
        lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
@@ -982,6 +1170,16 @@ ENTRY(mcck_int_handler)
 .Lmcck_skip:
        lghi    %r14,__LC_GPREGS_SAVE_AREA+64
        stmg    %r0,%r7,__PT_R0(%r11)
+       # clear user controlled registers to prevent speculative use
+       xgr     %r0,%r0
+       xgr     %r1,%r1
+       xgr     %r2,%r2
+       xgr     %r3,%r3
+       xgr     %r4,%r4
+       xgr     %r5,%r5
+       xgr     %r6,%r6
+       xgr     %r7,%r7
+       xgr     %r10,%r10
        mvc     __PT_R8(64,%r11),0(%r14)
        stmg    %r8,%r9,__PT_PSW(%r11)
        xc      __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
@@ -1007,6 +1205,7 @@ ENTRY(mcck_int_handler)
        mvc     __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW
        tm      __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
        jno     0f
+       BPEXIT  __TI_flags(%r12),_TIF_ISOLATE_BP
        stpt    __LC_EXIT_TIMER
        mvc     __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
 0:     lmg     %r11,%r15,__PT_R11(%r11)
@@ -1102,7 +1301,7 @@ cleanup_critical:
        jl      0f
        clg     %r9,BASED(.Lcleanup_table+104)  # .Lload_fpu_regs_end
        jl      .Lcleanup_load_fpu_regs
-0:     br      %r14
+0:     BR_R11USE_R14
 
        .align  8
 .Lcleanup_table:
@@ -1133,11 +1332,12 @@ cleanup_critical:
        clg     %r9,BASED(.Lsie_crit_mcck_length)
        jh      1f
        oi      __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
-1:     lg      %r9,__SF_EMPTY(%r15)            # get control block pointer
+1:     BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
+       lg      %r9,__SF_EMPTY(%r15)            # get control block pointer
        ni      __SIE_PROG0C+3(%r9),0xfe        # no longer in SIE
        lctlg   %c1,%c1,__LC_USER_ASCE          # load primary asce
        larl    %r9,sie_exit                    # skip forward to sie_exit
-       br      %r14
+       BR_R11USE_R14
 #endif
 
 .Lcleanup_system_call:
@@ -1175,6 +1375,7 @@ cleanup_critical:
        stg     %r15,__LC_SYSTEM_TIMER
 0:     # update accounting time stamp
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+       BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
        # set up saved register r11
        lg      %r15,__LC_KERNEL_STACK
        la      %r9,STACK_FRAME_OVERHEAD(%r15)
@@ -1190,7 +1391,7 @@ cleanup_critical:
        stg     %r15,56(%r11)           # r15 stack pointer
        # set new psw address and exit
        larl    %r9,.Lsysc_do_svc
-       br      %r14
+       BR_R11USE_R14
 .Lcleanup_system_call_insn:
        .quad   system_call
        .quad   .Lsysc_stmg
@@ -1202,7 +1403,7 @@ cleanup_critical:
 
 .Lcleanup_sysc_tif:
        larl    %r9,.Lsysc_tif
-       br      %r14
+       BR_R11USE_R14
 
 .Lcleanup_sysc_restore:
        # check if stpt has been executed
@@ -1219,14 +1420,14 @@ cleanup_critical:
        mvc     0(64,%r11),__PT_R8(%r9)
        lmg     %r0,%r7,__PT_R0(%r9)
 1:     lmg     %r8,%r9,__LC_RETURN_PSW
-       br      %r14
+       BR_R11USE_R14
 .Lcleanup_sysc_restore_insn:
        .quad   .Lsysc_exit_timer
        .quad   .Lsysc_done - 4
 
 .Lcleanup_io_tif:
        larl    %r9,.Lio_tif
-       br      %r14
+       BR_R11USE_R14
 
 .Lcleanup_io_restore:
        # check if stpt has been executed
@@ -1240,7 +1441,7 @@ cleanup_critical:
        mvc     0(64,%r11),__PT_R8(%r9)
        lmg     %r0,%r7,__PT_R0(%r9)
 1:     lmg     %r8,%r9,__LC_RETURN_PSW
-       br      %r14
+       BR_R11USE_R14
 .Lcleanup_io_restore_insn:
        .quad   .Lio_exit_timer
        .quad   .Lio_done - 4
@@ -1293,17 +1494,17 @@ cleanup_critical:
        # prepare return psw
        nihh    %r8,0xfcfd              # clear irq & wait state bits
        lg      %r9,48(%r11)            # return from psw_idle
-       br      %r14
+       BR_R11USE_R14
 .Lcleanup_idle_insn:
        .quad   .Lpsw_idle_lpsw
 
 .Lcleanup_save_fpu_regs:
        larl    %r9,save_fpu_regs
-       br      %r14
+       BR_R11USE_R14
 
 .Lcleanup_load_fpu_regs:
        larl    %r9,load_fpu_regs
-       br      %r14
+       BR_R11USE_R14
 
 /*
  * Integer constants
@@ -1323,7 +1524,6 @@ cleanup_critical:
 .Lsie_crit_mcck_length:
        .quad   .Lsie_skip - .Lsie_entry
 #endif
-
        .section .rodata, "a"
 #define SYSCALL(esame,emu)     .long esame
        .globl  sys_call_table
index d1a0e2c521d70470e6f9c15b4712de4179db8d0c..b565e784bae82c7a18237aabdef79126a4c723e8 100644 (file)
@@ -564,6 +564,7 @@ static struct kset *ipl_kset;
 
 static void __ipl_run(void *unused)
 {
+       __bpon();
        diag308(DIAG308_LOAD_CLEAR, NULL);
        if (MACHINE_IS_VM)
                __cpcmd("IPL", NULL, 0, NULL);
index 1a27f307a92079e79ead66c5e50e4f54e992530c..b441e069e674f53fc23948179a7bdc0f170902da 100644 (file)
@@ -31,6 +31,9 @@
 #include <linux/kernel.h>
 #include <linux/moduleloader.h>
 #include <linux/bug.h>
+#include <asm/alternative.h>
+#include <asm/nospec-branch.h>
+#include <asm/facility.h>
 
 #if 0
 #define DEBUGP printk
@@ -168,7 +171,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
        me->arch.got_offset = me->core_layout.size;
        me->core_layout.size += me->arch.got_size;
        me->arch.plt_offset = me->core_layout.size;
-       me->core_layout.size += me->arch.plt_size;
+       if (me->arch.plt_size) {
+               if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable)
+                       me->arch.plt_size += PLT_ENTRY_SIZE;
+               me->core_layout.size += me->arch.plt_size;
+       }
        return 0;
 }
 
@@ -322,9 +329,20 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
                        unsigned int *ip;
                        ip = me->core_layout.base + me->arch.plt_offset +
                                info->plt_offset;
-                       ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
-                       ip[1] = 0x100a0004;
-                       ip[2] = 0x07f10000;
+                       ip[0] = 0x0d10e310;     /* basr 1,0  */
+                       ip[1] = 0x100a0004;     /* lg   1,10(1) */
+                       if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) {
+                               unsigned int *ij;
+                               ij = me->core_layout.base +
+                                       me->arch.plt_offset +
+                                       me->arch.plt_size - PLT_ENTRY_SIZE;
+                               ip[2] = 0xa7f40000 +    /* j __jump_r1 */
+                                       (unsigned int)(u16)
+                                       (((unsigned long) ij - 8 -
+                                         (unsigned long) ip) / 2);
+                       } else {
+                               ip[2] = 0x07f10000;     /* br %r1 */
+                       }
                        ip[3] = (unsigned int) (val >> 32);
                        ip[4] = (unsigned int) val;
                        info->plt_initialized = 1;
@@ -429,6 +447,45 @@ int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
 {
+       const Elf_Shdr *s;
+       char *secstrings, *secname;
+       void *aseg;
+
+       if (IS_ENABLED(CONFIG_EXPOLINE) &&
+           !nospec_disable && me->arch.plt_size) {
+               unsigned int *ij;
+
+               ij = me->core_layout.base + me->arch.plt_offset +
+                       me->arch.plt_size - PLT_ENTRY_SIZE;
+               if (test_facility(35)) {
+                       ij[0] = 0xc6000000;     /* exrl %r0,.+10        */
+                       ij[1] = 0x0005a7f4;     /* j    .               */
+                       ij[2] = 0x000007f1;     /* br   %r1             */
+               } else {
+                       ij[0] = 0x44000000 | (unsigned int)
+                               offsetof(struct lowcore, br_r1_trampoline);
+                       ij[1] = 0xa7f40000;     /* j    .               */
+               }
+       }
+
+       secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+       for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+               aseg = (void *) s->sh_addr;
+               secname = secstrings + s->sh_name;
+
+               if (!strcmp(".altinstructions", secname))
+                       /* patch .altinstructions */
+                       apply_alternatives(aseg, aseg + s->sh_size);
+
+               if (IS_ENABLED(CONFIG_EXPOLINE) &&
+                   (!strncmp(".s390_indirect", secname, 14)))
+                       nospec_revert(aseg, aseg + s->sh_size);
+
+               if (IS_ENABLED(CONFIG_EXPOLINE) &&
+                   (!strncmp(".s390_return", secname, 12)))
+                       nospec_revert(aseg, aseg + s->sh_size);
+       }
+
        jump_label_apply_nops(me);
        return 0;
 }
diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c
new file mode 100644 (file)
index 0000000..9f3b5b3
--- /dev/null
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/module.h>
+#include <linux/device.h>
+#include <asm/facility.h>
+#include <asm/nospec-branch.h>
+
+static int __init nobp_setup_early(char *str)
+{
+       bool enabled;
+       int rc;
+
+       rc = kstrtobool(str, &enabled);
+       if (rc)
+               return rc;
+       if (enabled && test_facility(82)) {
+               /*
+                * The user explicitely requested nobp=1, enable it and
+                * disable the expoline support.
+                */
+               __set_facility(82, S390_lowcore.alt_stfle_fac_list);
+               if (IS_ENABLED(CONFIG_EXPOLINE))
+                       nospec_disable = 1;
+       } else {
+               __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+       }
+       return 0;
+}
+early_param("nobp", nobp_setup_early);
+
+static int __init nospec_setup_early(char *str)
+{
+       __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+       return 0;
+}
+early_param("nospec", nospec_setup_early);
+
+static int __init nospec_report(void)
+{
+       if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable)
+               pr_info("Spectre V2 mitigation: execute trampolines.\n");
+       if (__test_facility(82, S390_lowcore.alt_stfle_fac_list))
+               pr_info("Spectre V2 mitigation: limited branch prediction.\n");
+       return 0;
+}
+arch_initcall(nospec_report);
+
+#ifdef CONFIG_SYSFS
+ssize_t cpu_show_spectre_v1(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "Mitigation: __user pointer sanitization\n");
+}
+
+ssize_t cpu_show_spectre_v2(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable)
+               return sprintf(buf, "Mitigation: execute trampolines\n");
+       if (__test_facility(82, S390_lowcore.alt_stfle_fac_list))
+               return sprintf(buf, "Mitigation: limited branch prediction.\n");
+       return sprintf(buf, "Vulnerable\n");
+}
+#endif
+
+#ifdef CONFIG_EXPOLINE
+
+int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF);
+
+static int __init nospectre_v2_setup_early(char *str)
+{
+       nospec_disable = 1;
+       return 0;
+}
+early_param("nospectre_v2", nospectre_v2_setup_early);
+
+void __init nospec_auto_detect(void)
+{
+       if (IS_ENABLED(CC_USING_EXPOLINE)) {
+               /*
+                * The kernel has been compiled with expolines.
+                * Keep expolines enabled and disable nobp.
+                */
+               nospec_disable = 0;
+               __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+       }
+       /*
+        * If the kernel has not been compiled with expolines the
+        * nobp setting decides what is done, this depends on the
+        * CONFIG_KERNEL_NP option and the nobp/nospec parameters.
+        */
+}
+
+static int __init spectre_v2_setup_early(char *str)
+{
+       if (str && !strncmp(str, "on", 2)) {
+               nospec_disable = 0;
+               __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+       }
+       if (str && !strncmp(str, "off", 3))
+               nospec_disable = 1;
+       if (str && !strncmp(str, "auto", 4))
+               nospec_auto_detect();
+       return 0;
+}
+early_param("spectre_v2", spectre_v2_setup_early);
+
+static void __init_or_module __nospec_revert(s32 *start, s32 *end)
+{
+       enum { BRCL_EXPOLINE, BRASL_EXPOLINE } type;
+       u8 *instr, *thunk, *br;
+       u8 insnbuf[6];
+       s32 *epo;
+
+       /* Second part of the instruction replace is always a nop */
+       memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x00, 0x00 }, 4);
+       for (epo = start; epo < end; epo++) {
+               instr = (u8 *) epo + *epo;
+               if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04)
+                       type = BRCL_EXPOLINE;   /* brcl instruction */
+               else if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x05)
+                       type = BRASL_EXPOLINE;  /* brasl instruction */
+               else
+                       continue;
+               thunk = instr + (*(int *)(instr + 2)) * 2;
+               if (thunk[0] == 0xc6 && thunk[1] == 0x00)
+                       /* exrl %r0,<target-br> */
+                       br = thunk + (*(int *)(thunk + 2)) * 2;
+               else if (thunk[0] == 0xc0 && (thunk[1] & 0x0f) == 0x00 &&
+                        thunk[6] == 0x44 && thunk[7] == 0x00 &&
+                        (thunk[8] & 0x0f) == 0x00 && thunk[9] == 0x00 &&
+                        (thunk[1] & 0xf0) == (thunk[8] & 0xf0))
+                       /* larl %rx,<target br> + ex %r0,0(%rx) */
+                       br = thunk + (*(int *)(thunk + 2)) * 2;
+               else
+                       continue;
+               if (br[0] != 0x07 || (br[1] & 0xf0) != 0xf0)
+                       continue;
+               switch (type) {
+               case BRCL_EXPOLINE:
+                       /* brcl to thunk, replace with br + nop */
+                       insnbuf[0] = br[0];
+                       insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
+                       break;
+               case BRASL_EXPOLINE:
+                       /* brasl to thunk, replace with basr + nop */
+                       insnbuf[0] = 0x0d;
+                       insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
+                       break;
+               }
+
+               s390_kernel_write(instr, insnbuf, 6);
+       }
+}
+
+void __init_or_module nospec_revert(s32 *start, s32 *end)
+{
+       if (nospec_disable)
+               __nospec_revert(start, end);
+}
+
+extern s32 __nospec_call_start[], __nospec_call_end[];
+extern s32 __nospec_return_start[], __nospec_return_end[];
+void __init nospec_init_branches(void)
+{
+       nospec_revert(__nospec_call_start, __nospec_call_end);
+       nospec_revert(__nospec_return_start, __nospec_return_end);
+}
+
+#endif /* CONFIG_EXPOLINE */
index 5362fd868d0d42e73eaf73c8abb63e7dc94d4580..6fe2e1875058bec89419d680bef0110249ba9ed3 100644 (file)
@@ -197,3 +197,21 @@ const struct seq_operations cpuinfo_op = {
        .stop   = c_stop,
        .show   = show_cpuinfo,
 };
+
+int s390_isolate_bp(void)
+{
+       if (!test_facility(82))
+               return -EOPNOTSUPP;
+       set_thread_flag(TIF_ISOLATE_BP);
+       return 0;
+}
+EXPORT_SYMBOL(s390_isolate_bp);
+
+int s390_isolate_bp_guest(void)
+{
+       if (!test_facility(82))
+               return -EOPNOTSUPP;
+       set_thread_flag(TIF_ISOLATE_BP_GUEST);
+       return 0;
+}
+EXPORT_SYMBOL(s390_isolate_bp_guest);
index 164a1e16b53edfb2d60da9e1a459630023bc392a..98c1f79411426a18384c2e6bcb645af91649842d 100644 (file)
@@ -66,6 +66,8 @@
 #include <asm/sclp.h>
 #include <asm/sysinfo.h>
 #include <asm/numa.h>
+#include <asm/alternative.h>
+#include <asm/nospec-branch.h>
 #include "entry.h"
 
 /*
@@ -338,7 +340,9 @@ static void __init setup_lowcore(void)
        lc->preempt_count = S390_lowcore.preempt_count;
        lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
        memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
-              MAX_FACILITY_BIT/8);
+              sizeof(lc->stfle_fac_list));
+       memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
+              sizeof(lc->alt_stfle_fac_list));
        if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
                unsigned long bits, size;
 
@@ -381,6 +385,7 @@ static void __init setup_lowcore(void)
 #ifdef CONFIG_SMP
        lc->spinlock_lockval = arch_spin_lockval(0);
 #endif
+       lc->br_r1_trampoline = 0x07f1;  /* br %r1 */
 
        set_prefix((u32)(unsigned long) lc);
        lowcore_ptr[0] = lc;
@@ -892,6 +897,9 @@ void __init setup_arch(char **cmdline_p)
        init_mm.end_data = (unsigned long) &_edata;
        init_mm.brk = (unsigned long) &_end;
 
+       if (IS_ENABLED(CONFIG_EXPOLINE_AUTO))
+               nospec_auto_detect();
+
        parse_early_param();
 #ifdef CONFIG_CRASH_DUMP
        /* Deactivate elfcorehdr= kernel parameter */
@@ -955,6 +963,10 @@ void __init setup_arch(char **cmdline_p)
        conmode_default();
        set_preferred_console();
 
+       apply_alternative_instructions();
+       if (IS_ENABLED(CONFIG_EXPOLINE))
+               nospec_init_branches();
+
        /* Setup zfcpdump support */
        setup_zfcpdump();
 
index 7ffaf9fd6d19796762a57504e44464fb0a24950b..ae5df41778037fd4ec5df4c422295dfaaa3da68e 100644 (file)
@@ -228,6 +228,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
        lc->mcesad = mcesa_origin | mcesa_bits;
        lc->cpu_nr = cpu;
        lc->spinlock_lockval = arch_spin_lockval(cpu);
+       lc->br_r1_trampoline = 0x07f1;  /* br %r1 */
        if (vdso_alloc_per_cpu(lc))
                goto out;
        lowcore_ptr[cpu] = lc;
@@ -282,7 +283,9 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
        __ctl_store(lc->cregs_save_area, 0, 15);
        save_access_regs((unsigned int *) lc->access_regs_save_area);
        memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
-              MAX_FACILITY_BIT/8);
+              sizeof(lc->stfle_fac_list));
+       memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
+              sizeof(lc->alt_stfle_fac_list));
 }
 
 static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
@@ -332,6 +335,7 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
        mem_assign_absolute(lc->restart_fn, (unsigned long) func);
        mem_assign_absolute(lc->restart_data, (unsigned long) data);
        mem_assign_absolute(lc->restart_source, source_cpu);
+       __bpon();
        asm volatile(
                "0:     sigp    0,%0,%2 # sigp restart to target cpu\n"
                "       brc     2,0b    # busy, try again\n"
@@ -907,6 +911,7 @@ void __cpu_die(unsigned int cpu)
 void __noreturn cpu_die(void)
 {
        idle_task_exit();
+       __bpon();
        pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
        for (;;) ;
 }
index d9d1f512f019415ed36912e7afd81156fbd284ae..5007fac01bb5e215392362768898cc829cc121d0 100644 (file)
@@ -150,6 +150,15 @@ unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline,
        return orig;
 }
 
+bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
+                            struct pt_regs *regs)
+{
+       if (ctx == RP_CHECK_CHAIN_CALL)
+               return user_stack_pointer(regs) <= ret->stack;
+       else
+               return user_stack_pointer(regs) < ret->stack;
+}
+
 /* Instruction Emulation */
 
 static void adjust_psw_addr(psw_t *psw, unsigned long len)
index 96a713a470e77a67a56c0b18f3db29b02ccf2471..85dd3c7bdd86bb7586d216c2691f854c94684e30 100644 (file)
@@ -105,6 +105,43 @@ SECTIONS
                EXIT_DATA
        }
 
+       /*
+        * struct alt_inst entries. From the header (alternative.h):
+        * "Alternative instructions for different CPU types or capabilities"
+        * Think locking instructions on spinlocks.
+        * Note, that it is a part of __init region.
+        */
+       . = ALIGN(8);
+       .altinstructions : {
+               __alt_instructions = .;
+               *(.altinstructions)
+               __alt_instructions_end = .;
+       }
+
+       /*
+        * And here are the replacement instructions. The linker sticks
+        * them as binary blobs. The .altinstructions has enough data to
+        * get the address and the length of them to patch the kernel safely.
+        * Note, that it is a part of __init region.
+        */
+       .altinstr_replacement : {
+               *(.altinstr_replacement)
+       }
+
+       /*
+        * Table with the patch locations to undo expolines
+       */
+       .nospec_call_table : {
+               __nospec_call_start = . ;
+               *(.s390_indirect*)
+               __nospec_call_end = . ;
+       }
+       .nospec_return_table : {
+               __nospec_return_start = . ;
+               *(.s390_return*)
+               __nospec_return_end = . ;
+       }
+
        /* early.c uses stsi, which requires page aligned data. */
        . = ALIGN(PAGE_SIZE);
        INIT_DATA_SECTION(0x100)
index 0bce918db11a4ac2f76a0d72c9513f4bf6d9968f..4f6adbea592b373902a6a30f43f7e4fedbbbe95e 100644 (file)
@@ -449,6 +449,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_S390_GS:
                r = test_facility(133);
                break;
+       case KVM_CAP_S390_BPB:
+               r = test_facility(82);
+               break;
        default:
                r = 0;
        }
@@ -2231,6 +2234,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
        kvm_s390_set_prefix(vcpu, 0);
        if (test_kvm_facility(vcpu->kvm, 64))
                vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
+       if (test_kvm_facility(vcpu->kvm, 82))
+               vcpu->run->kvm_valid_regs |= KVM_SYNC_BPBC;
        if (test_kvm_facility(vcpu->kvm, 133))
                vcpu->run->kvm_valid_regs |= KVM_SYNC_GSCB;
        /* fprs can be synchronized via vrs, even if the guest has no vx. With
@@ -2372,6 +2377,7 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
        current->thread.fpu.fpc = 0;
        vcpu->arch.sie_block->gbea = 1;
        vcpu->arch.sie_block->pp = 0;
+       vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
        vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
        kvm_clear_async_pf_completion_queue(vcpu);
        if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
@@ -3318,6 +3324,11 @@ static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT;
                vcpu->arch.gs_enabled = 1;
        }
+       if ((kvm_run->kvm_dirty_regs & KVM_SYNC_BPBC) &&
+           test_kvm_facility(vcpu->kvm, 82)) {
+               vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
+               vcpu->arch.sie_block->fpf |= kvm_run->s.regs.bpbc ? FPF_BPBC : 0;
+       }
        save_access_regs(vcpu->arch.host_acrs);
        restore_access_regs(vcpu->run->s.regs.acrs);
        /* save host (userspace) fprs/vrs */
@@ -3364,6 +3375,7 @@ static void store_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        kvm_run->s.regs.pft = vcpu->arch.pfault_token;
        kvm_run->s.regs.pfs = vcpu->arch.pfault_select;
        kvm_run->s.regs.pfc = vcpu->arch.pfault_compare;
+       kvm_run->s.regs.bpbc = (vcpu->arch.sie_block->fpf & FPF_BPBC) == FPF_BPBC;
        save_access_regs(vcpu->run->s.regs.acrs);
        restore_access_regs(vcpu->arch.host_acrs);
        /* Save guest register state */
index a74204db759b74725ff9f390e55b4dec5cf7a0f4..eb7b530d1783f7c8da48f0ff328e15a808a71b2f 100644 (file)
@@ -234,6 +234,12 @@ static void unshadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
        memcpy(scb_o->gcr, scb_s->gcr, 128);
        scb_o->pp = scb_s->pp;
 
+       /* branch prediction */
+       if (test_kvm_facility(vcpu->kvm, 82)) {
+               scb_o->fpf &= ~FPF_BPBC;
+               scb_o->fpf |= scb_s->fpf & FPF_BPBC;
+       }
+
        /* interrupt intercept */
        switch (scb_s->icptcode) {
        case ICPT_PROGI:
@@ -280,6 +286,7 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
        scb_s->ecb3 = 0;
        scb_s->ecd = 0;
        scb_s->fac = 0;
+       scb_s->fpf = 0;
 
        rc = prepare_cpuflags(vcpu, vsie_page);
        if (rc)
@@ -339,6 +346,9 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
                        prefix_unmapped(vsie_page);
                scb_s->ecb |= ECB_TE;
        }
+       /* branch prediction */
+       if (test_kvm_facility(vcpu->kvm, 82))
+               scb_s->fpf |= scb_o->fpf & FPF_BPBC;
        /* SIMD */
        if (test_kvm_facility(vcpu->kvm, 129)) {
                scb_s->eca |= scb_o->eca & ECA_VX;
@@ -821,6 +831,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 {
        struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
        struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+       int guest_bp_isolation;
        int rc;
 
        handle_last_fault(vcpu, vsie_page);
@@ -831,6 +842,20 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
                s390_handle_mcck();
 
        srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
+
+       /* save current guest state of bp isolation override */
+       guest_bp_isolation = test_thread_flag(TIF_ISOLATE_BP_GUEST);
+
+       /*
+        * The guest is running with BPBC, so we have to force it on for our
+        * nested guest. This is done by enabling BPBC globally, so the BPBC
+        * control in the SCB (which the nested guest can modify) is simply
+        * ignored.
+        */
+       if (test_kvm_facility(vcpu->kvm, 82) &&
+           vcpu->arch.sie_block->fpf & FPF_BPBC)
+               set_thread_flag(TIF_ISOLATE_BP_GUEST);
+
        local_irq_disable();
        guest_enter_irqoff();
        local_irq_enable();
@@ -840,6 +865,11 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
        local_irq_disable();
        guest_exit_irqoff();
        local_irq_enable();
+
+       /* restore guest state for bp isolation override */
+       if (!guest_bp_isolation)
+               clear_thread_flag(TIF_ISOLATE_BP_GUEST);
+
        vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
 
        if (rc == -EINTR) {
index f53ccc68023819ad0c33e6f6728ffc5ffe4ad232..dbdd460a995865618c784840d0728fd0933d1560 100644 (file)
@@ -2123,6 +2123,25 @@ static int __init intel_opregion_present(void)
        return opregion;
 }
 
+static bool dmi_is_desktop(void)
+{
+       const char *chassis_type;
+
+       chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
+       if (!chassis_type)
+               return false;
+
+       if (!strcmp(chassis_type, "3") || /*  3: Desktop */
+           !strcmp(chassis_type, "4") || /*  4: Low Profile Desktop */
+           !strcmp(chassis_type, "5") || /*  5: Pizza Box */
+           !strcmp(chassis_type, "6") || /*  6: Mini Tower */
+           !strcmp(chassis_type, "7") || /*  7: Tower */
+           !strcmp(chassis_type, "11"))  /* 11: Main Server Chassis */
+               return true;
+
+       return false;
+}
+
 int acpi_video_register(void)
 {
        int ret = 0;
@@ -2143,8 +2162,12 @@ int acpi_video_register(void)
         * win8 ready (where we also prefer the native backlight driver, so
         * normally the acpi_video code should not register there anyways).
         */
-       if (only_lcd == -1)
-               only_lcd = acpi_osi_is_win8();
+       if (only_lcd == -1) {
+               if (dmi_is_desktop() && acpi_osi_is_win8())
+                       only_lcd = true;
+               else
+                       only_lcd = false;
+       }
 
        dmi_check_system(video_dmi_table);
 
index 84434d3ea19b8f3a7500972219b952a6b84072a2..e88d50f75a4a3ecf62e4a086e2676731243aa386 100644 (file)
@@ -110,7 +110,7 @@ struct iwm {
 /* Select values for swim_select and swim_readbit */
 
 #define READ_DATA_0    0x074
-#define TWOMEG_DRIVE   0x075
+#define ONEMEG_DRIVE   0x075
 #define SINGLE_SIDED   0x076
 #define DRIVE_PRESENT  0x077
 #define DISK_IN                0x170
@@ -118,9 +118,9 @@ struct iwm {
 #define TRACK_ZERO     0x172
 #define TACHO          0x173
 #define READ_DATA_1    0x174
-#define MFM_MODE       0x175
+#define GCR_MODE       0x175
 #define SEEK_COMPLETE  0x176
-#define ONEMEG_MEDIA   0x177
+#define TWOMEG_MEDIA   0x177
 
 /* Bits in handshake register */
 
@@ -612,7 +612,6 @@ static void setup_medium(struct floppy_state *fs)
                struct floppy_struct *g;
                fs->disk_in = 1;
                fs->write_protected = swim_readbit(base, WRITE_PROT);
-               fs->type = swim_readbit(base, ONEMEG_MEDIA);
 
                if (swim_track00(base))
                        printk(KERN_ERR
@@ -620,6 +619,9 @@ static void setup_medium(struct floppy_state *fs)
 
                swim_track00(base);
 
+               fs->type = swim_readbit(base, TWOMEG_MEDIA) ?
+                       HD_MEDIA : DD_MEDIA;
+               fs->head_number = swim_readbit(base, SINGLE_SIDED) ? 1 : 2;
                get_floppy_geometry(fs, 0, &g);
                fs->total_secs = g->size;
                fs->secpercyl = g->head * g->sect;
@@ -646,7 +648,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
 
        swim_write(base, setup, S_IBM_DRIVE  | S_FCLK_DIV2);
        udelay(10);
-       swim_drive(base, INTERNAL_DRIVE);
+       swim_drive(base, fs->location);
        swim_motor(base, ON);
        swim_action(base, SETMFM);
        if (fs->ejected)
@@ -656,6 +658,8 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
                goto out;
        }
 
+       set_capacity(fs->disk, fs->total_secs);
+
        if (mode & FMODE_NDELAY)
                return 0;
 
@@ -727,14 +731,9 @@ static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
                if (copy_to_user((void __user *) param, (void *) &floppy_type,
                                 sizeof(struct floppy_struct)))
                        return -EFAULT;
-               break;
-
-       default:
-               printk(KERN_DEBUG "SWIM floppy_ioctl: unknown cmd %d\n",
-                      cmd);
-               return -ENOSYS;
+               return 0;
        }
-       return 0;
+       return -ENOTTY;
 }
 
 static int floppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
@@ -795,7 +794,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
        struct swim_priv *swd = data;
        int drive = (*part & 3);
 
-       if (drive > swd->floppy_count)
+       if (drive >= swd->floppy_count)
                return NULL;
 
        *part = 0;
@@ -813,10 +812,9 @@ static int swim_add_floppy(struct swim_priv *swd, enum drive_location location)
 
        swim_motor(base, OFF);
 
-       if (swim_readbit(base, SINGLE_SIDED))
-               fs->head_number = 1;
-       else
-               fs->head_number = 2;
+       fs->type = HD_MEDIA;
+       fs->head_number = 2;
+
        fs->ref_count = 0;
        fs->ejected = 1;
 
@@ -834,10 +832,12 @@ static int swim_floppy_init(struct swim_priv *swd)
        /* scan floppy drives */
 
        swim_drive(base, INTERNAL_DRIVE);
-       if (swim_readbit(base, DRIVE_PRESENT))
+       if (swim_readbit(base, DRIVE_PRESENT) &&
+           !swim_readbit(base, ONEMEG_DRIVE))
                swim_add_floppy(swd, INTERNAL_DRIVE);
        swim_drive(base, EXTERNAL_DRIVE);
-       if (swim_readbit(base, DRIVE_PRESENT))
+       if (swim_readbit(base, DRIVE_PRESENT) &&
+           !swim_readbit(base, ONEMEG_DRIVE))
                swim_add_floppy(swd, EXTERNAL_DRIVE);
 
        /* register floppy drives */
@@ -861,7 +861,6 @@ static int swim_floppy_init(struct swim_priv *swd)
                                                              &swd->lock);
                if (!swd->unit[drive].disk->queue) {
                        err = -ENOMEM;
-                       put_disk(swd->unit[drive].disk);
                        goto exit_put_disks;
                }
                blk_queue_bounce_limit(swd->unit[drive].disk->queue,
@@ -911,7 +910,7 @@ static int swim_probe(struct platform_device *dev)
                goto out;
        }
 
-       swim_base = ioremap(res->start, resource_size(res));
+       swim_base = (struct swim __iomem *)res->start;
        if (!swim_base) {
                ret = -ENOMEM;
                goto out_release_io;
@@ -923,7 +922,7 @@ static int swim_probe(struct platform_device *dev)
        if (!get_swim_mode(swim_base)) {
                printk(KERN_INFO "SWIM device not found !\n");
                ret = -ENODEV;
-               goto out_iounmap;
+               goto out_release_io;
        }
 
        /* set platform driver data */
@@ -931,7 +930,7 @@ static int swim_probe(struct platform_device *dev)
        swd = kzalloc(sizeof(struct swim_priv), GFP_KERNEL);
        if (!swd) {
                ret = -ENOMEM;
-               goto out_iounmap;
+               goto out_release_io;
        }
        platform_set_drvdata(dev, swd);
 
@@ -945,8 +944,6 @@ static int swim_probe(struct platform_device *dev)
 
 out_kfree:
        kfree(swd);
-out_iounmap:
-       iounmap(swim_base);
 out_release_io:
        release_mem_region(res->start, resource_size(res));
 out:
@@ -974,8 +971,6 @@ static int swim_remove(struct platform_device *dev)
        for (drive = 0; drive < swd->floppy_count; drive++)
                floppy_eject(&swd->unit[drive]);
 
-       iounmap(swd->base);
-
        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (res)
                release_mem_region(res->start, resource_size(res));
index 9f931f8f6b4ced797175c95bf77fe455469ef463..0d7527c6825a913f3ff4f75e03d49602be73cacc 100644 (file)
@@ -148,7 +148,7 @@ struct swim3 {
 #define MOTOR_ON       2
 #define RELAX          3       /* also eject in progress */
 #define READ_DATA_0    4
-#define TWOMEG_DRIVE   5
+#define ONEMEG_DRIVE   5
 #define SINGLE_SIDED   6       /* drive or diskette is 4MB type? */
 #define DRIVE_PRESENT  7
 #define DISK_IN                8
@@ -156,9 +156,9 @@ struct swim3 {
 #define TRACK_ZERO     10
 #define TACHO          11
 #define READ_DATA_1    12
-#define MFM_MODE       13
+#define GCR_MODE       13
 #define SEEK_COMPLETE  14
-#define ONEMEG_MEDIA   15
+#define TWOMEG_MEDIA   15
 
 /* Definitions of values used in writing and formatting */
 #define DATA_ESCAPE    0x99
index e36d160c458fdb334556129b9559d147aefb2472..5f7d86509f2f523fc48c7c5fe3dc616cdfafadec 100644 (file)
@@ -2374,7 +2374,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
        if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
                return media_changed(cdi, 1);
 
-       if ((unsigned int)arg >= cdi->capacity)
+       if (arg >= cdi->capacity)
                return -EINVAL;
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
index 1d01a8f77db17847feef367b7bbe09919447cb97..dba5259def6038645dbe24d95f0243c0b6282443 100644 (file)
@@ -369,20 +369,40 @@ err_len:
        return -EINVAL;
 }
 
-/**
- * tmp_transmit - Internal kernel interface to transmit TPM commands.
- *
- * @chip: TPM chip to use
- * @buf: TPM command buffer
- * @bufsiz: length of the TPM command buffer
- * @flags: tpm transmit flags - bitmap
- *
- * Return:
- *     0 when the operation is successful.
- *     A negative number for system errors (errno).
- */
-ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
-                    u8 *buf, size_t bufsiz, unsigned int flags)
+static int tpm_request_locality(struct tpm_chip *chip)
+{
+       int rc;
+
+       if (!chip->ops->request_locality)
+               return 0;
+
+       rc = chip->ops->request_locality(chip, 0);
+       if (rc < 0)
+               return rc;
+
+       chip->locality = rc;
+
+       return 0;
+}
+
+static void tpm_relinquish_locality(struct tpm_chip *chip)
+{
+       int rc;
+
+       if (!chip->ops->relinquish_locality)
+               return;
+
+       rc = chip->ops->relinquish_locality(chip, chip->locality);
+       if (rc)
+               dev_err(&chip->dev, "%s: : error %d\n", __func__, rc);
+
+       chip->locality = -1;
+}
+
+static ssize_t tpm_try_transmit(struct tpm_chip *chip,
+                               struct tpm_space *space,
+                               u8 *buf, size_t bufsiz,
+                               unsigned int flags)
 {
        struct tpm_output_header *header = (void *)buf;
        int rc;
@@ -422,8 +442,6 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
        if (!(flags & TPM_TRANSMIT_UNLOCKED))
                mutex_lock(&chip->tpm_mutex);
 
-       if (chip->dev.parent)
-               pm_runtime_get_sync(chip->dev.parent);
 
        if (chip->ops->clk_enable != NULL)
                chip->ops->clk_enable(chip, true);
@@ -431,14 +449,15 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
        /* Store the decision as chip->locality will be changed. */
        need_locality = chip->locality == -1;
 
-       if (!(flags & TPM_TRANSMIT_RAW) &&
-           need_locality && chip->ops->request_locality)  {
-               rc = chip->ops->request_locality(chip, 0);
+       if (!(flags & TPM_TRANSMIT_RAW) && need_locality) {
+               rc = tpm_request_locality(chip);
                if (rc < 0)
                        goto out_no_locality;
-               chip->locality = rc;
        }
 
+       if (chip->dev.parent)
+               pm_runtime_get_sync(chip->dev.parent);
+
        rc = tpm2_prepare_space(chip, space, ordinal, buf);
        if (rc)
                goto out;
@@ -499,27 +518,83 @@ out_recv:
        rc = tpm2_commit_space(chip, space, ordinal, buf, &len);
 
 out:
-       if (need_locality && chip->ops->relinquish_locality) {
-               chip->ops->relinquish_locality(chip, chip->locality);
-               chip->locality = -1;
-       }
+       if (chip->dev.parent)
+               pm_runtime_put_sync(chip->dev.parent);
+
+       if (need_locality)
+               tpm_relinquish_locality(chip);
+
 out_no_locality:
        if (chip->ops->clk_enable != NULL)
                chip->ops->clk_enable(chip, false);
 
-       if (chip->dev.parent)
-               pm_runtime_put_sync(chip->dev.parent);
-
        if (!(flags & TPM_TRANSMIT_UNLOCKED))
                mutex_unlock(&chip->tpm_mutex);
        return rc ? rc : len;
 }
 
 /**
- * tmp_transmit_cmd - send a tpm command to the device
+ * tpm_transmit - Internal kernel interface to transmit TPM commands.
+ *
+ * @chip: TPM chip to use
+ * @space: tpm space
+ * @buf: TPM command buffer
+ * @bufsiz: length of the TPM command buffer
+ * @flags: tpm transmit flags - bitmap
+ *
+ * A wrapper around tpm_try_transmit that handles TPM2_RC_RETRY
+ * returns from the TPM and retransmits the command after a delay up
+ * to a maximum wait of TPM2_DURATION_LONG.
+ *
+ * Note: TPM1 never returns TPM2_RC_RETRY so the retry logic is TPM2
+ * only
+ *
+ * Return:
+ *     the length of the return when the operation is successful.
+ *     A negative number for system errors (errno).
+ */
+ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
+                    u8 *buf, size_t bufsiz, unsigned int flags)
+{
+       struct tpm_output_header *header = (struct tpm_output_header *)buf;
+       /* space for header and handles */
+       u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)];
+       unsigned int delay_msec = TPM2_DURATION_SHORT;
+       u32 rc = 0;
+       ssize_t ret;
+       const size_t save_size = min(space ? sizeof(save) : TPM_HEADER_SIZE,
+                                    bufsiz);
+
+       /*
+        * Subtlety here: if we have a space, the handles will be
+        * transformed, so when we restore the header we also have to
+        * restore the handles.
+        */
+       memcpy(save, buf, save_size);
+
+       for (;;) {
+               ret = tpm_try_transmit(chip, space, buf, bufsiz, flags);
+               if (ret < 0)
+                       break;
+               rc = be32_to_cpu(header->return_code);
+               if (rc != TPM2_RC_RETRY)
+                       break;
+               delay_msec *= 2;
+               if (delay_msec > TPM2_DURATION_LONG) {
+                       dev_err(&chip->dev, "TPM is in retry loop\n");
+                       break;
+               }
+               tpm_msleep(delay_msec);
+               memcpy(buf, save, save_size);
+       }
+       return ret;
+}
+/**
+ * tpm_transmit_cmd - send a tpm command to the device
  *    The function extracts tpm out header return code
  *
  * @chip: TPM chip to use
+ * @space: tpm space
  * @buf: TPM command buffer
  * @bufsiz: length of the buffer
  * @min_rsp_body_length: minimum expected length of response body
index 0b5b499f726ad2551c359211010043e8e3a46667..b83b30a3eea5ef4e2de8b60a720d7dd571d45479 100644 (file)
@@ -106,6 +106,7 @@ enum tpm2_return_codes {
        TPM2_RC_COMMAND_CODE    = 0x0143,
        TPM2_RC_TESTING         = 0x090A, /* RC_WARN */
        TPM2_RC_REFERENCE_H0    = 0x0910,
+       TPM2_RC_RETRY           = 0x0922,
 };
 
 enum tpm2_algorithms {
index 8f0a98dea327a5bc90d7fcf3529c3701d17abd6b..bb756ad7897e7ca2b445cfa37a16a3edfd7926a6 100644 (file)
@@ -117,6 +117,25 @@ struct tpm2_crb_smc {
        u32 smc_func_id;
 };
 
+static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
+                               unsigned long timeout)
+{
+       ktime_t start;
+       ktime_t stop;
+
+       start = ktime_get();
+       stop = ktime_add(start, ms_to_ktime(timeout));
+
+       do {
+               if ((ioread32(reg) & mask) == value)
+                       return true;
+
+               usleep_range(50, 100);
+       } while (ktime_before(ktime_get(), stop));
+
+       return ((ioread32(reg) & mask) == value);
+}
+
 /**
  * crb_go_idle - request tpm crb device to go the idle state
  *
@@ -132,37 +151,24 @@ struct tpm2_crb_smc {
  *
  * Return: 0 always
  */
-static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv)
+static int crb_go_idle(struct device *dev, struct crb_priv *priv)
 {
        if ((priv->flags & CRB_FL_ACPI_START) ||
            (priv->flags & CRB_FL_CRB_SMC_START))
                return 0;
 
        iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req);
-       /* we don't really care when this settles */
 
+       if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_req,
+                                CRB_CTRL_REQ_GO_IDLE/* mask */,
+                                0, /* value */
+                                TPM2_TIMEOUT_C)) {
+               dev_warn(dev, "goIdle timed out\n");
+               return -ETIME;
+       }
        return 0;
 }
 
-static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
-                               unsigned long timeout)
-{
-       ktime_t start;
-       ktime_t stop;
-
-       start = ktime_get();
-       stop = ktime_add(start, ms_to_ktime(timeout));
-
-       do {
-               if ((ioread32(reg) & mask) == value)
-                       return true;
-
-               usleep_range(50, 100);
-       } while (ktime_before(ktime_get(), stop));
-
-       return false;
-}
-
 /**
  * crb_cmd_ready - request tpm crb device to enter ready state
  *
@@ -177,8 +183,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
  *
  * Return: 0 on success -ETIME on timeout;
  */
-static int __maybe_unused crb_cmd_ready(struct device *dev,
-                                       struct crb_priv *priv)
+static int crb_cmd_ready(struct device *dev, struct crb_priv *priv)
 {
        if ((priv->flags & CRB_FL_ACPI_START) ||
            (priv->flags & CRB_FL_CRB_SMC_START))
@@ -196,11 +201,11 @@ static int __maybe_unused crb_cmd_ready(struct device *dev,
        return 0;
 }
 
-static int crb_request_locality(struct tpm_chip *chip, int loc)
+static int __crb_request_locality(struct device *dev,
+                                 struct crb_priv *priv, int loc)
 {
-       struct crb_priv *priv = dev_get_drvdata(&chip->dev);
        u32 value = CRB_LOC_STATE_LOC_ASSIGNED |
-               CRB_LOC_STATE_TPM_REG_VALID_STS;
+                   CRB_LOC_STATE_TPM_REG_VALID_STS;
 
        if (!priv->regs_h)
                return 0;
@@ -208,21 +213,45 @@ static int crb_request_locality(struct tpm_chip *chip, int loc)
        iowrite32(CRB_LOC_CTRL_REQUEST_ACCESS, &priv->regs_h->loc_ctrl);
        if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, value, value,
                                 TPM2_TIMEOUT_C)) {
-               dev_warn(&chip->dev, "TPM_LOC_STATE_x.requestAccess timed out\n");
+               dev_warn(dev, "TPM_LOC_STATE_x.requestAccess timed out\n");
                return -ETIME;
        }
 
        return 0;
 }
 
-static void crb_relinquish_locality(struct tpm_chip *chip, int loc)
+static int crb_request_locality(struct tpm_chip *chip, int loc)
 {
        struct crb_priv *priv = dev_get_drvdata(&chip->dev);
 
+       return __crb_request_locality(&chip->dev, priv, loc);
+}
+
+static int __crb_relinquish_locality(struct device *dev,
+                                    struct crb_priv *priv, int loc)
+{
+       u32 mask = CRB_LOC_STATE_LOC_ASSIGNED |
+                  CRB_LOC_STATE_TPM_REG_VALID_STS;
+       u32 value = CRB_LOC_STATE_TPM_REG_VALID_STS;
+
        if (!priv->regs_h)
-               return;
+               return 0;
 
        iowrite32(CRB_LOC_CTRL_RELINQUISH, &priv->regs_h->loc_ctrl);
+       if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, mask, value,
+                                TPM2_TIMEOUT_C)) {
+               dev_warn(dev, "TPM_LOC_STATE_x.requestAccess timed out\n");
+               return -ETIME;
+       }
+
+       return 0;
+}
+
+static int crb_relinquish_locality(struct tpm_chip *chip, int loc)
+{
+       struct crb_priv *priv = dev_get_drvdata(&chip->dev);
+
+       return __crb_relinquish_locality(&chip->dev, priv, loc);
 }
 
 static u8 crb_status(struct tpm_chip *chip)
@@ -466,6 +495,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
                        dev_warn(dev, FW_BUG "Bad ACPI memory layout");
        }
 
+       ret = __crb_request_locality(dev, priv, 0);
+       if (ret)
+               return ret;
+
        priv->regs_t = crb_map_res(dev, priv, &io_res, buf->control_address,
                                   sizeof(struct crb_regs_tail));
        if (IS_ERR(priv->regs_t))
@@ -522,6 +555,8 @@ out:
 
        crb_go_idle(dev, priv);
 
+       __crb_relinquish_locality(dev, priv, 0);
+
        return ret;
 }
 
@@ -589,10 +624,14 @@ static int crb_acpi_add(struct acpi_device *device)
        chip->acpi_dev_handle = device->handle;
        chip->flags = TPM_CHIP_FLAG_TPM2;
 
-       rc  = crb_cmd_ready(dev, priv);
+       rc = __crb_request_locality(dev, priv, 0);
        if (rc)
                return rc;
 
+       rc  = crb_cmd_ready(dev, priv);
+       if (rc)
+               goto out;
+
        pm_runtime_get_noresume(dev);
        pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
@@ -602,12 +641,15 @@ static int crb_acpi_add(struct acpi_device *device)
                crb_go_idle(dev, priv);
                pm_runtime_put_noidle(dev);
                pm_runtime_disable(dev);
-               return rc;
+               goto out;
        }
 
-       pm_runtime_put(dev);
+       pm_runtime_put_sync(dev);
 
-       return 0;
+out:
+       __crb_relinquish_locality(dev, priv, 0);
+
+       return rc;
 }
 
 static int crb_acpi_remove(struct acpi_device *device)
index a21e31c2b952ed4b62b89b33879df4bf48e8ecda..58123df6b5f6bf77a8bcfb73e33b9a7e81572add 100644 (file)
@@ -77,11 +77,13 @@ static bool check_locality(struct tpm_chip *chip, int l)
        return false;
 }
 
-static void release_locality(struct tpm_chip *chip, int l)
+static int release_locality(struct tpm_chip *chip, int l)
 {
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
 
        tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
+
+       return 0;
 }
 
 static int request_locality(struct tpm_chip *chip, int l)
index bf14214fa4640279fa46b655333198ed5aa1446e..4db31b89507c5f6e5185583725c5bb3a1f641f28 100644 (file)
@@ -1634,6 +1634,8 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
         * (and possibly on the platform). So far only i.MX6Q (v1.30a) and
         * i.MX6DL (v1.31a) have been identified as needing the workaround, with
         * 4 and 1 iterations respectively.
+        * The Amlogic Meson GX SoCs (v2.01a) have been identified as needing
+        * the workaround with a single iteration.
         */
 
        switch (hdmi->version) {
@@ -1641,6 +1643,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
                count = 4;
                break;
        case 0x131a:
+       case 0x201a:
                count = 1;
                break;
        default:
index 345f6035599eaf91e20032fd1f5d819b9549729e..f1d93676b0fc72dc1e7f9a5effeb7605b19db17f 100644 (file)
@@ -1995,6 +1995,7 @@ static struct scsi_host_template mptsas_driver_template = {
        .cmd_per_lun                    = 7,
        .use_clustering                 = ENABLE_CLUSTERING,
        .shost_attrs                    = mptscsih_host_attrs,
+       .no_write_same                  = 1,
 };
 
 static int mptsas_get_linkerrors(struct sas_phy *phy)
index 82f28ffccddffdb01fbd6635775d07fe4e75ccd4..bf3be2e6d4a801c06fe4d3e6075f5ec4439e4fe5 100644 (file)
@@ -1656,8 +1656,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        } /* switch(bond_mode) */
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-       slave_dev->npinfo = bond->dev->npinfo;
-       if (slave_dev->npinfo) {
+       if (bond->dev->npinfo) {
                if (slave_enable_netpoll(new_slave)) {
                        netdev_info(bond_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n");
                        res = -EBUSY;
index 7ea72ef11a55d5a4425959da1d12c69b108676b2..d272dc6984ac6ef3f61743a16912c13552c35b2f 100644 (file)
 #define MDIO_VEND2_AN_STAT             0x8002
 #endif
 
+#ifndef MDIO_VEND2_PMA_CDR_CONTROL
+#define MDIO_VEND2_PMA_CDR_CONTROL     0x8056
+#endif
+
 #ifndef MDIO_CTRL1_SPEED1G
 #define MDIO_CTRL1_SPEED1G             (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
 #endif
 #define XGBE_AN_CL37_TX_CONFIG_MASK    0x08
 #define XGBE_AN_CL37_MII_CTRL_8BIT     0x0100
 
+#define XGBE_PMA_CDR_TRACK_EN_MASK     0x01
+#define XGBE_PMA_CDR_TRACK_EN_OFF      0x00
+#define XGBE_PMA_CDR_TRACK_EN_ON       0x01
+
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
  *  the variable
index 7d128be613103a1088655c4b1dcc2e10e234a82f..b91143947ed271a6d29c83040aae6f4304e1549d 100644 (file)
@@ -519,6 +519,22 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
                                   "debugfs_create_file failed\n");
        }
 
+       if (pdata->vdata->an_cdr_workaround) {
+               pfile = debugfs_create_bool("an_cdr_workaround", 0600,
+                                           pdata->xgbe_debugfs,
+                                           &pdata->debugfs_an_cdr_workaround);
+               if (!pfile)
+                       netdev_err(pdata->netdev,
+                                  "debugfs_create_bool failed\n");
+
+               pfile = debugfs_create_bool("an_cdr_track_early", 0600,
+                                           pdata->xgbe_debugfs,
+                                           &pdata->debugfs_an_cdr_track_early);
+               if (!pfile)
+                       netdev_err(pdata->netdev,
+                                  "debugfs_create_bool failed\n");
+       }
+
        kfree(buf);
 }
 
index d91fa595be9835318ce15a0b6b8ef6ef58bdf56a..e31d9d1fb6a66c34501fb76eade3ea961db33f4d 100644 (file)
@@ -349,6 +349,7 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
        XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
 
        /* Call MDIO/PHY initialization routine */
+       pdata->debugfs_an_cdr_workaround = pdata->vdata->an_cdr_workaround;
        ret = pdata->phy_if.phy_init(pdata);
        if (ret)
                return ret;
index 072b9f6645978d0c53ce40271b9dbfe44a6baa0a..1b45cd73a258f05211bfc2ca6e69124c5347bda8 100644 (file)
@@ -432,11 +432,16 @@ static void xgbe_an73_disable(struct xgbe_prv_data *pdata)
        xgbe_an73_set(pdata, false, false);
        xgbe_an73_disable_interrupts(pdata);
 
+       pdata->an_start = 0;
+
        netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n");
 }
 
 static void xgbe_an_restart(struct xgbe_prv_data *pdata)
 {
+       if (pdata->phy_if.phy_impl.an_pre)
+               pdata->phy_if.phy_impl.an_pre(pdata);
+
        switch (pdata->an_mode) {
        case XGBE_AN_MODE_CL73:
        case XGBE_AN_MODE_CL73_REDRV:
@@ -453,6 +458,9 @@ static void xgbe_an_restart(struct xgbe_prv_data *pdata)
 
 static void xgbe_an_disable(struct xgbe_prv_data *pdata)
 {
+       if (pdata->phy_if.phy_impl.an_post)
+               pdata->phy_if.phy_impl.an_post(pdata);
+
        switch (pdata->an_mode) {
        case XGBE_AN_MODE_CL73:
        case XGBE_AN_MODE_CL73_REDRV:
@@ -505,11 +513,11 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
                XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
                            reg);
 
-               if (pdata->phy_if.phy_impl.kr_training_post)
-                       pdata->phy_if.phy_impl.kr_training_post(pdata);
-
                netif_dbg(pdata, link, pdata->netdev,
                          "KR training initiated\n");
+
+               if (pdata->phy_if.phy_impl.kr_training_post)
+                       pdata->phy_if.phy_impl.kr_training_post(pdata);
        }
 
        return XGBE_AN_PAGE_RECEIVED;
@@ -637,11 +645,11 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
                        return XGBE_AN_NO_LINK;
        }
 
-       xgbe_an73_disable(pdata);
+       xgbe_an_disable(pdata);
 
        xgbe_switch_mode(pdata);
 
-       xgbe_an73_restart(pdata);
+       xgbe_an_restart(pdata);
 
        return XGBE_AN_INCOMPAT_LINK;
 }
@@ -820,6 +828,9 @@ static void xgbe_an37_state_machine(struct xgbe_prv_data *pdata)
                pdata->an_result = pdata->an_state;
                pdata->an_state = XGBE_AN_READY;
 
+               if (pdata->phy_if.phy_impl.an_post)
+                       pdata->phy_if.phy_impl.an_post(pdata);
+
                netif_dbg(pdata, link, pdata->netdev, "CL37 AN result: %s\n",
                          xgbe_state_as_string(pdata->an_result));
        }
@@ -903,6 +914,9 @@ again:
                pdata->kx_state = XGBE_RX_BPA;
                pdata->an_start = 0;
 
+               if (pdata->phy_if.phy_impl.an_post)
+                       pdata->phy_if.phy_impl.an_post(pdata);
+
                netif_dbg(pdata, link, pdata->netdev, "CL73 AN result: %s\n",
                          xgbe_state_as_string(pdata->an_result));
        }
index eb23f9ba1a9a10091f8d42bb71e35291e224c4f1..82d1f416ee2ac96c9aa2d7e5d70c22650e0407fe 100644 (file)
@@ -456,6 +456,7 @@ static const struct xgbe_version_data xgbe_v2a = {
        .irq_reissue_support            = 1,
        .tx_desc_prefetch               = 5,
        .rx_desc_prefetch               = 5,
+       .an_cdr_workaround              = 1,
 };
 
 static const struct xgbe_version_data xgbe_v2b = {
@@ -470,6 +471,7 @@ static const struct xgbe_version_data xgbe_v2b = {
        .irq_reissue_support            = 1,
        .tx_desc_prefetch               = 5,
        .rx_desc_prefetch               = 5,
+       .an_cdr_workaround              = 1,
 };
 
 static const struct pci_device_id xgbe_pci_table[] = {
index 3304a291aa964c034f1ebcace56d8aaec32c8407..aac884314000c9114decb1a29e743a593a5bce89 100644 (file)
 /* Rate-change complete wait/retry count */
 #define XGBE_RATECHANGE_COUNT          500
 
+/* CDR delay values for KR support (in usec) */
+#define XGBE_CDR_DELAY_INIT            10000
+#define XGBE_CDR_DELAY_INC             10000
+#define XGBE_CDR_DELAY_MAX             100000
+
+/* RRC frequency during link status check */
+#define XGBE_RRC_FREQUENCY             10
+
 enum xgbe_port_mode {
        XGBE_PORT_MODE_RSVD = 0,
        XGBE_PORT_MODE_BACKPLANE,
@@ -245,6 +253,10 @@ enum xgbe_sfp_speed {
 #define XGBE_SFP_BASE_VENDOR_SN                        4
 #define XGBE_SFP_BASE_VENDOR_SN_LEN            16
 
+#define XGBE_SFP_EXTD_OPT1                     1
+#define XGBE_SFP_EXTD_OPT1_RX_LOS              BIT(1)
+#define XGBE_SFP_EXTD_OPT1_TX_FAULT            BIT(3)
+
 #define XGBE_SFP_EXTD_DIAG                     28
 #define XGBE_SFP_EXTD_DIAG_ADDR_CHANGE         BIT(2)
 
@@ -324,6 +336,7 @@ struct xgbe_phy_data {
 
        unsigned int sfp_gpio_address;
        unsigned int sfp_gpio_mask;
+       unsigned int sfp_gpio_inputs;
        unsigned int sfp_gpio_rx_los;
        unsigned int sfp_gpio_tx_fault;
        unsigned int sfp_gpio_mod_absent;
@@ -355,6 +368,10 @@ struct xgbe_phy_data {
        unsigned int redrv_addr;
        unsigned int redrv_lane;
        unsigned int redrv_model;
+
+       /* KR AN support */
+       unsigned int phy_cdr_notrack;
+       unsigned int phy_cdr_delay;
 };
 
 /* I2C, MDIO and GPIO lines are muxed, so only one device at a time */
@@ -974,6 +991,49 @@ static void xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata)
        phy_data->sfp_phy_avail = 1;
 }
 
+static bool xgbe_phy_check_sfp_rx_los(struct xgbe_phy_data *phy_data)
+{
+       u8 *sfp_extd = phy_data->sfp_eeprom.extd;
+
+       if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_RX_LOS))
+               return false;
+
+       if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS)
+               return false;
+
+       if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_rx_los))
+               return true;
+
+       return false;
+}
+
+static bool xgbe_phy_check_sfp_tx_fault(struct xgbe_phy_data *phy_data)
+{
+       u8 *sfp_extd = phy_data->sfp_eeprom.extd;
+
+       if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_TX_FAULT))
+               return false;
+
+       if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT)
+               return false;
+
+       if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_tx_fault))
+               return true;
+
+       return false;
+}
+
+static bool xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data *phy_data)
+{
+       if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT)
+               return false;
+
+       if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_mod_absent))
+               return true;
+
+       return false;
+}
+
 static bool xgbe_phy_belfuse_parse_quirks(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_data *phy_data = pdata->phy_data;
@@ -1019,6 +1079,10 @@ static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
        if (sfp_base[XGBE_SFP_BASE_EXT_ID] != XGBE_SFP_EXT_ID_SFP)
                return;
 
+       /* Update transceiver signals (eeprom extd/options) */
+       phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data);
+       phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data);
+
        if (xgbe_phy_sfp_parse_quirks(pdata))
                return;
 
@@ -1184,7 +1248,6 @@ put:
 static void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_data *phy_data = pdata->phy_data;
-       unsigned int gpio_input;
        u8 gpio_reg, gpio_ports[2];
        int ret;
 
@@ -1199,23 +1262,9 @@ static void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata)
                return;
        }
 
-       gpio_input = (gpio_ports[1] << 8) | gpio_ports[0];
-
-       if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT) {
-               /* No GPIO, just assume the module is present for now */
-               phy_data->sfp_mod_absent = 0;
-       } else {
-               if (!(gpio_input & (1 << phy_data->sfp_gpio_mod_absent)))
-                       phy_data->sfp_mod_absent = 0;
-       }
-
-       if (!(phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS) &&
-           (gpio_input & (1 << phy_data->sfp_gpio_rx_los)))
-               phy_data->sfp_rx_los = 1;
+       phy_data->sfp_gpio_inputs = (gpio_ports[1] << 8) | gpio_ports[0];
 
-       if (!(phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT) &&
-           (gpio_input & (1 << phy_data->sfp_gpio_tx_fault)))
-               phy_data->sfp_tx_fault = 1;
+       phy_data->sfp_mod_absent = xgbe_phy_check_sfp_mod_absent(phy_data);
 }
 
 static void xgbe_phy_sfp_mod_absent(struct xgbe_prv_data *pdata)
@@ -2361,7 +2410,7 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
                return 1;
 
        /* No link, attempt a receiver reset cycle */
-       if (phy_data->rrc_count++) {
+       if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) {
                phy_data->rrc_count = 0;
                xgbe_phy_rrc(pdata);
        }
@@ -2669,6 +2718,103 @@ static bool xgbe_phy_port_enabled(struct xgbe_prv_data *pdata)
        return true;
 }
 
+static void xgbe_phy_cdr_track(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+       if (!pdata->debugfs_an_cdr_workaround)
+               return;
+
+       if (!phy_data->phy_cdr_notrack)
+               return;
+
+       usleep_range(phy_data->phy_cdr_delay,
+                    phy_data->phy_cdr_delay + 500);
+
+       XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
+                        XGBE_PMA_CDR_TRACK_EN_MASK,
+                        XGBE_PMA_CDR_TRACK_EN_ON);
+
+       phy_data->phy_cdr_notrack = 0;
+}
+
+static void xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+       if (!pdata->debugfs_an_cdr_workaround)
+               return;
+
+       if (phy_data->phy_cdr_notrack)
+               return;
+
+       XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
+                        XGBE_PMA_CDR_TRACK_EN_MASK,
+                        XGBE_PMA_CDR_TRACK_EN_OFF);
+
+       xgbe_phy_rrc(pdata);
+
+       phy_data->phy_cdr_notrack = 1;
+}
+
+static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata)
+{
+       if (!pdata->debugfs_an_cdr_track_early)
+               xgbe_phy_cdr_track(pdata);
+}
+
+static void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata)
+{
+       if (pdata->debugfs_an_cdr_track_early)
+               xgbe_phy_cdr_track(pdata);
+}
+
+static void xgbe_phy_an_post(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+       switch (pdata->an_mode) {
+       case XGBE_AN_MODE_CL73:
+       case XGBE_AN_MODE_CL73_REDRV:
+               if (phy_data->cur_mode != XGBE_MODE_KR)
+                       break;
+
+               xgbe_phy_cdr_track(pdata);
+
+               switch (pdata->an_result) {
+               case XGBE_AN_READY:
+               case XGBE_AN_COMPLETE:
+                       break;
+               default:
+                       if (phy_data->phy_cdr_delay < XGBE_CDR_DELAY_MAX)
+                               phy_data->phy_cdr_delay += XGBE_CDR_DELAY_INC;
+                       else
+                               phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void xgbe_phy_an_pre(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+       switch (pdata->an_mode) {
+       case XGBE_AN_MODE_CL73:
+       case XGBE_AN_MODE_CL73_REDRV:
+               if (phy_data->cur_mode != XGBE_MODE_KR)
+                       break;
+
+               xgbe_phy_cdr_notrack(pdata);
+               break;
+       default:
+               break;
+       }
+}
+
 static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_data *phy_data = pdata->phy_data;
@@ -2680,6 +2826,9 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
        xgbe_phy_sfp_reset(phy_data);
        xgbe_phy_sfp_mod_absent(pdata);
 
+       /* Reset CDR support */
+       xgbe_phy_cdr_track(pdata);
+
        /* Power off the PHY */
        xgbe_phy_power_off(pdata);
 
@@ -2712,6 +2861,9 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)
        /* Start in highest supported mode */
        xgbe_phy_set_mode(pdata, phy_data->start_mode);
 
+       /* Reset CDR support */
+       xgbe_phy_cdr_track(pdata);
+
        /* After starting the I2C controller, we can check for an SFP */
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_SFP:
@@ -3019,6 +3171,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
                }
        }
 
+       phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
+
        /* Register for driving external PHYs */
        mii = devm_mdiobus_alloc(pdata->dev);
        if (!mii) {
@@ -3071,4 +3225,10 @@ void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if)
        phy_impl->an_advertising        = xgbe_phy_an_advertising;
 
        phy_impl->an_outcome            = xgbe_phy_an_outcome;
+
+       phy_impl->an_pre                = xgbe_phy_an_pre;
+       phy_impl->an_post               = xgbe_phy_an_post;
+
+       phy_impl->kr_training_pre       = xgbe_phy_kr_training_pre;
+       phy_impl->kr_training_post      = xgbe_phy_kr_training_post;
 }
index ad102c8bac7bf44d8fa92d0bc175333b12f415fc..95d4b56448c68058102cc4fb3da9e1aefc9fea59 100644 (file)
@@ -833,6 +833,7 @@ struct xgbe_hw_if {
 /* This structure represents implementation specific routines for an
  * implementation of a PHY. All routines are required unless noted below.
  *   Optional routines:
+ *     an_pre, an_post
  *     kr_training_pre, kr_training_post
  */
 struct xgbe_phy_impl_if {
@@ -875,6 +876,10 @@ struct xgbe_phy_impl_if {
        /* Process results of auto-negotiation */
        enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *);
 
+       /* Pre/Post auto-negotiation support */
+       void (*an_pre)(struct xgbe_prv_data *);
+       void (*an_post)(struct xgbe_prv_data *);
+
        /* Pre/Post KR training enablement support */
        void (*kr_training_pre)(struct xgbe_prv_data *);
        void (*kr_training_post)(struct xgbe_prv_data *);
@@ -989,6 +994,7 @@ struct xgbe_version_data {
        unsigned int irq_reissue_support;
        unsigned int tx_desc_prefetch;
        unsigned int rx_desc_prefetch;
+       unsigned int an_cdr_workaround;
 };
 
 struct xgbe_vxlan_data {
@@ -1257,6 +1263,9 @@ struct xgbe_prv_data {
        unsigned int debugfs_xprop_reg;
 
        unsigned int debugfs_xi2c_reg;
+
+       bool debugfs_an_cdr_workaround;
+       bool debugfs_an_cdr_track_early;
 };
 
 /* Function prototypes*/
index e368b0237a1b64115a02c69974a760108b35bb8a..4a85a24ced1c81595b54ea98a533235d5713d147 100644 (file)
@@ -2781,6 +2781,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
        int ret = 0;
        struct hlist_node *h;
        int bkt;
+       u8 i;
 
        /* validate the request */
        if (vf_id >= pf->num_alloc_vfs) {
@@ -2792,6 +2793,16 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
 
        vf = &(pf->vf[vf_id]);
        vsi = pf->vsi[vf->lan_vsi_idx];
+
+       /* When the VF is resetting wait until it is done.
+        * It can take up to 200 milliseconds,
+        * but wait for up to 300 milliseconds to be safe.
+        */
+       for (i = 0; i < 15; i++) {
+               if (test_bit(I40E_VF_STATE_INIT, &vf->vf_states))
+                       break;
+               msleep(20);
+       }
        if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
                dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
                        vf_id);
index a5bb7b19040e9642ac166a53b19a2f448b841232..992c43b1868f97a627a475d91f2c3293286f9d1d 100644 (file)
@@ -124,7 +124,7 @@ do {                                                                \
 
 #define RX_PRIORITY_MAPPING    0x76543210
 #define TX_PRIORITY_MAPPING    0x33221100
-#define CPDMA_TX_PRIORITY_MAP  0x01234567
+#define CPDMA_TX_PRIORITY_MAP  0x76543210
 
 #define CPSW_VLAN_AWARE                BIT(1)
 #define CPSW_ALE_VLAN_AWARE    1
index 5aa59f41bf8c3992b5ba58e24ac8763ab264eb5f..71e2aef6b7a1b5cdb052fed4aeec2a843a1a9a4d 100644 (file)
@@ -620,6 +620,10 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
        lock_sock(sk);
 
        error = -EINVAL;
+
+       if (sockaddr_len != sizeof(struct sockaddr_pppox))
+               goto end;
+
        if (sp->sa_protocol != PX_PROTO_OE)
                goto end;
 
index 2a366554c503d6530589b544a8bfa26566e3a8e8..8a222ae5950e46dd9977f3384ad3e7a6cd98fad8 100644 (file)
@@ -261,6 +261,17 @@ static void __team_option_inst_mark_removed_port(struct team *team,
        }
 }
 
+static bool __team_option_inst_tmp_find(const struct list_head *opts,
+                                       const struct team_option_inst *needle)
+{
+       struct team_option_inst *opt_inst;
+
+       list_for_each_entry(opt_inst, opts, tmp_list)
+               if (opt_inst == needle)
+                       return true;
+       return false;
+}
+
 static int __team_options_register(struct team *team,
                                   const struct team_option *option,
                                   size_t option_count)
@@ -1061,14 +1072,11 @@ static void team_port_leave(struct team *team, struct team_port *port)
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int __team_port_enable_netpoll(struct team_port *port)
 {
        struct netpoll *np;
        int err;
 
-       if (!team->dev->npinfo)
-               return 0;
-
        np = kzalloc(sizeof(*np), GFP_KERNEL);
        if (!np)
                return -ENOMEM;
@@ -1082,6 +1090,14 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port)
        return err;
 }
 
+static int team_port_enable_netpoll(struct team_port *port)
+{
+       if (!port->team->dev->npinfo)
+               return 0;
+
+       return __team_port_enable_netpoll(port);
+}
+
 static void team_port_disable_netpoll(struct team_port *port)
 {
        struct netpoll *np = port->np;
@@ -1096,7 +1112,7 @@ static void team_port_disable_netpoll(struct team_port *port)
        kfree(np);
 }
 #else
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int team_port_enable_netpoll(struct team_port *port)
 {
        return 0;
 }
@@ -1204,7 +1220,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_vids_add;
        }
 
-       err = team_port_enable_netpoll(team, port);
+       err = team_port_enable_netpoll(port);
        if (err) {
                netdev_err(dev, "Failed to enable netpoll on device %s\n",
                           portname);
@@ -1901,7 +1917,7 @@ static int team_netpoll_setup(struct net_device *dev,
 
        mutex_lock(&team->lock);
        list_for_each_entry(port, &team->port_list, list) {
-               err = team_port_enable_netpoll(team, port);
+               err = __team_port_enable_netpoll(port);
                if (err) {
                        __team_netpoll_cleanup(team);
                        break;
@@ -2561,6 +2577,14 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
                        if (err)
                                goto team_put;
                        opt_inst->changed = true;
+
+                       /* dumb/evil user-space can send us duplicate opt,
+                        * keep only the last one
+                        */
+                       if (__team_option_inst_tmp_find(&opt_inst_list,
+                                                       opt_inst))
+                               continue;
+
                        list_add(&opt_inst->tmp_list, &opt_inst_list);
                }
                if (!opt_found) {
index b0a038e6fda043432926153b0b1fdcc188afe362..bb15b3012aa5fe90e05a4214b622671446ef5fb0 100644 (file)
@@ -116,6 +116,17 @@ struct receive_queue {
        char name[40];
 };
 
+/* Control VQ buffers: protected by the rtnl lock */
+struct control_buf {
+       struct virtio_net_ctrl_hdr hdr;
+       virtio_net_ctrl_ack status;
+       struct virtio_net_ctrl_mq mq;
+       u8 promisc;
+       u8 allmulti;
+       __virtio16 vid;
+       u64 offloads;
+};
+
 struct virtnet_info {
        struct virtio_device *vdev;
        struct virtqueue *cvq;
@@ -164,14 +175,7 @@ struct virtnet_info {
        struct hlist_node node;
        struct hlist_node node_dead;
 
-       /* Control VQ buffers: protected by the rtnl lock */
-       struct virtio_net_ctrl_hdr ctrl_hdr;
-       virtio_net_ctrl_ack ctrl_status;
-       struct virtio_net_ctrl_mq ctrl_mq;
-       u8 ctrl_promisc;
-       u8 ctrl_allmulti;
-       u16 ctrl_vid;
-       u64 ctrl_offloads;
+       struct control_buf *ctrl;
 
        /* Ethtool settings */
        u8 duplex;
@@ -1340,25 +1344,25 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
        /* Caller should know better */
        BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ));
 
-       vi->ctrl_status = ~0;
-       vi->ctrl_hdr.class = class;
-       vi->ctrl_hdr.cmd = cmd;
+       vi->ctrl->status = ~0;
+       vi->ctrl->hdr.class = class;
+       vi->ctrl->hdr.cmd = cmd;
        /* Add header */
-       sg_init_one(&hdr, &vi->ctrl_hdr, sizeof(vi->ctrl_hdr));
+       sg_init_one(&hdr, &vi->ctrl->hdr, sizeof(vi->ctrl->hdr));
        sgs[out_num++] = &hdr;
 
        if (out)
                sgs[out_num++] = out;
 
        /* Add return status. */
-       sg_init_one(&stat, &vi->ctrl_status, sizeof(vi->ctrl_status));
+       sg_init_one(&stat, &vi->ctrl->status, sizeof(vi->ctrl->status));
        sgs[out_num] = &stat;
 
        BUG_ON(out_num + 1 > ARRAY_SIZE(sgs));
        virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
 
        if (unlikely(!virtqueue_kick(vi->cvq)))
-               return vi->ctrl_status == VIRTIO_NET_OK;
+               return vi->ctrl->status == VIRTIO_NET_OK;
 
        /* Spin for a response, the kick causes an ioport write, trapping
         * into the hypervisor, so the request should be handled immediately.
@@ -1367,7 +1371,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
               !virtqueue_is_broken(vi->cvq))
                cpu_relax();
 
-       return vi->ctrl_status == VIRTIO_NET_OK;
+       return vi->ctrl->status == VIRTIO_NET_OK;
 }
 
 static int virtnet_set_mac_address(struct net_device *dev, void *p)
@@ -1478,8 +1482,8 @@ static int _virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
        if (!vi->has_cvq || !virtio_has_feature(vi->vdev, VIRTIO_NET_F_MQ))
                return 0;
 
-       vi->ctrl_mq.virtqueue_pairs = cpu_to_virtio16(vi->vdev, queue_pairs);
-       sg_init_one(&sg, &vi->ctrl_mq, sizeof(vi->ctrl_mq));
+       vi->ctrl->mq.virtqueue_pairs = cpu_to_virtio16(vi->vdev, queue_pairs);
+       sg_init_one(&sg, &vi->ctrl->mq, sizeof(vi->ctrl->mq));
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
                                  VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, &sg)) {
@@ -1537,22 +1541,22 @@ static void virtnet_set_rx_mode(struct net_device *dev)
        if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX))
                return;
 
-       vi->ctrl_promisc = ((dev->flags & IFF_PROMISC) != 0);
-       vi->ctrl_allmulti = ((dev->flags & IFF_ALLMULTI) != 0);
+       vi->ctrl->promisc = ((dev->flags & IFF_PROMISC) != 0);
+       vi->ctrl->allmulti = ((dev->flags & IFF_ALLMULTI) != 0);
 
-       sg_init_one(sg, &vi->ctrl_promisc, sizeof(vi->ctrl_promisc));
+       sg_init_one(sg, &vi->ctrl->promisc, sizeof(vi->ctrl->promisc));
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
                                  VIRTIO_NET_CTRL_RX_PROMISC, sg))
                dev_warn(&dev->dev, "Failed to %sable promisc mode.\n",
-                        vi->ctrl_promisc ? "en" : "dis");
+                        vi->ctrl->promisc ? "en" : "dis");
 
-       sg_init_one(sg, &vi->ctrl_allmulti, sizeof(vi->ctrl_allmulti));
+       sg_init_one(sg, &vi->ctrl->allmulti, sizeof(vi->ctrl->allmulti));
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
                                  VIRTIO_NET_CTRL_RX_ALLMULTI, sg))
                dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n",
-                        vi->ctrl_allmulti ? "en" : "dis");
+                        vi->ctrl->allmulti ? "en" : "dis");
 
        uc_count = netdev_uc_count(dev);
        mc_count = netdev_mc_count(dev);
@@ -1598,8 +1602,8 @@ static int virtnet_vlan_rx_add_vid(struct net_device *dev,
        struct virtnet_info *vi = netdev_priv(dev);
        struct scatterlist sg;
 
-       vi->ctrl_vid = vid;
-       sg_init_one(&sg, &vi->ctrl_vid, sizeof(vi->ctrl_vid));
+       vi->ctrl->vid = cpu_to_virtio16(vi->vdev, vid);
+       sg_init_one(&sg, &vi->ctrl->vid, sizeof(vi->ctrl->vid));
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN,
                                  VIRTIO_NET_CTRL_VLAN_ADD, &sg))
@@ -1613,8 +1617,8 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
        struct virtnet_info *vi = netdev_priv(dev);
        struct scatterlist sg;
 
-       vi->ctrl_vid = vid;
-       sg_init_one(&sg, &vi->ctrl_vid, sizeof(vi->ctrl_vid));
+       vi->ctrl->vid = cpu_to_virtio16(vi->vdev, vid);
+       sg_init_one(&sg, &vi->ctrl->vid, sizeof(vi->ctrl->vid));
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN,
                                  VIRTIO_NET_CTRL_VLAN_DEL, &sg))
@@ -1912,9 +1916,9 @@ static int virtnet_restore_up(struct virtio_device *vdev)
 static int virtnet_set_guest_offloads(struct virtnet_info *vi, u64 offloads)
 {
        struct scatterlist sg;
-       vi->ctrl_offloads = cpu_to_virtio64(vi->vdev, offloads);
+       vi->ctrl->offloads = cpu_to_virtio64(vi->vdev, offloads);
 
-       sg_init_one(&sg, &vi->ctrl_offloads, sizeof(vi->ctrl_offloads));
+       sg_init_one(&sg, &vi->ctrl->offloads, sizeof(vi->ctrl->offloads));
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_GUEST_OFFLOADS,
                                  VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, &sg)) {
@@ -2134,6 +2138,7 @@ static void virtnet_free_queues(struct virtnet_info *vi)
 
        kfree(vi->rq);
        kfree(vi->sq);
+       kfree(vi->ctrl);
 }
 
 static void _free_receive_bufs(struct virtnet_info *vi)
@@ -2326,6 +2331,9 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
 {
        int i;
 
+       vi->ctrl = kzalloc(sizeof(*vi->ctrl), GFP_KERNEL);
+       if (!vi->ctrl)
+               goto err_ctrl;
        vi->sq = kzalloc(sizeof(*vi->sq) * vi->max_queue_pairs, GFP_KERNEL);
        if (!vi->sq)
                goto err_sq;
@@ -2351,6 +2359,8 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
 err_rq:
        kfree(vi->sq);
 err_sq:
+       kfree(vi->ctrl);
+err_ctrl:
        return -ENOMEM;
 }
 
index 252c2206cbb5b20ab90d800be36dd786e8239f09..c1772215702a8c31ec60afdf8cda3690a54715c5 100644 (file)
@@ -5955,9 +5955,8 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
                                    sta->addr, smps, err);
        }
 
-       if (changed & IEEE80211_RC_SUPP_RATES_CHANGED ||
-           changed & IEEE80211_RC_NSS_CHANGED) {
-               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n",
+       if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
                           sta->addr);
 
                err = ath10k_station_assoc(ar, arvif->vif, sta, true);
index 72b4527d690f43bae235936f766b7be2dca79a90..71df0f70b61f01c51484c87f35bdba9a1158cdbc 100644 (file)
@@ -427,18 +427,6 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input)
        writel(value, padcfg0);
 }
 
-static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
-{
-       u32 value;
-
-       /* Put the pad into GPIO mode */
-       value = readl(padcfg0) & ~PADCFG0_PMODE_MASK;
-       /* Disable SCI/SMI/NMI generation */
-       value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
-       value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
-       writel(value, padcfg0);
-}
-
 static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
                                     struct pinctrl_gpio_range *range,
                                     unsigned pin)
@@ -446,6 +434,7 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
        struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        void __iomem *padcfg0;
        unsigned long flags;
+       u32 value;
 
        raw_spin_lock_irqsave(&pctrl->lock, flags);
 
@@ -455,7 +444,13 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
        }
 
        padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
-       intel_gpio_set_gpio_mode(padcfg0);
+       /* Put the pad into GPIO mode */
+       value = readl(padcfg0) & ~PADCFG0_PMODE_MASK;
+       /* Disable SCI/SMI/NMI generation */
+       value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
+       value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
+       writel(value, padcfg0);
+
        /* Disable TX buffer and enable RX (this will be input) */
        __intel_gpio_set_direction(padcfg0, true);
 
@@ -940,8 +935,6 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
 
        raw_spin_lock_irqsave(&pctrl->lock, flags);
 
-       intel_gpio_set_gpio_mode(reg);
-
        value = readl(reg);
 
        value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV);
index 62f5f04d8f615e393c88824606f58d13801c5e6b..5e963fe0e38d4c2125c43ae801ca7e9b28d98d07 100644 (file)
@@ -592,13 +592,22 @@ static int _schedule_lcu_update(struct alias_lcu *lcu,
 int dasd_alias_add_device(struct dasd_device *device)
 {
        struct dasd_eckd_private *private = device->private;
-       struct alias_lcu *lcu;
+       __u8 uaddr = private->uid.real_unit_addr;
+       struct alias_lcu *lcu = private->lcu;
        unsigned long flags;
        int rc;
 
-       lcu = private->lcu;
        rc = 0;
        spin_lock_irqsave(&lcu->lock, flags);
+       /*
+        * Check if device and lcu type differ. If so, the uac data may be
+        * outdated and needs to be updated.
+        */
+       if (private->uid.type !=  lcu->uac->unit[uaddr].ua_type) {
+               lcu->flags |= UPDATE_PENDING;
+               DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+                             "uid type mismatch - trigger rescan");
+       }
        if (!(lcu->flags & UPDATE_PENDING)) {
                rc = _add_device_to_lcu(lcu, device, device);
                if (rc)
index 05ac6ba15a53285f41e01ab415b776366ddb5e54..ecc24a46e71a2fa538b9261071f6fc1986d20c4a 100644 (file)
@@ -17,6 +17,8 @@ CFLAGS_REMOVE_sclp_early_core.o       += $(CC_FLAGS_MARCH)
 CFLAGS_sclp_early_core.o               += -march=z900
 endif
 
+CFLAGS_REMOVE_sclp_early_core.o        += $(CC_FLAGS_EXPOLINE)
+
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
         sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \
         sclp_early.o sclp_early_core.o
index 7b0b295b2313b8f3056378ed64c4249381a0213b..69687c16a150a4a4f839bb7357217f0616d13558 100644 (file)
@@ -451,6 +451,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_nt0_area *sei_area)
 
 static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area)
 {
+       struct channel_path *chp;
        struct chp_link link;
        struct chp_id chpid;
        int status;
@@ -463,10 +464,17 @@ static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area)
        chpid.id = sei_area->rsid;
        /* allocate a new channel path structure, if needed */
        status = chp_get_status(chpid);
-       if (status < 0)
-               chp_new(chpid);
-       else if (!status)
+       if (!status)
                return;
+
+       if (status < 0) {
+               chp_new(chpid);
+       } else {
+               chp = chpid_to_chp(chpid);
+               mutex_lock(&chp->lock);
+               chp_update_desc(chp);
+               mutex_unlock(&chp->lock);
+       }
        memset(&link, 0, sizeof(struct chp_link));
        link.chpid = chpid;
        if ((sei_area->vf & 0xc0) != 0) {
index 3597ef78df4d7bbd40df3e252e064f89f75aadbd..ce74278a454a2466f3bed8ea642f362cfd1b9325 100644 (file)
@@ -217,12 +217,10 @@ struct fsnotify_mark_connector {
        union { /* Object pointer [lock] */
                struct inode *inode;
                struct vfsmount *mnt;
-       };
-       union {
-               struct hlist_head list;
                /* Used listing heads to free after srcu period expires */
                struct fsnotify_mark_connector *destroy_next;
        };
+       struct hlist_head list;
 };
 
 /*
index 8198faf16ed69dd4ef6f3253694a80db594f9968..96e69979f84d7b7fe1edb6568097bf32cec97a92 100644 (file)
@@ -498,16 +498,23 @@ struct hmm_device {
 struct hmm_device *hmm_device_new(void *drvdata);
 void hmm_device_put(struct hmm_device *hmm_device);
 #endif /* CONFIG_DEVICE_PRIVATE || CONFIG_DEVICE_PUBLIC */
+#endif /* IS_ENABLED(CONFIG_HMM) */
 
 /* Below are for HMM internal use only! Not to be used by device driver! */
+#if IS_ENABLED(CONFIG_HMM_MIRROR)
 void hmm_mm_destroy(struct mm_struct *mm);
 
 static inline void hmm_mm_init(struct mm_struct *mm)
 {
        mm->hmm = NULL;
 }
+#else /* IS_ENABLED(CONFIG_HMM_MIRROR) */
+static inline void hmm_mm_destroy(struct mm_struct *mm) {}
+static inline void hmm_mm_init(struct mm_struct *mm) {}
+#endif /* IS_ENABLED(CONFIG_HMM_MIRROR) */
+
+
 #else /* IS_ENABLED(CONFIG_HMM) */
 static inline void hmm_mm_destroy(struct mm_struct *mm) {}
 static inline void hmm_mm_init(struct mm_struct *mm) {}
-#endif /* IS_ENABLED(CONFIG_HMM) */
 #endif /* LINUX_HMM_H */
index 5e6a2d4dc366033772027940b5c4b742e17d0173..ab927383c99d69abafaf1e12bb365d9f51ad211d 100644 (file)
@@ -584,7 +584,7 @@ static inline bool skb_vlan_tagged(const struct sk_buff *skb)
  * Returns true if the skb is tagged with multiple vlan headers, regardless
  * of whether it is hardware accelerated or not.
  */
-static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
+static inline bool skb_vlan_tagged_multi(struct sk_buff *skb)
 {
        __be16 protocol = skb->protocol;
 
@@ -594,6 +594,9 @@ static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
                if (likely(!eth_type_vlan(protocol)))
                        return false;
 
+               if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN)))
+                       return false;
+
                veh = (struct vlan_ethhdr *)skb->data;
                protocol = veh->h_vlan_encapsulated_proto;
        }
@@ -611,7 +614,7 @@ static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
  *
  * Returns features without unsafe ones if the skb has multiple tags.
  */
-static inline netdev_features_t vlan_features_check(const struct sk_buff *skb,
+static inline netdev_features_t vlan_features_check(struct sk_buff *skb,
                                                    netdev_features_t features)
 {
        if (skb_vlan_tagged_multi(skb)) {
index 881312d85574b41286589856674a0bf61cef5f87..2a6c3d96b31f0bc52960d134d6318cb57b1396af 100644 (file)
@@ -49,7 +49,7 @@ struct tpm_class_ops {
        bool (*update_timeouts)(struct tpm_chip *chip,
                                unsigned long *timeout_cap);
        int (*request_locality)(struct tpm_chip *chip, int loc);
-       void (*relinquish_locality)(struct tpm_chip *chip, int loc);
+       int (*relinquish_locality)(struct tpm_chip *chip, int loc);
        void (*clk_enable)(struct tpm_chip *chip, bool value);
 };
 
index 44b9c00f72232c31d3cf478c901e7b164748bb04..e117617e3c347af5eec412ebd8cbb2271de22b56 100644 (file)
@@ -12,7 +12,8 @@
 void *ife_encode(struct sk_buff *skb, u16 metalen);
 void *ife_decode(struct sk_buff *skb, u16 *metalen);
 
-void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen);
+void *ife_tlv_meta_decode(void *skbdata, const void *ifehdr_end, u16 *attrtype,
+                         u16 *dlen, u16 *totlen);
 int ife_tlv_meta_encode(void *skbdata, u16 attrtype, u16 dlen,
                        const void *dval);
 
index fe994d2e52869d06be7d26b48b942e666e60f2da..ea985aa7a6c5e64b6802c2399ad47db23fdbd9bf 100644 (file)
@@ -97,6 +97,7 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb)
 
 struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority,
                          struct proto *prot, int kern);
+void llc_sk_stop_all_timers(struct sock *sk, bool sync);
 void llc_sk_free(struct sock *sk);
 
 void llc_sk_reset(struct sock *sk);
index f99d17c9540ba2ad8f4f1356fb81d9c6d736d0a3..71082ba003d7360b7ec2b99c377134fb9ab7a5c8 100644 (file)
@@ -1617,6 +1617,7 @@ static inline void tcp_write_queue_purge(struct sock *sk)
        sk_mem_reclaim(sk);
        tcp_clear_all_retrans_hints(tcp_sk(sk));
        tcp_init_send_head(sk);
+       tcp_sk(sk)->packets_out = 0;
 }
 
 static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk)
index 7e99999d6236fa2940fa2b565442e8b1b1331407..857bad91c454046200c81e260c9850933df0981b 100644 (file)
@@ -931,6 +931,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_PPC_SMT_POSSIBLE 147
 #define KVM_CAP_HYPERV_SYNIC2 148
 #define KVM_CAP_HYPERV_VP_INDEX 149
+#define KVM_CAP_S390_BPB 152
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
index e954ae3d82c0f78e2ac5646e84563c6237e23bce..e3a658bac10feef4e42740f9c5b556687162bd32 100644 (file)
@@ -356,7 +356,7 @@ FTRACE_ENTRY(hwlat, hwlat_entry,
                __field(        unsigned int,           seqnum          )
        ),
 
-       F_printk("cnt:%u\tts:%010llu.%010lu\tinner:%llu\touter:%llunmi-ts:%llu\tnmi-count:%u\n",
+       F_printk("cnt:%u\tts:%010llu.%010lu\tinner:%llu\touter:%llu\tnmi-ts:%llu\tnmi-count:%u\n",
                 __entry->seqnum,
                 __entry->tv_sec,
                 __entry->tv_nsec,
index 4be2a4047640a40319294f9b459a053d659cc5ba..e7d56c5adde6322251cb58af02b33aae05c73320 100644 (file)
@@ -2903,7 +2903,7 @@ netdev_features_t passthru_features_check(struct sk_buff *skb,
 }
 EXPORT_SYMBOL(passthru_features_check);
 
-static netdev_features_t dflt_features_check(const struct sk_buff *skb,
+static netdev_features_t dflt_features_check(struct sk_buff *skb,
                                             struct net_device *dev,
                                             netdev_features_t features)
 {
index 741ae2554190a82369b8bb6e28122951e22cb4bf..514d697d469137d2d1f229fd0698dacc34850d79 100644 (file)
@@ -55,7 +55,8 @@ static void neigh_timer_handler(unsigned long arg);
 static void __neigh_notify(struct neighbour *n, int type, int flags,
                           u32 pid);
 static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid);
-static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
+static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
+                                   struct net_device *dev);
 
 #ifdef CONFIG_PROC_FS
 static const struct file_operations neigh_stat_seq_fops;
@@ -291,8 +292,7 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
 {
        write_lock_bh(&tbl->lock);
        neigh_flush_dev(tbl, dev);
-       pneigh_ifdown(tbl, dev);
-       write_unlock_bh(&tbl->lock);
+       pneigh_ifdown_and_unlock(tbl, dev);
 
        del_timer_sync(&tbl->proxy_timer);
        pneigh_queue_purge(&tbl->proxy_queue);
@@ -681,9 +681,10 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
        return -ENOENT;
 }
 
-static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
+static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
+                                   struct net_device *dev)
 {
-       struct pneigh_entry *n, **np;
+       struct pneigh_entry *n, **np, *freelist = NULL;
        u32 h;
 
        for (h = 0; h <= PNEIGH_HASHMASK; h++) {
@@ -691,16 +692,23 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
                while ((n = *np) != NULL) {
                        if (!dev || n->dev == dev) {
                                *np = n->next;
-                               if (tbl->pdestructor)
-                                       tbl->pdestructor(n);
-                               if (n->dev)
-                                       dev_put(n->dev);
-                               kfree(n);
+                               n->next = freelist;
+                               freelist = n;
                                continue;
                        }
                        np = &n->next;
                }
        }
+       write_unlock_bh(&tbl->lock);
+       while ((n = freelist)) {
+               freelist = n->next;
+               n->next = NULL;
+               if (tbl->pdestructor)
+                       tbl->pdestructor(n);
+               if (n->dev)
+                       dev_put(n->dev);
+               kfree(n);
+       }
        return -ENOENT;
 }
 
@@ -2323,12 +2331,16 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
 
        err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL, NULL);
        if (!err) {
-               if (tb[NDA_IFINDEX])
+               if (tb[NDA_IFINDEX]) {
+                       if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32))
+                               return -EINVAL;
                        filter_idx = nla_get_u32(tb[NDA_IFINDEX]);
-
-               if (tb[NDA_MASTER])
+               }
+               if (tb[NDA_MASTER]) {
+                       if (nla_len(tb[NDA_MASTER]) != sizeof(u32))
+                               return -EINVAL;
                        filter_master_idx = nla_get_u32(tb[NDA_MASTER]);
-
+               }
                if (filter_idx || filter_master_idx)
                        flags |= NLM_F_DUMP_FILTERED;
        }
index e1d4d898a007df9ba0911fd612caac4a48a50dc2..f0252768ecf4c39219a58626198f58e5278031ad 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/moduleparam.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/ratelimit.h>
 #include <linux/kernel.h>
 #include <linux/keyctl.h>
 #include <linux/err.h>
@@ -91,9 +92,9 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
 
                        next_opt = memchr(opt, '#', end - opt) ?: end;
                        opt_len = next_opt - opt;
-                       if (!opt_len) {
-                               printk(KERN_WARNING
-                                      "Empty option to dns_resolver key\n");
+                       if (opt_len <= 0 || opt_len > 128) {
+                               pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n",
+                                                   opt_len);
                                return -EINVAL;
                        }
 
@@ -127,10 +128,8 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
                        }
 
                bad_option_value:
-                       printk(KERN_WARNING
-                              "Option '%*.*s' to dns_resolver key:"
-                              " bad/missing value\n",
-                              opt_nlen, opt_nlen, opt);
+                       pr_warn_ratelimited("Option '%*.*s' to dns_resolver key: bad/missing value\n",
+                                           opt_nlen, opt_nlen, opt);
                        return -EINVAL;
                } while (opt = next_opt + 1, opt < end);
        }
index 7d1ec76e7f433a2525581782a0bf14731548d4a8..13bbf8cb6a3961d422d01cf5b16a724d16107419 100644 (file)
@@ -69,6 +69,9 @@ void *ife_decode(struct sk_buff *skb, u16 *metalen)
        int total_pull;
        u16 ifehdrln;
 
+       if (!pskb_may_pull(skb, skb->dev->hard_header_len + IFE_METAHDRLEN))
+               return NULL;
+
        ifehdr = (struct ifeheadr *) (skb->data + skb->dev->hard_header_len);
        ifehdrln = ntohs(ifehdr->metalen);
        total_pull = skb->dev->hard_header_len + ifehdrln;
@@ -92,12 +95,43 @@ struct meta_tlvhdr {
        __be16 len;
 };
 
+static bool __ife_tlv_meta_valid(const unsigned char *skbdata,
+                                const unsigned char *ifehdr_end)
+{
+       const struct meta_tlvhdr *tlv;
+       u16 tlvlen;
+
+       if (unlikely(skbdata + sizeof(*tlv) > ifehdr_end))
+               return false;
+
+       tlv = (const struct meta_tlvhdr *)skbdata;
+       tlvlen = ntohs(tlv->len);
+
+       /* tlv length field is inc header, check on minimum */
+       if (tlvlen < NLA_HDRLEN)
+               return false;
+
+       /* overflow by NLA_ALIGN check */
+       if (NLA_ALIGN(tlvlen) < tlvlen)
+               return false;
+
+       if (unlikely(skbdata + NLA_ALIGN(tlvlen) > ifehdr_end))
+               return false;
+
+       return true;
+}
+
 /* Caller takes care of presenting data in network order
  */
-void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen)
+void *ife_tlv_meta_decode(void *skbdata, const void *ifehdr_end, u16 *attrtype,
+                         u16 *dlen, u16 *totlen)
 {
-       struct meta_tlvhdr *tlv = (struct meta_tlvhdr *) skbdata;
+       struct meta_tlvhdr *tlv;
+
+       if (!__ife_tlv_meta_valid(skbdata, ifehdr_end))
+               return NULL;
 
+       tlv = (struct meta_tlvhdr *)skbdata;
        *dlen = ntohs(tlv->len) - NLA_HDRLEN;
        *attrtype = ntohs(tlv->type);
 
index 38b9a6276a9de826293ce918c23e0ac0302e6a83..d023f879e7bb6a47c27e89bfc5aeb8e20c2cfe58 100644 (file)
@@ -2354,7 +2354,6 @@ int tcp_disconnect(struct sock *sk, int flags)
        icsk->icsk_backoff = 0;
        tp->snd_cwnd = 2;
        icsk->icsk_probes_out = 0;
-       tp->packets_out = 0;
        tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
        tp->snd_cwnd_cnt = 0;
        tp->window_clamp = 0;
@@ -2742,8 +2741,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 #ifdef CONFIG_TCP_MD5SIG
        case TCP_MD5SIG:
        case TCP_MD5SIG_EXT:
-               /* Read the IP->Key mappings from userspace */
-               err = tp->af_specific->md5_parse(sk, optname, optval, optlen);
+               if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))
+                       err = tp->af_specific->md5_parse(sk, optname, optval, optlen);
+               else
+                       err = -EINVAL;
                break;
 #endif
        case TCP_USER_TIMEOUT:
index 42ef06df774335184ffcf2866b6004f21b9290df..1197f85c105ac7d313830d4b7a3016400bcf3901 100644 (file)
@@ -3893,11 +3893,8 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
        int length = (th->doff << 2) - sizeof(*th);
        const u8 *ptr = (const u8 *)(th + 1);
 
-       /* If the TCP option is too short, we can short cut */
-       if (length < TCPOLEN_MD5SIG)
-               return NULL;
-
-       while (length > 0) {
+       /* If not enough data remaining, we can short cut */
+       while (length >= TCPOLEN_MD5SIG) {
                int opcode = *ptr++;
                int opsize;
 
index 312e6b66ceb533b81cf41773530de5dff982c6bd..bf64e9da34d6c52c89f3c03f532b49d379ebda15 100644 (file)
@@ -2931,6 +2931,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
 
 static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
        [RTA_GATEWAY]           = { .len = sizeof(struct in6_addr) },
+       [RTA_PREFSRC]           = { .len = sizeof(struct in6_addr) },
        [RTA_OIF]               = { .type = NLA_U32 },
        [RTA_IIF]               = { .type = NLA_U32 },
        [RTA_PRIORITY]          = { .type = NLA_U32 },
@@ -2942,6 +2943,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
        [RTA_EXPIRES]           = { .type = NLA_U32 },
        [RTA_UID]               = { .type = NLA_U32 },
        [RTA_MARK]              = { .type = NLA_U32 },
+       [RTA_TABLE]             = { .type = NLA_U32 },
 };
 
 static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
index f343e6f0fc95a89fa5f386430dc161600367338c..5fe13948491968f2121782a4e4c2d3b93abe6e17 100644 (file)
@@ -136,7 +136,7 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
        isrh->nexthdr = proto;
 
        hdr->daddr = isrh->segments[isrh->first_segment];
-       set_tun_src(net, ip6_dst_idev(dst)->dev, &hdr->daddr, &hdr->saddr);
+       set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
        if (sr_has_hmac(isrh)) {
index 0c2738349442ba705f4240aed29fc4c1d9be727d..8bef35aa878605f6887c717f6f09481d62e770b3 100644 (file)
@@ -591,6 +591,13 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        lock_sock(sk);
 
        error = -EINVAL;
+
+       if (sockaddr_len != sizeof(struct sockaddr_pppol2tp) &&
+           sockaddr_len != sizeof(struct sockaddr_pppol2tpv3) &&
+           sockaddr_len != sizeof(struct sockaddr_pppol2tpin6) &&
+           sockaddr_len != sizeof(struct sockaddr_pppol2tpv3in6))
+               goto end;
+
        if (sp->sa_protocol != PX_PROTO_OL2TP)
                goto end;
 
index c38d16f22d2a7ff265b8729d43b164312598fd9f..cf41d9b4a0b82dd46c804d6906bc514fd29ccfc4 100644 (file)
@@ -199,9 +199,19 @@ static int llc_ui_release(struct socket *sock)
                llc->laddr.lsap, llc->daddr.lsap);
        if (!llc_send_disc(sk))
                llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
-       if (!sock_flag(sk, SOCK_ZAPPED))
+       if (!sock_flag(sk, SOCK_ZAPPED)) {
+               struct llc_sap *sap = llc->sap;
+
+               /* Hold this for release_sock(), so that llc_backlog_rcv()
+                * could still use it.
+                */
+               llc_sap_hold(sap);
                llc_sap_remove_socket(llc->sap, sk);
-       release_sock(sk);
+               release_sock(sk);
+               llc_sap_put(sap);
+       } else {
+               release_sock(sk);
+       }
        if (llc->dev)
                dev_put(llc->dev);
        sock_put(sk);
index ea225bd2672c03947dcc01b581a14e1a2b792e68..f8d4ab8ca1a5f0781ca4704e85481efd9bdd47be 100644 (file)
@@ -1096,14 +1096,7 @@ int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb)
 
 int llc_conn_ac_stop_all_timers(struct sock *sk, struct sk_buff *skb)
 {
-       struct llc_sock *llc = llc_sk(sk);
-
-       del_timer(&llc->pf_cycle_timer.timer);
-       del_timer(&llc->ack_timer.timer);
-       del_timer(&llc->rej_sent_timer.timer);
-       del_timer(&llc->busy_state_timer.timer);
-       llc->ack_must_be_send = 0;
-       llc->ack_pf = 0;
+       llc_sk_stop_all_timers(sk, false);
        return 0;
 }
 
index 5e91b47f0d2ac73a6e5b6e34ba19e058ada70f74..9a42448eb182913dc87ba706a2057bcbfc1fa8cc 100644 (file)
@@ -951,6 +951,26 @@ out:
        return sk;
 }
 
+void llc_sk_stop_all_timers(struct sock *sk, bool sync)
+{
+       struct llc_sock *llc = llc_sk(sk);
+
+       if (sync) {
+               del_timer_sync(&llc->pf_cycle_timer.timer);
+               del_timer_sync(&llc->ack_timer.timer);
+               del_timer_sync(&llc->rej_sent_timer.timer);
+               del_timer_sync(&llc->busy_state_timer.timer);
+       } else {
+               del_timer(&llc->pf_cycle_timer.timer);
+               del_timer(&llc->ack_timer.timer);
+               del_timer(&llc->rej_sent_timer.timer);
+               del_timer(&llc->busy_state_timer.timer);
+       }
+
+       llc->ack_must_be_send = 0;
+       llc->ack_pf = 0;
+}
+
 /**
  *     llc_sk_free - Frees a LLC socket
  *     @sk - socket to free
@@ -963,7 +983,7 @@ void llc_sk_free(struct sock *sk)
 
        llc->state = LLC_CONN_OUT_OF_SVC;
        /* Stop all (possibly) running timers */
-       llc_conn_ac_stop_all_timers(sk, NULL);
+       llc_sk_stop_all_timers(sk, true);
 #ifdef DEBUG_LLC_CONN_ALLOC
        printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __func__,
                skb_queue_len(&llc->pdu_unack_q),
index f4a0587b7d5ec88bddfa04cc4c9a6392604baa88..3994b71f81971b6419f277138d98c7ef7d003ef5 100644 (file)
@@ -331,11 +331,11 @@ static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
        skb_set_queue_mapping(skb, queue_index);
 }
 
-/* register_prot_hook must be invoked with the po->bind_lock held,
+/* __register_prot_hook must be invoked through register_prot_hook
  * or from a context in which asynchronous accesses to the packet
  * socket is not possible (packet_create()).
  */
-static void register_prot_hook(struct sock *sk)
+static void __register_prot_hook(struct sock *sk)
 {
        struct packet_sock *po = pkt_sk(sk);
 
@@ -350,8 +350,13 @@ static void register_prot_hook(struct sock *sk)
        }
 }
 
-/* {,__}unregister_prot_hook() must be invoked with the po->bind_lock
- * held.   If the sync parameter is true, we will temporarily drop
+static void register_prot_hook(struct sock *sk)
+{
+       lockdep_assert_held_once(&pkt_sk(sk)->bind_lock);
+       __register_prot_hook(sk);
+}
+
+/* If the sync parameter is true, we will temporarily drop
  * the po->bind_lock and do a synchronize_net to make sure no
  * asynchronous packet processing paths still refer to the elements
  * of po->prot_hook.  If the sync parameter is false, it is the
@@ -361,6 +366,8 @@ static void __unregister_prot_hook(struct sock *sk, bool sync)
 {
        struct packet_sock *po = pkt_sk(sk);
 
+       lockdep_assert_held_once(&po->bind_lock);
+
        po->running = 0;
 
        if (po->fanout)
@@ -3017,6 +3024,7 @@ static int packet_release(struct socket *sock)
 
        packet_flush_mclist(sk);
 
+       lock_sock(sk);
        if (po->rx_ring.pg_vec) {
                memset(&req_u, 0, sizeof(req_u));
                packet_set_ring(sk, &req_u, 1, 0);
@@ -3026,6 +3034,7 @@ static int packet_release(struct socket *sock)
                memset(&req_u, 0, sizeof(req_u));
                packet_set_ring(sk, &req_u, 1, 1);
        }
+       release_sock(sk);
 
        f = fanout_release(sk);
 
@@ -3259,7 +3268,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
 
        if (proto) {
                po->prot_hook.type = proto;
-               register_prot_hook(sk);
+               __register_prot_hook(sk);
        }
 
        mutex_lock(&net->packet.sklist_lock);
@@ -3654,6 +3663,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
                union tpacket_req_u req_u;
                int len;
 
+               lock_sock(sk);
                switch (po->tp_version) {
                case TPACKET_V1:
                case TPACKET_V2:
@@ -3664,12 +3674,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
                        len = sizeof(req_u.req3);
                        break;
                }
-               if (optlen < len)
-                       return -EINVAL;
-               if (copy_from_user(&req_u.req, optval, len))
-                       return -EFAULT;
-               return packet_set_ring(sk, &req_u, 0,
-                       optname == PACKET_TX_RING);
+               if (optlen < len) {
+                       ret = -EINVAL;
+               } else {
+                       if (copy_from_user(&req_u.req, optval, len))
+                               ret = -EFAULT;
+                       else
+                               ret = packet_set_ring(sk, &req_u, 0,
+                                                   optname == PACKET_TX_RING);
+               }
+               release_sock(sk);
+               return ret;
        }
        case PACKET_COPY_THRESH:
        {
@@ -3735,12 +3750,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
 
                if (optlen != sizeof(val))
                        return -EINVAL;
-               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
-                       return -EBUSY;
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
-               po->tp_loss = !!val;
-               return 0;
+
+               lock_sock(sk);
+               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
+                       ret = -EBUSY;
+               } else {
+                       po->tp_loss = !!val;
+                       ret = 0;
+               }
+               release_sock(sk);
+               return ret;
        }
        case PACKET_AUXDATA:
        {
@@ -3751,7 +3772,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
 
+               lock_sock(sk);
                po->auxdata = !!val;
+               release_sock(sk);
                return 0;
        }
        case PACKET_ORIGDEV:
@@ -3763,7 +3786,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
 
+               lock_sock(sk);
                po->origdev = !!val;
+               release_sock(sk);
                return 0;
        }
        case PACKET_VNET_HDR:
@@ -3772,15 +3797,20 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
 
                if (sock->type != SOCK_RAW)
                        return -EINVAL;
-               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
-                       return -EBUSY;
                if (optlen < sizeof(val))
                        return -EINVAL;
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
 
-               po->has_vnet_hdr = !!val;
-               return 0;
+               lock_sock(sk);
+               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
+                       ret = -EBUSY;
+               } else {
+                       po->has_vnet_hdr = !!val;
+                       ret = 0;
+               }
+               release_sock(sk);
+               return ret;
        }
        case PACKET_TIMESTAMP:
        {
@@ -3818,11 +3848,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
 
                if (optlen != sizeof(val))
                        return -EINVAL;
-               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
-                       return -EBUSY;
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
-               po->tp_tx_has_off = !!val;
+
+               lock_sock(sk);
+               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
+                       ret = -EBUSY;
+               } else {
+                       po->tp_tx_has_off = !!val;
+                       ret = 0;
+               }
+               release_sock(sk);
                return 0;
        }
        case PACKET_QDISC_BYPASS:
@@ -4219,8 +4255,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
        /* Added to avoid minimal code churn */
        struct tpacket_req *req = &req_u->req;
 
-       lock_sock(sk);
-
        rb = tx_ring ? &po->tx_ring : &po->rx_ring;
        rb_queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
 
@@ -4358,7 +4392,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
        if (pg_vec)
                free_pg_vec(pg_vec, order, req->tp_block_nr);
 out:
-       release_sock(sk);
        return err;
 }
 
index a1d2b2319ae990d55bb3c469cc1ba404cadcbdb9..3bb7c5fb3bff2fd5d91c3d973d006d0cdde29a0b 100644 (file)
@@ -112,10 +112,12 @@ struct packet_sock {
        int                     copy_thresh;
        spinlock_t              bind_lock;
        struct mutex            pg_vec_lock;
-       unsigned int            running:1,      /* prot_hook is attached*/
-                               auxdata:1,
+       unsigned int            running;        /* bind_lock must be held */
+       unsigned int            auxdata:1,      /* writer must hold sock lock */
                                origdev:1,
-                               has_vnet_hdr:1;
+                               has_vnet_hdr:1,
+                               tp_loss:1,
+                               tp_tx_has_off:1;
        int                     pressure;
        int                     ifindex;        /* bound device         */
        __be16                  num;
@@ -125,8 +127,6 @@ struct packet_sock {
        enum tpacket_versions   tp_version;
        unsigned int            tp_hdrlen;
        unsigned int            tp_reserve;
-       unsigned int            tp_loss:1;
-       unsigned int            tp_tx_has_off:1;
        unsigned int            tp_tstamp;
        struct net_device __rcu *cached_dev;
        int                     (*xmit)(struct sk_buff *skb);
index 8ccd35825b6b97f48311c1060f88a41a34f18f9a..85757af7f1508522e4dc7468c92cacd402987047 100644 (file)
@@ -605,7 +605,7 @@ static int find_decode_metaid(struct sk_buff *skb, struct tcf_ife_info *ife,
                }
        }
 
-       return 0;
+       return -ENOENT;
 }
 
 static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
@@ -639,7 +639,12 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
                u16 mtype;
                u16 dlen;
 
-               curr_data = ife_tlv_meta_decode(tlv_data, &mtype, &dlen, NULL);
+               curr_data = ife_tlv_meta_decode(tlv_data, ifehdr_end, &mtype,
+                                               &dlen, NULL);
+               if (!curr_data) {
+                       qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats));
+                       return TC_ACT_SHOT;
+               }
 
                if (find_decode_metaid(skb, ife, mtype, dlen, curr_data)) {
                        /* abuse overlimits to count when we receive metadata
index 08b5705e73813a189ce89e3b2b24eb3d3ffe29b7..7219a1c041f759da3c6275d15824799274e3ee01 100644 (file)
@@ -521,46 +521,49 @@ static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
        addr->v6.sin6_scope_id = 0;
 }
 
-/* Compare addresses exactly.
- * v4-mapped-v6 is also in consideration.
- */
-static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
-                           const union sctp_addr *addr2)
+static int __sctp_v6_cmp_addr(const union sctp_addr *addr1,
+                             const union sctp_addr *addr2)
 {
        if (addr1->sa.sa_family != addr2->sa.sa_family) {
                if (addr1->sa.sa_family == AF_INET &&
                    addr2->sa.sa_family == AF_INET6 &&
-                   ipv6_addr_v4mapped(&addr2->v6.sin6_addr)) {
-                       if (addr2->v6.sin6_port == addr1->v4.sin_port &&
-                           addr2->v6.sin6_addr.s6_addr32[3] ==
-                           addr1->v4.sin_addr.s_addr)
-                               return 1;
-               }
+                   ipv6_addr_v4mapped(&addr2->v6.sin6_addr) &&
+                   addr2->v6.sin6_addr.s6_addr32[3] ==
+                   addr1->v4.sin_addr.s_addr)
+                       return 1;
+
                if (addr2->sa.sa_family == AF_INET &&
                    addr1->sa.sa_family == AF_INET6 &&
-                   ipv6_addr_v4mapped(&addr1->v6.sin6_addr)) {
-                       if (addr1->v6.sin6_port == addr2->v4.sin_port &&
-                           addr1->v6.sin6_addr.s6_addr32[3] ==
-                           addr2->v4.sin_addr.s_addr)
-                               return 1;
-               }
+                   ipv6_addr_v4mapped(&addr1->v6.sin6_addr) &&
+                   addr1->v6.sin6_addr.s6_addr32[3] ==
+                   addr2->v4.sin_addr.s_addr)
+                       return 1;
+
                return 0;
        }
-       if (addr1->v6.sin6_port != addr2->v6.sin6_port)
-               return 0;
+
        if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr))
                return 0;
+
        /* If this is a linklocal address, compare the scope_id. */
-       if (ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
-               if (addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id &&
-                   (addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id)) {
-                       return 0;
-               }
-       }
+       if ((ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
+           addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id &&
+           addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id)
+               return 0;
 
        return 1;
 }
 
+/* Compare addresses exactly.
+ * v4-mapped-v6 is also in consideration.
+ */
+static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
+                           const union sctp_addr *addr2)
+{
+       return __sctp_v6_cmp_addr(addr1, addr2) &&
+              addr1->v6.sin6_port == addr2->v6.sin6_port;
+}
+
 /* Initialize addr struct to INADDR_ANY. */
 static void sctp_v6_inaddr_any(union sctp_addr *addr, __be16 port)
 {
@@ -845,8 +848,8 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
                               const union sctp_addr *addr2,
                               struct sctp_sock *opt)
 {
-       struct sctp_af *af1, *af2;
        struct sock *sk = sctp_opt2sk(opt);
+       struct sctp_af *af1, *af2;
 
        af1 = sctp_get_af_specific(addr1->sa.sa_family);
        af2 = sctp_get_af_specific(addr2->sa.sa_family);
@@ -862,10 +865,7 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
        if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2))
                return 1;
 
-       if (addr1->sa.sa_family != addr2->sa.sa_family)
-               return 0;
-
-       return af1->cmp_addr(addr1, addr2);
+       return __sctp_v6_cmp_addr(addr1, addr2);
 }
 
 /* Verify that the provided sockaddr looks bindable.   Common verification,
index a6d604fd969586e5e744a6b1cc092a898bb2d9fb..f9c289e05707bcd8f29e6d46237b899c98f40b4b 100644 (file)
@@ -1203,14 +1203,12 @@ static int smc_shutdown(struct socket *sock, int how)
                rc = smc_close_shutdown_write(smc);
                break;
        case SHUT_RD:
-               if (sk->sk_state == SMC_LISTEN)
-                       rc = smc_close_active(smc);
-               else
-                       rc = 0;
-                       /* nothing more to do because peer is not involved */
+               rc = 0;
+               /* nothing more to do because peer is not involved */
                break;
        }
-       rc1 = kernel_sock_shutdown(smc->clcsock, how);
+       if (smc->clcsock)
+               rc1 = kernel_sock_shutdown(smc->clcsock, how);
        /* map sock_shutdown_cmd constants to sk_shutdown value range */
        sk->sk_shutdown |= how + 1;
 
index 4a3a3f1331ee8f24d573069c1296ef7929bb1362..c741365f77daf9e92b6485d212c50ab6be3f6430 100644 (file)
@@ -67,7 +67,7 @@ static void strp_abort_strp(struct strparser *strp, int err)
 
 static void strp_start_timer(struct strparser *strp, long timeo)
 {
-       if (timeo)
+       if (timeo && timeo != LONG_MAX)
                mod_delayed_work(strp_wq, &strp->msg_timer_work, timeo);
 }
 
@@ -296,9 +296,9 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
                                        strp_start_timer(strp, timeo);
                                }
 
+                               stm->accum_len += cand_len;
                                strp->need_bytes = stm->strp.full_len -
                                                       stm->accum_len;
-                               stm->accum_len += cand_len;
                                stm->early_eaten = cand_len;
                                STRP_STATS_ADD(strp->stats.bytes, cand_len);
                                desc->count = 0; /* Stop reading socket */
@@ -321,6 +321,7 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
                /* Hurray, we have a new message! */
                cancel_delayed_work(&strp->msg_timer_work);
                strp->skb_head = NULL;
+               strp->need_bytes = 0;
                STRP_STATS_INCR(strp->stats.msgs);
 
                /* Give skb to upper layer */
@@ -410,9 +411,7 @@ void strp_data_ready(struct strparser *strp)
                return;
 
        if (strp->need_bytes) {
-               if (strp_peek_len(strp) >= strp->need_bytes)
-                       strp->need_bytes = 0;
-               else
+               if (strp_peek_len(strp) < strp->need_bytes)
                        return;
        }
 
index b76f13f6fea10a53d00ed14a38cdf5cdf7afa44c..d4e0bbeee72793a060befaf8a9d0239731c0d48c 100644 (file)
@@ -79,7 +79,8 @@ const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = {
 
 const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = {
        [TIPC_NLA_NET_UNSPEC]           = { .type = NLA_UNSPEC },
-       [TIPC_NLA_NET_ID]               = { .type = NLA_U32 }
+       [TIPC_NLA_NET_ID]               = { .type = NLA_U32 },
+       [TIPC_NLA_NET_ADDR]             = { .type = NLA_U32 },
 };
 
 const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = {
index 163e701f8d050fe66d206dda2d6e548452d484c1..2396664fe09ce9f54544b64fa97b98119cfd5c3c 100644 (file)
@@ -474,6 +474,8 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
                                magic |= VFS_CAP_FLAGS_EFFECTIVE;
                        memcpy(&cap->data, &nscap->data, sizeof(__le32) * 2 * VFS_CAP_U32);
                        cap->magic_etc = cpu_to_le32(magic);
+               } else {
+                       size = -ENOMEM;
                }
        }
        kfree(tmpbuf);