summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2017-03-12 08:17:37 -0400
committerMike Pagano <mpagano@gentoo.org>2017-03-12 08:17:37 -0400
commit91367744ce5b3751a6e8288292d5d2692aaff55f (patch)
treec98b4264ed278cac4462a93e3990604a2c84128d
parentEnable crypto API for systemd as its required for systemd versions >= 233. Se... (diff)
downloadlinux-patches-91367744ce5b3751a6e8288292d5d2692aaff55f.tar.gz
linux-patches-91367744ce5b3751a6e8288292d5d2692aaff55f.tar.bz2
linux-patches-91367744ce5b3751a6e8288292d5d2692aaff55f.zip
Linux patch 4.4.534.4-57
-rw-r--r--0000_README4
-rw-r--r--1052_linux-4.4.53.patch8444
2 files changed, 8448 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index 747896bd..ef8c4007 100644
--- a/0000_README
+++ b/0000_README
@@ -251,6 +251,10 @@ Patch: 1051_linux-4.4.52.patch
From: http://www.kernel.org
Desc: Linux 4.4.52
+Patch: 1052_linux-4.4.53.patch
+From: http://www.kernel.org
+Desc: Linux 4.4.53
+
Patch: 1500_XATTR_USER_PREFIX.patch
From: https://bugs.gentoo.org/show_bug.cgi?id=470644
Desc: Support for namespace user.pax.* on tmpfs.
diff --git a/1052_linux-4.4.53.patch b/1052_linux-4.4.53.patch
new file mode 100644
index 00000000..cdd968b5
--- /dev/null
+++ b/1052_linux-4.4.53.patch
@@ -0,0 +1,8444 @@
+diff --git a/Documentation/Makefile b/Documentation/Makefile
+index bc0548201755..fc759598c4c9 100644
+--- a/Documentation/Makefile
++++ b/Documentation/Makefile
+@@ -1,4 +1,4 @@
+ subdir-y := accounting auxdisplay blackfin connector \
+- filesystems filesystems ia64 laptops mic misc-devices \
++ filesystems filesystems ia64 laptops misc-devices \
+ networking pcmcia prctl ptp spi timers vDSO video4linux \
+ watchdog
+diff --git a/Documentation/mic/Makefile b/Documentation/mic/Makefile
+deleted file mode 100644
+index a191d453badf..000000000000
+--- a/Documentation/mic/Makefile
++++ /dev/null
+@@ -1 +0,0 @@
+-subdir-y := mpssd
+diff --git a/Documentation/mic/mpssd/.gitignore b/Documentation/mic/mpssd/.gitignore
+deleted file mode 100644
+index 8b7c72f07c92..000000000000
+--- a/Documentation/mic/mpssd/.gitignore
++++ /dev/null
+@@ -1 +0,0 @@
+-mpssd
+diff --git a/Documentation/mic/mpssd/Makefile b/Documentation/mic/mpssd/Makefile
+deleted file mode 100644
+index 06871b0c08a6..000000000000
+--- a/Documentation/mic/mpssd/Makefile
++++ /dev/null
+@@ -1,21 +0,0 @@
+-ifndef CROSS_COMPILE
+-# List of programs to build
+-hostprogs-$(CONFIG_X86_64) := mpssd
+-
+-mpssd-objs := mpssd.o sysfs.o
+-
+-# Tell kbuild to always build the programs
+-always := $(hostprogs-y)
+-
+-HOSTCFLAGS += -I$(objtree)/usr/include -I$(srctree)/tools/include
+-
+-ifdef DEBUG
+-HOSTCFLAGS += -DDEBUG=$(DEBUG)
+-endif
+-
+-HOSTLOADLIBES_mpssd := -lpthread
+-
+-install:
+- install mpssd /usr/sbin/mpssd
+- install micctrl /usr/sbin/micctrl
+-endif
+diff --git a/Documentation/mic/mpssd/micctrl b/Documentation/mic/mpssd/micctrl
+deleted file mode 100755
+index 8f2629b41c5f..000000000000
+--- a/Documentation/mic/mpssd/micctrl
++++ /dev/null
+@@ -1,173 +0,0 @@
+-#!/bin/bash
+-# Intel MIC Platform Software Stack (MPSS)
+-#
+-# Copyright(c) 2013 Intel Corporation.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License, version 2, as
+-# published by the Free Software Foundation.
+-#
+-# This program is distributed in the hope that it will be useful, but
+-# WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-# General Public License for more details.
+-#
+-# The full GNU General Public License is included in this distribution in
+-# the file called "COPYING".
+-#
+-# Intel MIC User Space Tools.
+-#
+-# micctrl - Controls MIC boot/start/stop.
+-#
+-# chkconfig: 2345 95 05
+-# description: start MPSS stack processing.
+-#
+-### BEGIN INIT INFO
+-# Provides: micctrl
+-### END INIT INFO
+-
+-# Source function library.
+-. /etc/init.d/functions
+-
+-sysfs="/sys/class/mic"
+-
+-_status()
+-{
+- f=$sysfs/$1
+- echo -e $1 state: "`cat $f/state`" shutdown_status: "`cat $f/shutdown_status`"
+-}
+-
+-status()
+-{
+- if [ "`echo $1 | head -c3`" == "mic" ]; then
+- _status $1
+- return $?
+- fi
+- for f in $sysfs/*
+- do
+- _status `basename $f`
+- RETVAL=$?
+- [ $RETVAL -ne 0 ] && return $RETVAL
+- done
+- return 0
+-}
+-
+-_reset()
+-{
+- f=$sysfs/$1
+- echo reset > $f/state
+-}
+-
+-reset()
+-{
+- if [ "`echo $1 | head -c3`" == "mic" ]; then
+- _reset $1
+- return $?
+- fi
+- for f in $sysfs/*
+- do
+- _reset `basename $f`
+- RETVAL=$?
+- [ $RETVAL -ne 0 ] && return $RETVAL
+- done
+- return 0
+-}
+-
+-_boot()
+-{
+- f=$sysfs/$1
+- echo "linux" > $f/bootmode
+- echo "mic/uos.img" > $f/firmware
+- echo "mic/$1.image" > $f/ramdisk
+- echo "boot" > $f/state
+-}
+-
+-boot()
+-{
+- if [ "`echo $1 | head -c3`" == "mic" ]; then
+- _boot $1
+- return $?
+- fi
+- for f in $sysfs/*
+- do
+- _boot `basename $f`
+- RETVAL=$?
+- [ $RETVAL -ne 0 ] && return $RETVAL
+- done
+- return 0
+-}
+-
+-_shutdown()
+-{
+- f=$sysfs/$1
+- echo shutdown > $f/state
+-}
+-
+-shutdown()
+-{
+- if [ "`echo $1 | head -c3`" == "mic" ]; then
+- _shutdown $1
+- return $?
+- fi
+- for f in $sysfs/*
+- do
+- _shutdown `basename $f`
+- RETVAL=$?
+- [ $RETVAL -ne 0 ] && return $RETVAL
+- done
+- return 0
+-}
+-
+-_wait()
+-{
+- f=$sysfs/$1
+- while [ "`cat $f/state`" != "offline" -a "`cat $f/state`" != "online" ]
+- do
+- sleep 1
+- echo -e "Waiting for $1 to go offline"
+- done
+-}
+-
+-wait()
+-{
+- if [ "`echo $1 | head -c3`" == "mic" ]; then
+- _wait $1
+- return $?
+- fi
+- # Wait for the cards to go offline
+- for f in $sysfs/*
+- do
+- _wait `basename $f`
+- RETVAL=$?
+- [ $RETVAL -ne 0 ] && return $RETVAL
+- done
+- return 0
+-}
+-
+-if [ ! -d "$sysfs" ]; then
+- echo -e $"Module unloaded "
+- exit 3
+-fi
+-
+-case $1 in
+- -s)
+- status $2
+- ;;
+- -r)
+- reset $2
+- ;;
+- -b)
+- boot $2
+- ;;
+- -S)
+- shutdown $2
+- ;;
+- -w)
+- wait $2
+- ;;
+- *)
+- echo $"Usage: $0 {-s (status) |-r (reset) |-b (boot) |-S (shutdown) |-w (wait)}"
+- exit 2
+-esac
+-
+-exit $?
+diff --git a/Documentation/mic/mpssd/mpss b/Documentation/mic/mpssd/mpss
+deleted file mode 100755
+index 09ea90931649..000000000000
+--- a/Documentation/mic/mpssd/mpss
++++ /dev/null
+@@ -1,200 +0,0 @@
+-#!/bin/bash
+-# Intel MIC Platform Software Stack (MPSS)
+-#
+-# Copyright(c) 2013 Intel Corporation.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License, version 2, as
+-# published by the Free Software Foundation.
+-#
+-# This program is distributed in the hope that it will be useful, but
+-# WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-# General Public License for more details.
+-#
+-# The full GNU General Public License is included in this distribution in
+-# the file called "COPYING".
+-#
+-# Intel MIC User Space Tools.
+-#
+-# mpss Start mpssd.
+-#
+-# chkconfig: 2345 95 05
+-# description: start MPSS stack processing.
+-#
+-### BEGIN INIT INFO
+-# Provides: mpss
+-# Required-Start:
+-# Required-Stop:
+-# Short-Description: MPSS stack control
+-# Description: MPSS stack control
+-### END INIT INFO
+-
+-# Source function library.
+-. /etc/init.d/functions
+-
+-exec=/usr/sbin/mpssd
+-sysfs="/sys/class/mic"
+-mic_modules="mic_host mic_x100_dma scif"
+-
+-start()
+-{
+- [ -x $exec ] || exit 5
+-
+- if [ "`ps -e | awk '{print $4}' | grep mpssd | head -1`" = "mpssd" ]; then
+- echo -e $"MPSSD already running! "
+- success
+- echo
+- return 0
+- fi
+-
+- echo -e $"Starting MPSS Stack"
+- echo -e $"Loading MIC drivers:" $mic_modules
+-
+- modprobe -a $mic_modules
+- RETVAL=$?
+- if [ $RETVAL -ne 0 ]; then
+- failure
+- echo
+- return $RETVAL
+- fi
+-
+- # Start the daemon
+- echo -n $"Starting MPSSD "
+- $exec
+- RETVAL=$?
+- if [ $RETVAL -ne 0 ]; then
+- failure
+- echo
+- return $RETVAL
+- fi
+- success
+- echo
+-
+- sleep 5
+-
+- # Boot the cards
+- micctrl -b
+-
+- # Wait till ping works
+- for f in $sysfs/*
+- do
+- count=100
+- ipaddr=`cat $f/cmdline`
+- ipaddr=${ipaddr#*address,}
+- ipaddr=`echo $ipaddr | cut -d, -f1 | cut -d\; -f1`
+- while [ $count -ge 0 ]
+- do
+- echo -e "Pinging "`basename $f`" "
+- ping -c 1 $ipaddr &> /dev/null
+- RETVAL=$?
+- if [ $RETVAL -eq 0 ]; then
+- success
+- break
+- fi
+- sleep 1
+- count=`expr $count - 1`
+- done
+- [ $RETVAL -ne 0 ] && failure || success
+- echo
+- done
+- return $RETVAL
+-}
+-
+-stop()
+-{
+- echo -e $"Shutting down MPSS Stack: "
+-
+- # Bail out if module is unloaded
+- if [ ! -d "$sysfs" ]; then
+- echo -n $"Module unloaded "
+- success
+- echo
+- return 0
+- fi
+-
+- # Shut down the cards.
+- micctrl -S
+-
+- # Wait for the cards to go offline
+- for f in $sysfs/*
+- do
+- while [ "`cat $f/state`" != "ready" ]
+- do
+- sleep 1
+- echo -e "Waiting for "`basename $f`" to become ready"
+- done
+- done
+-
+- # Display the status of the cards
+- micctrl -s
+-
+- # Kill MPSSD now
+- echo -n $"Killing MPSSD"
+- killall -9 mpssd 2>/dev/null
+- RETVAL=$?
+- [ $RETVAL -ne 0 ] && failure || success
+- echo
+- return $RETVAL
+-}
+-
+-restart()
+-{
+- stop
+- sleep 5
+- start
+-}
+-
+-status()
+-{
+- micctrl -s
+- if [ "`ps -e | awk '{print $4}' | grep mpssd | head -n 1`" = "mpssd" ]; then
+- echo "mpssd is running"
+- else
+- echo "mpssd is stopped"
+- fi
+- return 0
+-}
+-
+-unload()
+-{
+- if [ ! -d "$sysfs" ]; then
+- echo -n $"No MIC_HOST Module: "
+- success
+- echo
+- return
+- fi
+-
+- stop
+-
+- sleep 5
+- echo -n $"Removing MIC drivers:" $mic_modules
+- modprobe -r $mic_modules
+- RETVAL=$?
+- [ $RETVAL -ne 0 ] && failure || success
+- echo
+- return $RETVAL
+-}
+-
+-case $1 in
+- start)
+- start
+- ;;
+- stop)
+- stop
+- ;;
+- restart)
+- restart
+- ;;
+- status)
+- status
+- ;;
+- unload)
+- unload
+- ;;
+- *)
+- echo $"Usage: $0 {start|stop|restart|status|unload}"
+- exit 2
+-esac
+-
+-exit $?
+diff --git a/Documentation/mic/mpssd/mpssd.c b/Documentation/mic/mpssd/mpssd.c
+deleted file mode 100644
+index c99a75968c01..000000000000
+--- a/Documentation/mic/mpssd/mpssd.c
++++ /dev/null
+@@ -1,1826 +0,0 @@
+-/*
+- * Intel MIC Platform Software Stack (MPSS)
+- *
+- * Copyright(c) 2013 Intel Corporation.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License, version 2, as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * General Public License for more details.
+- *
+- * The full GNU General Public License is included in this distribution in
+- * the file called "COPYING".
+- *
+- * Intel MIC User Space Tools.
+- */
+-
+-#define _GNU_SOURCE
+-
+-#include <stdlib.h>
+-#include <fcntl.h>
+-#include <getopt.h>
+-#include <assert.h>
+-#include <unistd.h>
+-#include <stdbool.h>
+-#include <signal.h>
+-#include <poll.h>
+-#include <features.h>
+-#include <sys/types.h>
+-#include <sys/stat.h>
+-#include <sys/mman.h>
+-#include <sys/socket.h>
+-#include <linux/virtio_ring.h>
+-#include <linux/virtio_net.h>
+-#include <linux/virtio_console.h>
+-#include <linux/virtio_blk.h>
+-#include <linux/version.h>
+-#include "mpssd.h"
+-#include <linux/mic_ioctl.h>
+-#include <linux/mic_common.h>
+-#include <tools/endian.h>
+-
+-static void *init_mic(void *arg);
+-
+-static FILE *logfp;
+-static struct mic_info mic_list;
+-
+-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+-
+-#define min_t(type, x, y) ({ \
+- type __min1 = (x); \
+- type __min2 = (y); \
+- __min1 < __min2 ? __min1 : __min2; })
+-
+-/* align addr on a size boundary - adjust address up/down if needed */
+-#define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1)))
+-#define _ALIGN_UP(addr, size) _ALIGN_DOWN(addr + size - 1, size)
+-
+-/* align addr on a size boundary - adjust address up if needed */
+-#define _ALIGN(addr, size) _ALIGN_UP(addr, size)
+-
+-/* to align the pointer to the (next) page boundary */
+-#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
+-
+-#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+-
+-#define GSO_ENABLED 1
+-#define MAX_GSO_SIZE (64 * 1024)
+-#define ETH_H_LEN 14
+-#define MAX_NET_PKT_SIZE (_ALIGN_UP(MAX_GSO_SIZE + ETH_H_LEN, 64))
+-#define MIC_DEVICE_PAGE_END 0x1000
+-
+-#ifndef VIRTIO_NET_HDR_F_DATA_VALID
+-#define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */
+-#endif
+-
+-static struct {
+- struct mic_device_desc dd;
+- struct mic_vqconfig vqconfig[2];
+- __u32 host_features, guest_acknowledgements;
+- struct virtio_console_config cons_config;
+-} virtcons_dev_page = {
+- .dd = {
+- .type = VIRTIO_ID_CONSOLE,
+- .num_vq = ARRAY_SIZE(virtcons_dev_page.vqconfig),
+- .feature_len = sizeof(virtcons_dev_page.host_features),
+- .config_len = sizeof(virtcons_dev_page.cons_config),
+- },
+- .vqconfig[0] = {
+- .num = htole16(MIC_VRING_ENTRIES),
+- },
+- .vqconfig[1] = {
+- .num = htole16(MIC_VRING_ENTRIES),
+- },
+-};
+-
+-static struct {
+- struct mic_device_desc dd;
+- struct mic_vqconfig vqconfig[2];
+- __u32 host_features, guest_acknowledgements;
+- struct virtio_net_config net_config;
+-} virtnet_dev_page = {
+- .dd = {
+- .type = VIRTIO_ID_NET,
+- .num_vq = ARRAY_SIZE(virtnet_dev_page.vqconfig),
+- .feature_len = sizeof(virtnet_dev_page.host_features),
+- .config_len = sizeof(virtnet_dev_page.net_config),
+- },
+- .vqconfig[0] = {
+- .num = htole16(MIC_VRING_ENTRIES),
+- },
+- .vqconfig[1] = {
+- .num = htole16(MIC_VRING_ENTRIES),
+- },
+-#if GSO_ENABLED
+- .host_features = htole32(
+- 1 << VIRTIO_NET_F_CSUM |
+- 1 << VIRTIO_NET_F_GSO |
+- 1 << VIRTIO_NET_F_GUEST_TSO4 |
+- 1 << VIRTIO_NET_F_GUEST_TSO6 |
+- 1 << VIRTIO_NET_F_GUEST_ECN),
+-#else
+- .host_features = 0,
+-#endif
+-};
+-
+-static const char *mic_config_dir = "/etc/mpss";
+-static const char *virtblk_backend = "VIRTBLK_BACKEND";
+-static struct {
+- struct mic_device_desc dd;
+- struct mic_vqconfig vqconfig[1];
+- __u32 host_features, guest_acknowledgements;
+- struct virtio_blk_config blk_config;
+-} virtblk_dev_page = {
+- .dd = {
+- .type = VIRTIO_ID_BLOCK,
+- .num_vq = ARRAY_SIZE(virtblk_dev_page.vqconfig),
+- .feature_len = sizeof(virtblk_dev_page.host_features),
+- .config_len = sizeof(virtblk_dev_page.blk_config),
+- },
+- .vqconfig[0] = {
+- .num = htole16(MIC_VRING_ENTRIES),
+- },
+- .host_features =
+- htole32(1<<VIRTIO_BLK_F_SEG_MAX),
+- .blk_config = {
+- .seg_max = htole32(MIC_VRING_ENTRIES - 2),
+- .capacity = htole64(0),
+- }
+-};
+-
+-static char *myname;
+-
+-static int
+-tap_configure(struct mic_info *mic, char *dev)
+-{
+- pid_t pid;
+- char *ifargv[7];
+- char ipaddr[IFNAMSIZ];
+- int ret = 0;
+-
+- pid = fork();
+- if (pid == 0) {
+- ifargv[0] = "ip";
+- ifargv[1] = "link";
+- ifargv[2] = "set";
+- ifargv[3] = dev;
+- ifargv[4] = "up";
+- ifargv[5] = NULL;
+- mpsslog("Configuring %s\n", dev);
+- ret = execvp("ip", ifargv);
+- if (ret < 0) {
+- mpsslog("%s execvp failed errno %s\n",
+- mic->name, strerror(errno));
+- return ret;
+- }
+- }
+- if (pid < 0) {
+- mpsslog("%s fork failed errno %s\n",
+- mic->name, strerror(errno));
+- return ret;
+- }
+-
+- ret = waitpid(pid, NULL, 0);
+- if (ret < 0) {
+- mpsslog("%s waitpid failed errno %s\n",
+- mic->name, strerror(errno));
+- return ret;
+- }
+-
+- snprintf(ipaddr, IFNAMSIZ, "172.31.%d.254/24", mic->id + 1);
+-
+- pid = fork();
+- if (pid == 0) {
+- ifargv[0] = "ip";
+- ifargv[1] = "addr";
+- ifargv[2] = "add";
+- ifargv[3] = ipaddr;
+- ifargv[4] = "dev";
+- ifargv[5] = dev;
+- ifargv[6] = NULL;
+- mpsslog("Configuring %s ipaddr %s\n", dev, ipaddr);
+- ret = execvp("ip", ifargv);
+- if (ret < 0) {
+- mpsslog("%s execvp failed errno %s\n",
+- mic->name, strerror(errno));
+- return ret;
+- }
+- }
+- if (pid < 0) {
+- mpsslog("%s fork failed errno %s\n",
+- mic->name, strerror(errno));
+- return ret;
+- }
+-
+- ret = waitpid(pid, NULL, 0);
+- if (ret < 0) {
+- mpsslog("%s waitpid failed errno %s\n",
+- mic->name, strerror(errno));
+- return ret;
+- }
+- mpsslog("MIC name %s %s %d DONE!\n",
+- mic->name, __func__, __LINE__);
+- return 0;
+-}
+-
+-static int tun_alloc(struct mic_info *mic, char *dev)
+-{
+- struct ifreq ifr;
+- int fd, err;
+-#if GSO_ENABLED
+- unsigned offload;
+-#endif
+- fd = open("/dev/net/tun", O_RDWR);
+- if (fd < 0) {
+- mpsslog("Could not open /dev/net/tun %s\n", strerror(errno));
+- goto done;
+- }
+-
+- memset(&ifr, 0, sizeof(ifr));
+-
+- ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
+- if (*dev)
+- strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+-
+- err = ioctl(fd, TUNSETIFF, (void *)&ifr);
+- if (err < 0) {
+- mpsslog("%s %s %d TUNSETIFF failed %s\n",
+- mic->name, __func__, __LINE__, strerror(errno));
+- close(fd);
+- return err;
+- }
+-#if GSO_ENABLED
+- offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_TSO_ECN;
+-
+- err = ioctl(fd, TUNSETOFFLOAD, offload);
+- if (err < 0) {
+- mpsslog("%s %s %d TUNSETOFFLOAD failed %s\n",
+- mic->name, __func__, __LINE__, strerror(errno));
+- close(fd);
+- return err;
+- }
+-#endif
+- strcpy(dev, ifr.ifr_name);
+- mpsslog("Created TAP %s\n", dev);
+-done:
+- return fd;
+-}
+-
+-#define NET_FD_VIRTIO_NET 0
+-#define NET_FD_TUN 1
+-#define MAX_NET_FD 2
+-
+-static void set_dp(struct mic_info *mic, int type, void *dp)
+-{
+- switch (type) {
+- case VIRTIO_ID_CONSOLE:
+- mic->mic_console.console_dp = dp;
+- return;
+- case VIRTIO_ID_NET:
+- mic->mic_net.net_dp = dp;
+- return;
+- case VIRTIO_ID_BLOCK:
+- mic->mic_virtblk.block_dp = dp;
+- return;
+- }
+- mpsslog("%s %s %d not found\n", mic->name, __func__, type);
+- assert(0);
+-}
+-
+-static void *get_dp(struct mic_info *mic, int type)
+-{
+- switch (type) {
+- case VIRTIO_ID_CONSOLE:
+- return mic->mic_console.console_dp;
+- case VIRTIO_ID_NET:
+- return mic->mic_net.net_dp;
+- case VIRTIO_ID_BLOCK:
+- return mic->mic_virtblk.block_dp;
+- }
+- mpsslog("%s %s %d not found\n", mic->name, __func__, type);
+- assert(0);
+- return NULL;
+-}
+-
+-static struct mic_device_desc *get_device_desc(struct mic_info *mic, int type)
+-{
+- struct mic_device_desc *d;
+- int i;
+- void *dp = get_dp(mic, type);
+-
+- for (i = sizeof(struct mic_bootparam); i < PAGE_SIZE;
+- i += mic_total_desc_size(d)) {
+- d = dp + i;
+-
+- /* End of list */
+- if (d->type == 0)
+- break;
+-
+- if (d->type == -1)
+- continue;
+-
+- mpsslog("%s %s d-> type %d d %p\n",
+- mic->name, __func__, d->type, d);
+-
+- if (d->type == (__u8)type)
+- return d;
+- }
+- mpsslog("%s %s %d not found\n", mic->name, __func__, type);
+- return NULL;
+-}
+-
+-/* See comments in vhost.c for explanation of next_desc() */
+-static unsigned next_desc(struct vring_desc *desc)
+-{
+- unsigned int next;
+-
+- if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT))
+- return -1U;
+- next = le16toh(desc->next);
+- return next;
+-}
+-
+-/* Sum up all the IOVEC length */
+-static ssize_t
+-sum_iovec_len(struct mic_copy_desc *copy)
+-{
+- ssize_t sum = 0;
+- int i;
+-
+- for (i = 0; i < copy->iovcnt; i++)
+- sum += copy->iov[i].iov_len;
+- return sum;
+-}
+-
+-static inline void verify_out_len(struct mic_info *mic,
+- struct mic_copy_desc *copy)
+-{
+- if (copy->out_len != sum_iovec_len(copy)) {
+- mpsslog("%s %s %d BUG copy->out_len 0x%x len 0x%zx\n",
+- mic->name, __func__, __LINE__,
+- copy->out_len, sum_iovec_len(copy));
+- assert(copy->out_len == sum_iovec_len(copy));
+- }
+-}
+-
+-/* Display an iovec */
+-static void
+-disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy,
+- const char *s, int line)
+-{
+- int i;
+-
+- for (i = 0; i < copy->iovcnt; i++)
+- mpsslog("%s %s %d copy->iov[%d] addr %p len 0x%zx\n",
+- mic->name, s, line, i,
+- copy->iov[i].iov_base, copy->iov[i].iov_len);
+-}
+-
+-static inline __u16 read_avail_idx(struct mic_vring *vr)
+-{
+- return ACCESS_ONCE(vr->info->avail_idx);
+-}
+-
+-static inline void txrx_prepare(int type, bool tx, struct mic_vring *vr,
+- struct mic_copy_desc *copy, ssize_t len)
+-{
+- copy->vr_idx = tx ? 0 : 1;
+- copy->update_used = true;
+- if (type == VIRTIO_ID_NET)
+- copy->iov[1].iov_len = len - sizeof(struct virtio_net_hdr);
+- else
+- copy->iov[0].iov_len = len;
+-}
+-
+-/* Central API which triggers the copies */
+-static int
+-mic_virtio_copy(struct mic_info *mic, int fd,
+- struct mic_vring *vr, struct mic_copy_desc *copy)
+-{
+- int ret;
+-
+- ret = ioctl(fd, MIC_VIRTIO_COPY_DESC, copy);
+- if (ret) {
+- mpsslog("%s %s %d errno %s ret %d\n",
+- mic->name, __func__, __LINE__,
+- strerror(errno), ret);
+- }
+- return ret;
+-}
+-
+-static inline unsigned _vring_size(unsigned int num, unsigned long align)
+-{
+- return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (3 + num)
+- + align - 1) & ~(align - 1))
+- + sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
+-}
+-
+-/*
+- * This initialization routine requires at least one
+- * vring i.e. vr0. vr1 is optional.
+- */
+-static void *
+-init_vr(struct mic_info *mic, int fd, int type,
+- struct mic_vring *vr0, struct mic_vring *vr1, int num_vq)
+-{
+- int vr_size;
+- char *va;
+-
+- vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES,
+- MIC_VIRTIO_RING_ALIGN) +
+- sizeof(struct _mic_vring_info));
+- va = mmap(NULL, MIC_DEVICE_PAGE_END + vr_size * num_vq,
+- PROT_READ, MAP_SHARED, fd, 0);
+- if (MAP_FAILED == va) {
+- mpsslog("%s %s %d mmap failed errno %s\n",
+- mic->name, __func__, __LINE__,
+- strerror(errno));
+- goto done;
+- }
+- set_dp(mic, type, va);
+- vr0->va = (struct mic_vring *)&va[MIC_DEVICE_PAGE_END];
+- vr0->info = vr0->va +
+- _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN);
+- vring_init(&vr0->vr,
+- MIC_VRING_ENTRIES, vr0->va, MIC_VIRTIO_RING_ALIGN);
+- mpsslog("%s %s vr0 %p vr0->info %p vr_size 0x%x vring 0x%x ",
+- __func__, mic->name, vr0->va, vr0->info, vr_size,
+- _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
+- mpsslog("magic 0x%x expected 0x%x\n",
+- le32toh(vr0->info->magic), MIC_MAGIC + type);
+- assert(le32toh(vr0->info->magic) == MIC_MAGIC + type);
+- if (vr1) {
+- vr1->va = (struct mic_vring *)
+- &va[MIC_DEVICE_PAGE_END + vr_size];
+- vr1->info = vr1->va + _vring_size(MIC_VRING_ENTRIES,
+- MIC_VIRTIO_RING_ALIGN);
+- vring_init(&vr1->vr,
+- MIC_VRING_ENTRIES, vr1->va, MIC_VIRTIO_RING_ALIGN);
+- mpsslog("%s %s vr1 %p vr1->info %p vr_size 0x%x vring 0x%x ",
+- __func__, mic->name, vr1->va, vr1->info, vr_size,
+- _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
+- mpsslog("magic 0x%x expected 0x%x\n",
+- le32toh(vr1->info->magic), MIC_MAGIC + type + 1);
+- assert(le32toh(vr1->info->magic) == MIC_MAGIC + type + 1);
+- }
+-done:
+- return va;
+-}
+-
+-static int
+-wait_for_card_driver(struct mic_info *mic, int fd, int type)
+-{
+- struct pollfd pollfd;
+- int err;
+- struct mic_device_desc *desc = get_device_desc(mic, type);
+- __u8 prev_status;
+-
+- if (!desc)
+- return -ENODEV;
+- prev_status = desc->status;
+- pollfd.fd = fd;
+- mpsslog("%s %s Waiting .... desc-> type %d status 0x%x\n",
+- mic->name, __func__, type, desc->status);
+-
+- while (1) {
+- pollfd.events = POLLIN;
+- pollfd.revents = 0;
+- err = poll(&pollfd, 1, -1);
+- if (err < 0) {
+- mpsslog("%s %s poll failed %s\n",
+- mic->name, __func__, strerror(errno));
+- continue;
+- }
+-
+- if (pollfd.revents) {
+- if (desc->status != prev_status) {
+- mpsslog("%s %s Waiting... desc-> type %d "
+- "status 0x%x\n",
+- mic->name, __func__, type,
+- desc->status);
+- prev_status = desc->status;
+- }
+- if (desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
+- mpsslog("%s %s poll.revents %d\n",
+- mic->name, __func__, pollfd.revents);
+- mpsslog("%s %s desc-> type %d status 0x%x\n",
+- mic->name, __func__, type,
+- desc->status);
+- break;
+- }
+- }
+- }
+- return 0;
+-}
+-
+-/* Spin till we have some descriptors */
+-static void
+-spin_for_descriptors(struct mic_info *mic, struct mic_vring *vr)
+-{
+- __u16 avail_idx = read_avail_idx(vr);
+-
+- while (avail_idx == le16toh(ACCESS_ONCE(vr->vr.avail->idx))) {
+-#ifdef DEBUG
+- mpsslog("%s %s waiting for desc avail %d info_avail %d\n",
+- mic->name, __func__,
+- le16toh(vr->vr.avail->idx), vr->info->avail_idx);
+-#endif
+- sched_yield();
+- }
+-}
+-
+-static void *
+-virtio_net(void *arg)
+-{
+- static __u8 vnet_hdr[2][sizeof(struct virtio_net_hdr)];
+- static __u8 vnet_buf[2][MAX_NET_PKT_SIZE] __attribute__ ((aligned(64)));
+- struct iovec vnet_iov[2][2] = {
+- { { .iov_base = vnet_hdr[0], .iov_len = sizeof(vnet_hdr[0]) },
+- { .iov_base = vnet_buf[0], .iov_len = sizeof(vnet_buf[0]) } },
+- { { .iov_base = vnet_hdr[1], .iov_len = sizeof(vnet_hdr[1]) },
+- { .iov_base = vnet_buf[1], .iov_len = sizeof(vnet_buf[1]) } },
+- };
+- struct iovec *iov0 = vnet_iov[0], *iov1 = vnet_iov[1];
+- struct mic_info *mic = (struct mic_info *)arg;
+- char if_name[IFNAMSIZ];
+- struct pollfd net_poll[MAX_NET_FD];
+- struct mic_vring tx_vr, rx_vr;
+- struct mic_copy_desc copy;
+- struct mic_device_desc *desc;
+- int err;
+-
+- snprintf(if_name, IFNAMSIZ, "mic%d", mic->id);
+- mic->mic_net.tap_fd = tun_alloc(mic, if_name);
+- if (mic->mic_net.tap_fd < 0)
+- goto done;
+-
+- if (tap_configure(mic, if_name))
+- goto done;
+- mpsslog("MIC name %s id %d\n", mic->name, mic->id);
+-
+- net_poll[NET_FD_VIRTIO_NET].fd = mic->mic_net.virtio_net_fd;
+- net_poll[NET_FD_VIRTIO_NET].events = POLLIN;
+- net_poll[NET_FD_TUN].fd = mic->mic_net.tap_fd;
+- net_poll[NET_FD_TUN].events = POLLIN;
+-
+- if (MAP_FAILED == init_vr(mic, mic->mic_net.virtio_net_fd,
+- VIRTIO_ID_NET, &tx_vr, &rx_vr,
+- virtnet_dev_page.dd.num_vq)) {
+- mpsslog("%s init_vr failed %s\n",
+- mic->name, strerror(errno));
+- goto done;
+- }
+-
+- copy.iovcnt = 2;
+- desc = get_device_desc(mic, VIRTIO_ID_NET);
+-
+- while (1) {
+- ssize_t len;
+-
+- net_poll[NET_FD_VIRTIO_NET].revents = 0;
+- net_poll[NET_FD_TUN].revents = 0;
+-
+- /* Start polling for data from tap and virtio net */
+- err = poll(net_poll, 2, -1);
+- if (err < 0) {
+- mpsslog("%s poll failed %s\n",
+- __func__, strerror(errno));
+- continue;
+- }
+- if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+- err = wait_for_card_driver(mic,
+- mic->mic_net.virtio_net_fd,
+- VIRTIO_ID_NET);
+- if (err) {
+- mpsslog("%s %s %d Exiting...\n",
+- mic->name, __func__, __LINE__);
+- break;
+- }
+- }
+- /*
+- * Check if there is data to be read from TUN and write to
+- * virtio net fd if there is.
+- */
+- if (net_poll[NET_FD_TUN].revents & POLLIN) {
+- copy.iov = iov0;
+- len = readv(net_poll[NET_FD_TUN].fd,
+- copy.iov, copy.iovcnt);
+- if (len > 0) {
+- struct virtio_net_hdr *hdr
+- = (struct virtio_net_hdr *)vnet_hdr[0];
+-
+- /* Disable checksums on the card since we are on
+- a reliable PCIe link */
+- hdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID;
+-#ifdef DEBUG
+- mpsslog("%s %s %d hdr->flags 0x%x ", mic->name,
+- __func__, __LINE__, hdr->flags);
+- mpsslog("copy.out_len %d hdr->gso_type 0x%x\n",
+- copy.out_len, hdr->gso_type);
+-#endif
+-#ifdef DEBUG
+- disp_iovec(mic, copy, __func__, __LINE__);
+- mpsslog("%s %s %d read from tap 0x%lx\n",
+- mic->name, __func__, __LINE__,
+- len);
+-#endif
+- spin_for_descriptors(mic, &tx_vr);
+- txrx_prepare(VIRTIO_ID_NET, 1, &tx_vr, &copy,
+- len);
+-
+- err = mic_virtio_copy(mic,
+- mic->mic_net.virtio_net_fd, &tx_vr,
+- &copy);
+- if (err < 0) {
+- mpsslog("%s %s %d mic_virtio_copy %s\n",
+- mic->name, __func__, __LINE__,
+- strerror(errno));
+- }
+- if (!err)
+- verify_out_len(mic, &copy);
+-#ifdef DEBUG
+- disp_iovec(mic, copy, __func__, __LINE__);
+- mpsslog("%s %s %d wrote to net 0x%lx\n",
+- mic->name, __func__, __LINE__,
+- sum_iovec_len(&copy));
+-#endif
+- /* Reinitialize IOV for next run */
+- iov0[1].iov_len = MAX_NET_PKT_SIZE;
+- } else if (len < 0) {
+- disp_iovec(mic, &copy, __func__, __LINE__);
+- mpsslog("%s %s %d read failed %s ", mic->name,
+- __func__, __LINE__, strerror(errno));
+- mpsslog("cnt %d sum %zd\n",
+- copy.iovcnt, sum_iovec_len(&copy));
+- }
+- }
+-
+- /*
+- * Check if there is data to be read from virtio net and
+- * write to TUN if there is.
+- */
+- if (net_poll[NET_FD_VIRTIO_NET].revents & POLLIN) {
+- while (rx_vr.info->avail_idx !=
+- le16toh(rx_vr.vr.avail->idx)) {
+- copy.iov = iov1;
+- txrx_prepare(VIRTIO_ID_NET, 0, &rx_vr, &copy,
+- MAX_NET_PKT_SIZE
+- + sizeof(struct virtio_net_hdr));
+-
+- err = mic_virtio_copy(mic,
+- mic->mic_net.virtio_net_fd, &rx_vr,
+- &copy);
+- if (!err) {
+-#ifdef DEBUG
+- struct virtio_net_hdr *hdr
+- = (struct virtio_net_hdr *)
+- vnet_hdr[1];
+-
+- mpsslog("%s %s %d hdr->flags 0x%x, ",
+- mic->name, __func__, __LINE__,
+- hdr->flags);
+- mpsslog("out_len %d gso_type 0x%x\n",
+- copy.out_len,
+- hdr->gso_type);
+-#endif
+- /* Set the correct output iov_len */
+- iov1[1].iov_len = copy.out_len -
+- sizeof(struct virtio_net_hdr);
+- verify_out_len(mic, &copy);
+-#ifdef DEBUG
+- disp_iovec(mic, copy, __func__,
+- __LINE__);
+- mpsslog("%s %s %d ",
+- mic->name, __func__, __LINE__);
+- mpsslog("read from net 0x%lx\n",
+- sum_iovec_len(copy));
+-#endif
+- len = writev(net_poll[NET_FD_TUN].fd,
+- copy.iov, copy.iovcnt);
+- if (len != sum_iovec_len(&copy)) {
+- mpsslog("Tun write failed %s ",
+- strerror(errno));
+- mpsslog("len 0x%zx ", len);
+- mpsslog("read_len 0x%zx\n",
+- sum_iovec_len(&copy));
+- } else {
+-#ifdef DEBUG
+- disp_iovec(mic, &copy, __func__,
+- __LINE__);
+- mpsslog("%s %s %d ",
+- mic->name, __func__,
+- __LINE__);
+- mpsslog("wrote to tap 0x%lx\n",
+- len);
+-#endif
+- }
+- } else {
+- mpsslog("%s %s %d mic_virtio_copy %s\n",
+- mic->name, __func__, __LINE__,
+- strerror(errno));
+- break;
+- }
+- }
+- }
+- if (net_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
+- mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
+- }
+-done:
+- pthread_exit(NULL);
+-}
+-
+-/* virtio_console */
+-#define VIRTIO_CONSOLE_FD 0
+-#define MONITOR_FD (VIRTIO_CONSOLE_FD + 1)
+-#define MAX_CONSOLE_FD (MONITOR_FD + 1) /* must be the last one + 1 */
+-#define MAX_BUFFER_SIZE PAGE_SIZE
+-
+-static void *
+-virtio_console(void *arg)
+-{
+- static __u8 vcons_buf[2][PAGE_SIZE];
+- struct iovec vcons_iov[2] = {
+- { .iov_base = vcons_buf[0], .iov_len = sizeof(vcons_buf[0]) },
+- { .iov_base = vcons_buf[1], .iov_len = sizeof(vcons_buf[1]) },
+- };
+- struct iovec *iov0 = &vcons_iov[0], *iov1 = &vcons_iov[1];
+- struct mic_info *mic = (struct mic_info *)arg;
+- int err;
+- struct pollfd console_poll[MAX_CONSOLE_FD];
+- int pty_fd;
+- char *pts_name;
+- ssize_t len;
+- struct mic_vring tx_vr, rx_vr;
+- struct mic_copy_desc copy;
+- struct mic_device_desc *desc;
+-
+- pty_fd = posix_openpt(O_RDWR);
+- if (pty_fd < 0) {
+- mpsslog("can't open a pseudoterminal master device: %s\n",
+- strerror(errno));
+- goto _return;
+- }
+- pts_name = ptsname(pty_fd);
+- if (pts_name == NULL) {
+- mpsslog("can't get pts name\n");
+- goto _close_pty;
+- }
+- printf("%s console message goes to %s\n", mic->name, pts_name);
+- mpsslog("%s console message goes to %s\n", mic->name, pts_name);
+- err = grantpt(pty_fd);
+- if (err < 0) {
+- mpsslog("can't grant access: %s %s\n",
+- pts_name, strerror(errno));
+- goto _close_pty;
+- }
+- err = unlockpt(pty_fd);
+- if (err < 0) {
+- mpsslog("can't unlock a pseudoterminal: %s %s\n",
+- pts_name, strerror(errno));
+- goto _close_pty;
+- }
+- console_poll[MONITOR_FD].fd = pty_fd;
+- console_poll[MONITOR_FD].events = POLLIN;
+-
+- console_poll[VIRTIO_CONSOLE_FD].fd = mic->mic_console.virtio_console_fd;
+- console_poll[VIRTIO_CONSOLE_FD].events = POLLIN;
+-
+- if (MAP_FAILED == init_vr(mic, mic->mic_console.virtio_console_fd,
+- VIRTIO_ID_CONSOLE, &tx_vr, &rx_vr,
+- virtcons_dev_page.dd.num_vq)) {
+- mpsslog("%s init_vr failed %s\n",
+- mic->name, strerror(errno));
+- goto _close_pty;
+- }
+-
+- copy.iovcnt = 1;
+- desc = get_device_desc(mic, VIRTIO_ID_CONSOLE);
+-
+- for (;;) {
+- console_poll[MONITOR_FD].revents = 0;
+- console_poll[VIRTIO_CONSOLE_FD].revents = 0;
+- err = poll(console_poll, MAX_CONSOLE_FD, -1);
+- if (err < 0) {
+- mpsslog("%s %d: poll failed: %s\n", __func__, __LINE__,
+- strerror(errno));
+- continue;
+- }
+- if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+- err = wait_for_card_driver(mic,
+- mic->mic_console.virtio_console_fd,
+- VIRTIO_ID_CONSOLE);
+- if (err) {
+- mpsslog("%s %s %d Exiting...\n",
+- mic->name, __func__, __LINE__);
+- break;
+- }
+- }
+-
+- if (console_poll[MONITOR_FD].revents & POLLIN) {
+- copy.iov = iov0;
+- len = readv(pty_fd, copy.iov, copy.iovcnt);
+- if (len > 0) {
+-#ifdef DEBUG
+- disp_iovec(mic, copy, __func__, __LINE__);
+- mpsslog("%s %s %d read from tap 0x%lx\n",
+- mic->name, __func__, __LINE__,
+- len);
+-#endif
+- spin_for_descriptors(mic, &tx_vr);
+- txrx_prepare(VIRTIO_ID_CONSOLE, 1, &tx_vr,
+- &copy, len);
+-
+- err = mic_virtio_copy(mic,
+- mic->mic_console.virtio_console_fd,
+- &tx_vr, &copy);
+- if (err < 0) {
+- mpsslog("%s %s %d mic_virtio_copy %s\n",
+- mic->name, __func__, __LINE__,
+- strerror(errno));
+- }
+- if (!err)
+- verify_out_len(mic, &copy);
+-#ifdef DEBUG
+- disp_iovec(mic, copy, __func__, __LINE__);
+- mpsslog("%s %s %d wrote to net 0x%lx\n",
+- mic->name, __func__, __LINE__,
+- sum_iovec_len(copy));
+-#endif
+- /* Reinitialize IOV for next run */
+- iov0->iov_len = PAGE_SIZE;
+- } else if (len < 0) {
+- disp_iovec(mic, &copy, __func__, __LINE__);
+- mpsslog("%s %s %d read failed %s ",
+- mic->name, __func__, __LINE__,
+- strerror(errno));
+- mpsslog("cnt %d sum %zd\n",
+- copy.iovcnt, sum_iovec_len(&copy));
+- }
+- }
+-
+- if (console_poll[VIRTIO_CONSOLE_FD].revents & POLLIN) {
+- while (rx_vr.info->avail_idx !=
+- le16toh(rx_vr.vr.avail->idx)) {
+- copy.iov = iov1;
+- txrx_prepare(VIRTIO_ID_CONSOLE, 0, &rx_vr,
+- &copy, PAGE_SIZE);
+-
+- err = mic_virtio_copy(mic,
+- mic->mic_console.virtio_console_fd,
+- &rx_vr, &copy);
+- if (!err) {
+- /* Set the correct output iov_len */
+- iov1->iov_len = copy.out_len;
+- verify_out_len(mic, &copy);
+-#ifdef DEBUG
+- disp_iovec(mic, copy, __func__,
+- __LINE__);
+- mpsslog("%s %s %d ",
+- mic->name, __func__, __LINE__);
+- mpsslog("read from net 0x%lx\n",
+- sum_iovec_len(copy));
+-#endif
+- len = writev(pty_fd,
+- copy.iov, copy.iovcnt);
+- if (len != sum_iovec_len(&copy)) {
+- mpsslog("Tun write failed %s ",
+- strerror(errno));
+- mpsslog("len 0x%zx ", len);
+- mpsslog("read_len 0x%zx\n",
+- sum_iovec_len(&copy));
+- } else {
+-#ifdef DEBUG
+- disp_iovec(mic, copy, __func__,
+- __LINE__);
+- mpsslog("%s %s %d ",
+- mic->name, __func__,
+- __LINE__);
+- mpsslog("wrote to tap 0x%lx\n",
+- len);
+-#endif
+- }
+- } else {
+- mpsslog("%s %s %d mic_virtio_copy %s\n",
+- mic->name, __func__, __LINE__,
+- strerror(errno));
+- break;
+- }
+- }
+- }
+- if (console_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
+- mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
+- }
+-_close_pty:
+- close(pty_fd);
+-_return:
+- pthread_exit(NULL);
+-}
+-
+-static void
+-add_virtio_device(struct mic_info *mic, struct mic_device_desc *dd)
+-{
+- char path[PATH_MAX];
+- int fd, err;
+-
+- snprintf(path, PATH_MAX, "/dev/mic%d", mic->id);
+- fd = open(path, O_RDWR);
+- if (fd < 0) {
+- mpsslog("Could not open %s %s\n", path, strerror(errno));
+- return;
+- }
+-
+- err = ioctl(fd, MIC_VIRTIO_ADD_DEVICE, dd);
+- if (err < 0) {
+- mpsslog("Could not add %d %s\n", dd->type, strerror(errno));
+- close(fd);
+- return;
+- }
+- switch (dd->type) {
+- case VIRTIO_ID_NET:
+- mic->mic_net.virtio_net_fd = fd;
+- mpsslog("Added VIRTIO_ID_NET for %s\n", mic->name);
+- break;
+- case VIRTIO_ID_CONSOLE:
+- mic->mic_console.virtio_console_fd = fd;
+- mpsslog("Added VIRTIO_ID_CONSOLE for %s\n", mic->name);
+- break;
+- case VIRTIO_ID_BLOCK:
+- mic->mic_virtblk.virtio_block_fd = fd;
+- mpsslog("Added VIRTIO_ID_BLOCK for %s\n", mic->name);
+- break;
+- }
+-}
+-
+-static bool
+-set_backend_file(struct mic_info *mic)
+-{
+- FILE *config;
+- char buff[PATH_MAX], *line, *evv, *p;
+-
+- snprintf(buff, PATH_MAX, "%s/mpssd%03d.conf", mic_config_dir, mic->id);
+- config = fopen(buff, "r");
+- if (config == NULL)
+- return false;
+- do { /* look for "virtblk_backend=XXXX" */
+- line = fgets(buff, PATH_MAX, config);
+- if (line == NULL)
+- break;
+- if (*line == '#')
+- continue;
+- p = strchr(line, '\n');
+- if (p)
+- *p = '\0';
+- } while (strncmp(line, virtblk_backend, strlen(virtblk_backend)) != 0);
+- fclose(config);
+- if (line == NULL)
+- return false;
+- evv = strchr(line, '=');
+- if (evv == NULL)
+- return false;
+- mic->mic_virtblk.backend_file = malloc(strlen(evv) + 1);
+- if (mic->mic_virtblk.backend_file == NULL) {
+- mpsslog("%s %d can't allocate memory\n", mic->name, mic->id);
+- return false;
+- }
+- strcpy(mic->mic_virtblk.backend_file, evv + 1);
+- return true;
+-}
+-
+-#define SECTOR_SIZE 512
+-static bool
+-set_backend_size(struct mic_info *mic)
+-{
+- mic->mic_virtblk.backend_size = lseek(mic->mic_virtblk.backend, 0,
+- SEEK_END);
+- if (mic->mic_virtblk.backend_size < 0) {
+- mpsslog("%s: can't seek: %s\n",
+- mic->name, mic->mic_virtblk.backend_file);
+- return false;
+- }
+- virtblk_dev_page.blk_config.capacity =
+- mic->mic_virtblk.backend_size / SECTOR_SIZE;
+- if ((mic->mic_virtblk.backend_size % SECTOR_SIZE) != 0)
+- virtblk_dev_page.blk_config.capacity++;
+-
+- virtblk_dev_page.blk_config.capacity =
+- htole64(virtblk_dev_page.blk_config.capacity);
+-
+- return true;
+-}
+-
+-static bool
+-open_backend(struct mic_info *mic)
+-{
+- if (!set_backend_file(mic))
+- goto _error_exit;
+- mic->mic_virtblk.backend = open(mic->mic_virtblk.backend_file, O_RDWR);
+- if (mic->mic_virtblk.backend < 0) {
+- mpsslog("%s: can't open: %s\n", mic->name,
+- mic->mic_virtblk.backend_file);
+- goto _error_free;
+- }
+- if (!set_backend_size(mic))
+- goto _error_close;
+- mic->mic_virtblk.backend_addr = mmap(NULL,
+- mic->mic_virtblk.backend_size,
+- PROT_READ|PROT_WRITE, MAP_SHARED,
+- mic->mic_virtblk.backend, 0L);
+- if (mic->mic_virtblk.backend_addr == MAP_FAILED) {
+- mpsslog("%s: can't map: %s %s\n",
+- mic->name, mic->mic_virtblk.backend_file,
+- strerror(errno));
+- goto _error_close;
+- }
+- return true;
+-
+- _error_close:
+- close(mic->mic_virtblk.backend);
+- _error_free:
+- free(mic->mic_virtblk.backend_file);
+- _error_exit:
+- return false;
+-}
+-
+-static void
+-close_backend(struct mic_info *mic)
+-{
+- munmap(mic->mic_virtblk.backend_addr, mic->mic_virtblk.backend_size);
+- close(mic->mic_virtblk.backend);
+- free(mic->mic_virtblk.backend_file);
+-}
+-
+-static bool
+-start_virtblk(struct mic_info *mic, struct mic_vring *vring)
+-{
+- if (((unsigned long)&virtblk_dev_page.blk_config % 8) != 0) {
+- mpsslog("%s: blk_config is not 8 byte aligned.\n",
+- mic->name);
+- return false;
+- }
+- add_virtio_device(mic, &virtblk_dev_page.dd);
+- if (MAP_FAILED == init_vr(mic, mic->mic_virtblk.virtio_block_fd,
+- VIRTIO_ID_BLOCK, vring, NULL,
+- virtblk_dev_page.dd.num_vq)) {
+- mpsslog("%s init_vr failed %s\n",
+- mic->name, strerror(errno));
+- return false;
+- }
+- return true;
+-}
+-
+-static void
+-stop_virtblk(struct mic_info *mic)
+-{
+- int vr_size, ret;
+-
+- vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES,
+- MIC_VIRTIO_RING_ALIGN) +
+- sizeof(struct _mic_vring_info));
+- ret = munmap(mic->mic_virtblk.block_dp,
+- MIC_DEVICE_PAGE_END + vr_size * virtblk_dev_page.dd.num_vq);
+- if (ret < 0)
+- mpsslog("%s munmap errno %d\n", mic->name, errno);
+- close(mic->mic_virtblk.virtio_block_fd);
+-}
+-
+-static __u8
+-header_error_check(struct vring_desc *desc)
+-{
+- if (le32toh(desc->len) != sizeof(struct virtio_blk_outhdr)) {
+- mpsslog("%s() %d: length is not sizeof(virtio_blk_outhd)\n",
+- __func__, __LINE__);
+- return -EIO;
+- }
+- if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT)) {
+- mpsslog("%s() %d: alone\n",
+- __func__, __LINE__);
+- return -EIO;
+- }
+- if (le16toh(desc->flags) & VRING_DESC_F_WRITE) {
+- mpsslog("%s() %d: not read\n",
+- __func__, __LINE__);
+- return -EIO;
+- }
+- return 0;
+-}
+-
+-static int
+-read_header(int fd, struct virtio_blk_outhdr *hdr, __u32 desc_idx)
+-{
+- struct iovec iovec;
+- struct mic_copy_desc copy;
+-
+- iovec.iov_len = sizeof(*hdr);
+- iovec.iov_base = hdr;
+- copy.iov = &iovec;
+- copy.iovcnt = 1;
+- copy.vr_idx = 0; /* only one vring on virtio_block */
+- copy.update_used = false; /* do not update used index */
+- return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
+-}
+-
+-static int
+-transfer_blocks(int fd, struct iovec *iovec, __u32 iovcnt)
+-{
+- struct mic_copy_desc copy;
+-
+- copy.iov = iovec;
+- copy.iovcnt = iovcnt;
+- copy.vr_idx = 0; /* only one vring on virtio_block */
+- copy.update_used = false; /* do not update used index */
+- return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
+-}
+-
+-static __u8
+-status_error_check(struct vring_desc *desc)
+-{
+- if (le32toh(desc->len) != sizeof(__u8)) {
+- mpsslog("%s() %d: length is not sizeof(status)\n",
+- __func__, __LINE__);
+- return -EIO;
+- }
+- return 0;
+-}
+-
+-static int
+-write_status(int fd, __u8 *status)
+-{
+- struct iovec iovec;
+- struct mic_copy_desc copy;
+-
+- iovec.iov_base = status;
+- iovec.iov_len = sizeof(*status);
+- copy.iov = &iovec;
+- copy.iovcnt = 1;
+- copy.vr_idx = 0; /* only one vring on virtio_block */
+- copy.update_used = true; /* Update used index */
+- return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
+-}
+-
+-#ifndef VIRTIO_BLK_T_GET_ID
+-#define VIRTIO_BLK_T_GET_ID 8
+-#endif
+-
+-static void *
+-virtio_block(void *arg)
+-{
+- struct mic_info *mic = (struct mic_info *)arg;
+- int ret;
+- struct pollfd block_poll;
+- struct mic_vring vring;
+- __u16 avail_idx;
+- __u32 desc_idx;
+- struct vring_desc *desc;
+- struct iovec *iovec, *piov;
+- __u8 status;
+- __u32 buffer_desc_idx;
+- struct virtio_blk_outhdr hdr;
+- void *fos;
+-
+- for (;;) { /* forever */
+- if (!open_backend(mic)) { /* No virtblk */
+- for (mic->mic_virtblk.signaled = 0;
+- !mic->mic_virtblk.signaled;)
+- sleep(1);
+- continue;
+- }
+-
+- /* backend file is specified. */
+- if (!start_virtblk(mic, &vring))
+- goto _close_backend;
+- iovec = malloc(sizeof(*iovec) *
+- le32toh(virtblk_dev_page.blk_config.seg_max));
+- if (!iovec) {
+- mpsslog("%s: can't alloc iovec: %s\n",
+- mic->name, strerror(ENOMEM));
+- goto _stop_virtblk;
+- }
+-
+- block_poll.fd = mic->mic_virtblk.virtio_block_fd;
+- block_poll.events = POLLIN;
+- for (mic->mic_virtblk.signaled = 0;
+- !mic->mic_virtblk.signaled;) {
+- block_poll.revents = 0;
+- /* timeout in 1 sec to see signaled */
+- ret = poll(&block_poll, 1, 1000);
+- if (ret < 0) {
+- mpsslog("%s %d: poll failed: %s\n",
+- __func__, __LINE__,
+- strerror(errno));
+- continue;
+- }
+-
+- if (!(block_poll.revents & POLLIN)) {
+-#ifdef DEBUG
+- mpsslog("%s %d: block_poll.revents=0x%x\n",
+- __func__, __LINE__, block_poll.revents);
+-#endif
+- continue;
+- }
+-
+- /* POLLIN */
+- while (vring.info->avail_idx !=
+- le16toh(vring.vr.avail->idx)) {
+- /* read header element */
+- avail_idx =
+- vring.info->avail_idx &
+- (vring.vr.num - 1);
+- desc_idx = le16toh(
+- vring.vr.avail->ring[avail_idx]);
+- desc = &vring.vr.desc[desc_idx];
+-#ifdef DEBUG
+- mpsslog("%s() %d: avail_idx=%d ",
+- __func__, __LINE__,
+- vring.info->avail_idx);
+- mpsslog("vring.vr.num=%d desc=%p\n",
+- vring.vr.num, desc);
+-#endif
+- status = header_error_check(desc);
+- ret = read_header(
+- mic->mic_virtblk.virtio_block_fd,
+- &hdr, desc_idx);
+- if (ret < 0) {
+- mpsslog("%s() %d %s: ret=%d %s\n",
+- __func__, __LINE__,
+- mic->name, ret,
+- strerror(errno));
+- break;
+- }
+- /* buffer element */
+- piov = iovec;
+- status = 0;
+- fos = mic->mic_virtblk.backend_addr +
+- (hdr.sector * SECTOR_SIZE);
+- buffer_desc_idx = next_desc(desc);
+- desc_idx = buffer_desc_idx;
+- for (desc = &vring.vr.desc[buffer_desc_idx];
+- desc->flags & VRING_DESC_F_NEXT;
+- desc_idx = next_desc(desc),
+- desc = &vring.vr.desc[desc_idx]) {
+- piov->iov_len = desc->len;
+- piov->iov_base = fos;
+- piov++;
+- fos += desc->len;
+- }
+- /* Returning NULLs for VIRTIO_BLK_T_GET_ID. */
+- if (hdr.type & ~(VIRTIO_BLK_T_OUT |
+- VIRTIO_BLK_T_GET_ID)) {
+- /*
+- VIRTIO_BLK_T_IN - does not do
+- anything. Probably for documenting.
+- VIRTIO_BLK_T_SCSI_CMD - for
+- virtio_scsi.
+- VIRTIO_BLK_T_FLUSH - turned off in
+- config space.
+- VIRTIO_BLK_T_BARRIER - defined but not
+- used in anywhere.
+- */
+- mpsslog("%s() %d: type %x ",
+- __func__, __LINE__,
+- hdr.type);
+- mpsslog("is not supported\n");
+- status = -ENOTSUP;
+-
+- } else {
+- ret = transfer_blocks(
+- mic->mic_virtblk.virtio_block_fd,
+- iovec,
+- piov - iovec);
+- if (ret < 0 &&
+- status != 0)
+- status = ret;
+- }
+- /* write status and update used pointer */
+- if (status != 0)
+- status = status_error_check(desc);
+- ret = write_status(
+- mic->mic_virtblk.virtio_block_fd,
+- &status);
+-#ifdef DEBUG
+- mpsslog("%s() %d: write status=%d on desc=%p\n",
+- __func__, __LINE__,
+- status, desc);
+-#endif
+- }
+- }
+- free(iovec);
+-_stop_virtblk:
+- stop_virtblk(mic);
+-_close_backend:
+- close_backend(mic);
+- } /* forever */
+-
+- pthread_exit(NULL);
+-}
+-
+-static void
+-reset(struct mic_info *mic)
+-{
+-#define RESET_TIMEOUT 120
+- int i = RESET_TIMEOUT;
+- setsysfs(mic->name, "state", "reset");
+- while (i) {
+- char *state;
+- state = readsysfs(mic->name, "state");
+- if (!state)
+- goto retry;
+- mpsslog("%s: %s %d state %s\n",
+- mic->name, __func__, __LINE__, state);
+-
+- if (!strcmp(state, "ready")) {
+- free(state);
+- break;
+- }
+- free(state);
+-retry:
+- sleep(1);
+- i--;
+- }
+-}
+-
+-static int
+-get_mic_shutdown_status(struct mic_info *mic, char *shutdown_status)
+-{
+- if (!strcmp(shutdown_status, "nop"))
+- return MIC_NOP;
+- if (!strcmp(shutdown_status, "crashed"))
+- return MIC_CRASHED;
+- if (!strcmp(shutdown_status, "halted"))
+- return MIC_HALTED;
+- if (!strcmp(shutdown_status, "poweroff"))
+- return MIC_POWER_OFF;
+- if (!strcmp(shutdown_status, "restart"))
+- return MIC_RESTART;
+- mpsslog("%s: BUG invalid status %s\n", mic->name, shutdown_status);
+- /* Invalid state */
+- assert(0);
+-};
+-
+-static int get_mic_state(struct mic_info *mic)
+-{
+- char *state = NULL;
+- enum mic_states mic_state;
+-
+- while (!state) {
+- state = readsysfs(mic->name, "state");
+- sleep(1);
+- }
+- mpsslog("%s: %s %d state %s\n",
+- mic->name, __func__, __LINE__, state);
+-
+- if (!strcmp(state, "ready")) {
+- mic_state = MIC_READY;
+- } else if (!strcmp(state, "booting")) {
+- mic_state = MIC_BOOTING;
+- } else if (!strcmp(state, "online")) {
+- mic_state = MIC_ONLINE;
+- } else if (!strcmp(state, "shutting_down")) {
+- mic_state = MIC_SHUTTING_DOWN;
+- } else if (!strcmp(state, "reset_failed")) {
+- mic_state = MIC_RESET_FAILED;
+- } else if (!strcmp(state, "resetting")) {
+- mic_state = MIC_RESETTING;
+- } else {
+- mpsslog("%s: BUG invalid state %s\n", mic->name, state);
+- assert(0);
+- }
+-
+- free(state);
+- return mic_state;
+-};
+-
+-static void mic_handle_shutdown(struct mic_info *mic)
+-{
+-#define SHUTDOWN_TIMEOUT 60
+- int i = SHUTDOWN_TIMEOUT;
+- char *shutdown_status;
+- while (i) {
+- shutdown_status = readsysfs(mic->name, "shutdown_status");
+- if (!shutdown_status) {
+- sleep(1);
+- continue;
+- }
+- mpsslog("%s: %s %d shutdown_status %s\n",
+- mic->name, __func__, __LINE__, shutdown_status);
+- switch (get_mic_shutdown_status(mic, shutdown_status)) {
+- case MIC_RESTART:
+- mic->restart = 1;
+- case MIC_HALTED:
+- case MIC_POWER_OFF:
+- case MIC_CRASHED:
+- free(shutdown_status);
+- goto reset;
+- default:
+- break;
+- }
+- free(shutdown_status);
+- sleep(1);
+- i--;
+- }
+-reset:
+- if (!i)
+- mpsslog("%s: %s %d timing out waiting for shutdown_status %s\n",
+- mic->name, __func__, __LINE__, shutdown_status);
+- reset(mic);
+-}
+-
+-static int open_state_fd(struct mic_info *mic)
+-{
+- char pathname[PATH_MAX];
+- int fd;
+-
+- snprintf(pathname, PATH_MAX - 1, "%s/%s/%s",
+- MICSYSFSDIR, mic->name, "state");
+-
+- fd = open(pathname, O_RDONLY);
+- if (fd < 0)
+- mpsslog("%s: opening file %s failed %s\n",
+- mic->name, pathname, strerror(errno));
+- return fd;
+-}
+-
+-static int block_till_state_change(int fd, struct mic_info *mic)
+-{
+- struct pollfd ufds[1];
+- char value[PAGE_SIZE];
+- int ret;
+-
+- ufds[0].fd = fd;
+- ufds[0].events = POLLERR | POLLPRI;
+- ret = poll(ufds, 1, -1);
+- if (ret < 0) {
+- mpsslog("%s: %s %d poll failed %s\n",
+- mic->name, __func__, __LINE__, strerror(errno));
+- return ret;
+- }
+-
+- ret = lseek(fd, 0, SEEK_SET);
+- if (ret < 0) {
+- mpsslog("%s: %s %d Failed to seek to 0: %s\n",
+- mic->name, __func__, __LINE__, strerror(errno));
+- return ret;
+- }
+-
+- ret = read(fd, value, sizeof(value));
+- if (ret < 0) {
+- mpsslog("%s: %s %d Failed to read sysfs entry: %s\n",
+- mic->name, __func__, __LINE__, strerror(errno));
+- return ret;
+- }
+-
+- return 0;
+-}
+-
+-static void *
+-mic_config(void *arg)
+-{
+- struct mic_info *mic = (struct mic_info *)arg;
+- int fd, ret, stat = 0;
+-
+- fd = open_state_fd(mic);
+- if (fd < 0) {
+- mpsslog("%s: %s %d open state fd failed %s\n",
+- mic->name, __func__, __LINE__, strerror(errno));
+- goto exit;
+- }
+-
+- do {
+- ret = block_till_state_change(fd, mic);
+- if (ret < 0) {
+- mpsslog("%s: %s %d block_till_state_change error %s\n",
+- mic->name, __func__, __LINE__, strerror(errno));
+- goto close_exit;
+- }
+-
+- switch (get_mic_state(mic)) {
+- case MIC_SHUTTING_DOWN:
+- mic_handle_shutdown(mic);
+- break;
+- case MIC_READY:
+- case MIC_RESET_FAILED:
+- ret = kill(mic->pid, SIGTERM);
+- mpsslog("%s: %s %d kill pid %d ret %d\n",
+- mic->name, __func__, __LINE__,
+- mic->pid, ret);
+- if (!ret) {
+- ret = waitpid(mic->pid, &stat,
+- WIFSIGNALED(stat));
+- mpsslog("%s: %s %d waitpid ret %d pid %d\n",
+- mic->name, __func__, __LINE__,
+- ret, mic->pid);
+- }
+- if (mic->boot_on_resume) {
+- setsysfs(mic->name, "state", "boot");
+- mic->boot_on_resume = 0;
+- }
+- goto close_exit;
+- default:
+- break;
+- }
+- } while (1);
+-
+-close_exit:
+- close(fd);
+-exit:
+- init_mic(mic);
+- pthread_exit(NULL);
+-}
+-
+-static void
+-set_cmdline(struct mic_info *mic)
+-{
+- char buffer[PATH_MAX];
+- int len;
+-
+- len = snprintf(buffer, PATH_MAX,
+- "clocksource=tsc highres=off nohz=off ");
+- len += snprintf(buffer + len, PATH_MAX - len,
+- "cpufreq_on;corec6_off;pc3_off;pc6_off ");
+- len += snprintf(buffer + len, PATH_MAX - len,
+- "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0",
+- mic->id + 1);
+-
+- setsysfs(mic->name, "cmdline", buffer);
+- mpsslog("%s: Command line: \"%s\"\n", mic->name, buffer);
+- snprintf(buffer, PATH_MAX, "172.31.%d.1", mic->id + 1);
+- mpsslog("%s: IPADDR: \"%s\"\n", mic->name, buffer);
+-}
+-
+-static void
+-set_log_buf_info(struct mic_info *mic)
+-{
+- int fd;
+- off_t len;
+- char system_map[] = "/lib/firmware/mic/System.map";
+- char *map, *temp, log_buf[17] = {'\0'};
+-
+- fd = open(system_map, O_RDONLY);
+- if (fd < 0) {
+- mpsslog("%s: Opening System.map failed: %d\n",
+- mic->name, errno);
+- return;
+- }
+- len = lseek(fd, 0, SEEK_END);
+- if (len < 0) {
+- mpsslog("%s: Reading System.map size failed: %d\n",
+- mic->name, errno);
+- close(fd);
+- return;
+- }
+- map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+- if (map == MAP_FAILED) {
+- mpsslog("%s: mmap of System.map failed: %d\n",
+- mic->name, errno);
+- close(fd);
+- return;
+- }
+- temp = strstr(map, "__log_buf");
+- if (!temp) {
+- mpsslog("%s: __log_buf not found: %d\n", mic->name, errno);
+- munmap(map, len);
+- close(fd);
+- return;
+- }
+- strncpy(log_buf, temp - 19, 16);
+- setsysfs(mic->name, "log_buf_addr", log_buf);
+- mpsslog("%s: log_buf_addr: %s\n", mic->name, log_buf);
+- temp = strstr(map, "log_buf_len");
+- if (!temp) {
+- mpsslog("%s: log_buf_len not found: %d\n", mic->name, errno);
+- munmap(map, len);
+- close(fd);
+- return;
+- }
+- strncpy(log_buf, temp - 19, 16);
+- setsysfs(mic->name, "log_buf_len", log_buf);
+- mpsslog("%s: log_buf_len: %s\n", mic->name, log_buf);
+- munmap(map, len);
+- close(fd);
+-}
+-
+-static void
+-change_virtblk_backend(int x, siginfo_t *siginfo, void *p)
+-{
+- struct mic_info *mic;
+-
+- for (mic = mic_list.next; mic != NULL; mic = mic->next)
+- mic->mic_virtblk.signaled = 1/* true */;
+-}
+-
+-static void
+-set_mic_boot_params(struct mic_info *mic)
+-{
+- set_log_buf_info(mic);
+- set_cmdline(mic);
+-}
+-
+-static void *
+-init_mic(void *arg)
+-{
+- struct mic_info *mic = (struct mic_info *)arg;
+- struct sigaction ignore = {
+- .sa_flags = 0,
+- .sa_handler = SIG_IGN
+- };
+- struct sigaction act = {
+- .sa_flags = SA_SIGINFO,
+- .sa_sigaction = change_virtblk_backend,
+- };
+- char buffer[PATH_MAX];
+- int err, fd;
+-
+- /*
+- * Currently, one virtio block device is supported for each MIC card
+- * at a time. Any user (or test) can send a SIGUSR1 to the MIC daemon.
+- * The signal informs the virtio block backend about a change in the
+- * configuration file which specifies the virtio backend file name on
+- * the host. Virtio block backend then re-reads the configuration file
+- * and switches to the new block device. This signalling mechanism may
+- * not be required once multiple virtio block devices are supported by
+- * the MIC daemon.
+- */
+- sigaction(SIGUSR1, &ignore, NULL);
+-retry:
+- fd = open_state_fd(mic);
+- if (fd < 0) {
+- mpsslog("%s: %s %d open state fd failed %s\n",
+- mic->name, __func__, __LINE__, strerror(errno));
+- sleep(2);
+- goto retry;
+- }
+-
+- if (mic->restart) {
+- snprintf(buffer, PATH_MAX, "boot");
+- setsysfs(mic->name, "state", buffer);
+- mpsslog("%s restarting mic %d\n",
+- mic->name, mic->restart);
+- mic->restart = 0;
+- }
+-
+- while (1) {
+- while (block_till_state_change(fd, mic)) {
+- mpsslog("%s: %s %d block_till_state_change error %s\n",
+- mic->name, __func__, __LINE__, strerror(errno));
+- sleep(2);
+- continue;
+- }
+-
+- if (get_mic_state(mic) == MIC_BOOTING)
+- break;
+- }
+-
+- mic->pid = fork();
+- switch (mic->pid) {
+- case 0:
+- add_virtio_device(mic, &virtcons_dev_page.dd);
+- add_virtio_device(mic, &virtnet_dev_page.dd);
+- err = pthread_create(&mic->mic_console.console_thread, NULL,
+- virtio_console, mic);
+- if (err)
+- mpsslog("%s virtcons pthread_create failed %s\n",
+- mic->name, strerror(err));
+- err = pthread_create(&mic->mic_net.net_thread, NULL,
+- virtio_net, mic);
+- if (err)
+- mpsslog("%s virtnet pthread_create failed %s\n",
+- mic->name, strerror(err));
+- err = pthread_create(&mic->mic_virtblk.block_thread, NULL,
+- virtio_block, mic);
+- if (err)
+- mpsslog("%s virtblk pthread_create failed %s\n",
+- mic->name, strerror(err));
+- sigemptyset(&act.sa_mask);
+- err = sigaction(SIGUSR1, &act, NULL);
+- if (err)
+- mpsslog("%s sigaction SIGUSR1 failed %s\n",
+- mic->name, strerror(errno));
+- while (1)
+- sleep(60);
+- case -1:
+- mpsslog("fork failed MIC name %s id %d errno %d\n",
+- mic->name, mic->id, errno);
+- break;
+- default:
+- err = pthread_create(&mic->config_thread, NULL,
+- mic_config, mic);
+- if (err)
+- mpsslog("%s mic_config pthread_create failed %s\n",
+- mic->name, strerror(err));
+- }
+-
+- return NULL;
+-}
+-
+-static void
+-start_daemon(void)
+-{
+- struct mic_info *mic;
+- int err;
+-
+- for (mic = mic_list.next; mic; mic = mic->next) {
+- set_mic_boot_params(mic);
+- err = pthread_create(&mic->init_thread, NULL, init_mic, mic);
+- if (err)
+- mpsslog("%s init_mic pthread_create failed %s\n",
+- mic->name, strerror(err));
+- }
+-
+- while (1)
+- sleep(60);
+-}
+-
+-static int
+-init_mic_list(void)
+-{
+- struct mic_info *mic = &mic_list;
+- struct dirent *file;
+- DIR *dp;
+- int cnt = 0;
+-
+- dp = opendir(MICSYSFSDIR);
+- if (!dp)
+- return 0;
+-
+- while ((file = readdir(dp)) != NULL) {
+- if (!strncmp(file->d_name, "mic", 3)) {
+- mic->next = calloc(1, sizeof(struct mic_info));
+- if (mic->next) {
+- mic = mic->next;
+- mic->id = atoi(&file->d_name[3]);
+- mic->name = malloc(strlen(file->d_name) + 16);
+- if (mic->name)
+- strcpy(mic->name, file->d_name);
+- mpsslog("MIC name %s id %d\n", mic->name,
+- mic->id);
+- cnt++;
+- }
+- }
+- }
+-
+- closedir(dp);
+- return cnt;
+-}
+-
+-void
+-mpsslog(char *format, ...)
+-{
+- va_list args;
+- char buffer[4096];
+- char ts[52], *ts1;
+- time_t t;
+-
+- if (logfp == NULL)
+- return;
+-
+- va_start(args, format);
+- vsprintf(buffer, format, args);
+- va_end(args);
+-
+- time(&t);
+- ts1 = ctime_r(&t, ts);
+- ts1[strlen(ts1) - 1] = '\0';
+- fprintf(logfp, "%s: %s", ts1, buffer);
+-
+- fflush(logfp);
+-}
+-
+-int
+-main(int argc, char *argv[])
+-{
+- int cnt;
+- pid_t pid;
+-
+- myname = argv[0];
+-
+- logfp = fopen(LOGFILE_NAME, "a+");
+- if (!logfp) {
+- fprintf(stderr, "cannot open logfile '%s'\n", LOGFILE_NAME);
+- exit(1);
+- }
+- pid = fork();
+- switch (pid) {
+- case 0:
+- break;
+- case -1:
+- exit(2);
+- default:
+- exit(0);
+- }
+-
+- mpsslog("MIC Daemon start\n");
+-
+- cnt = init_mic_list();
+- if (cnt == 0) {
+- mpsslog("MIC module not loaded\n");
+- exit(3);
+- }
+- mpsslog("MIC found %d devices\n", cnt);
+-
+- start_daemon();
+-
+- exit(0);
+-}
+diff --git a/Documentation/mic/mpssd/mpssd.h b/Documentation/mic/mpssd/mpssd.h
+deleted file mode 100644
+index 8bd64944aacc..000000000000
+--- a/Documentation/mic/mpssd/mpssd.h
++++ /dev/null
+@@ -1,103 +0,0 @@
+-/*
+- * Intel MIC Platform Software Stack (MPSS)
+- *
+- * Copyright(c) 2013 Intel Corporation.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License, version 2, as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * General Public License for more details.
+- *
+- * The full GNU General Public License is included in this distribution in
+- * the file called "COPYING".
+- *
+- * Intel MIC User Space Tools.
+- */
+-#ifndef _MPSSD_H_
+-#define _MPSSD_H_
+-
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <string.h>
+-#include <fcntl.h>
+-#include <unistd.h>
+-#include <dirent.h>
+-#include <libgen.h>
+-#include <pthread.h>
+-#include <stdarg.h>
+-#include <time.h>
+-#include <errno.h>
+-#include <sys/dir.h>
+-#include <sys/ioctl.h>
+-#include <sys/poll.h>
+-#include <sys/types.h>
+-#include <sys/socket.h>
+-#include <sys/stat.h>
+-#include <sys/types.h>
+-#include <sys/mman.h>
+-#include <sys/utsname.h>
+-#include <sys/wait.h>
+-#include <netinet/in.h>
+-#include <arpa/inet.h>
+-#include <netdb.h>
+-#include <pthread.h>
+-#include <signal.h>
+-#include <limits.h>
+-#include <syslog.h>
+-#include <getopt.h>
+-#include <net/if.h>
+-#include <linux/if_tun.h>
+-#include <linux/if_tun.h>
+-#include <linux/virtio_ids.h>
+-
+-#define MICSYSFSDIR "/sys/class/mic"
+-#define LOGFILE_NAME "/var/log/mpssd"
+-#define PAGE_SIZE 4096
+-
+-struct mic_console_info {
+- pthread_t console_thread;
+- int virtio_console_fd;
+- void *console_dp;
+-};
+-
+-struct mic_net_info {
+- pthread_t net_thread;
+- int virtio_net_fd;
+- int tap_fd;
+- void *net_dp;
+-};
+-
+-struct mic_virtblk_info {
+- pthread_t block_thread;
+- int virtio_block_fd;
+- void *block_dp;
+- volatile sig_atomic_t signaled;
+- char *backend_file;
+- int backend;
+- void *backend_addr;
+- long backend_size;
+-};
+-
+-struct mic_info {
+- int id;
+- char *name;
+- pthread_t config_thread;
+- pthread_t init_thread;
+- pid_t pid;
+- struct mic_console_info mic_console;
+- struct mic_net_info mic_net;
+- struct mic_virtblk_info mic_virtblk;
+- int restart;
+- int boot_on_resume;
+- struct mic_info *next;
+-};
+-
+-__attribute__((format(printf, 1, 2)))
+-void mpsslog(char *format, ...);
+-char *readsysfs(char *dir, char *entry);
+-int setsysfs(char *dir, char *entry, char *value);
+-#endif
+diff --git a/Documentation/mic/mpssd/sysfs.c b/Documentation/mic/mpssd/sysfs.c
+deleted file mode 100644
+index 8dd326936083..000000000000
+--- a/Documentation/mic/mpssd/sysfs.c
++++ /dev/null
+@@ -1,102 +0,0 @@
+-/*
+- * Intel MIC Platform Software Stack (MPSS)
+- *
+- * Copyright(c) 2013 Intel Corporation.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License, version 2, as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * General Public License for more details.
+- *
+- * The full GNU General Public License is included in this distribution in
+- * the file called "COPYING".
+- *
+- * Intel MIC User Space Tools.
+- */
+-
+-#include "mpssd.h"
+-
+-#define PAGE_SIZE 4096
+-
+-char *
+-readsysfs(char *dir, char *entry)
+-{
+- char filename[PATH_MAX];
+- char value[PAGE_SIZE];
+- char *string = NULL;
+- int fd;
+- int len;
+-
+- if (dir == NULL)
+- snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry);
+- else
+- snprintf(filename, PATH_MAX,
+- "%s/%s/%s", MICSYSFSDIR, dir, entry);
+-
+- fd = open(filename, O_RDONLY);
+- if (fd < 0) {
+- mpsslog("Failed to open sysfs entry '%s': %s\n",
+- filename, strerror(errno));
+- return NULL;
+- }
+-
+- len = read(fd, value, sizeof(value));
+- if (len < 0) {
+- mpsslog("Failed to read sysfs entry '%s': %s\n",
+- filename, strerror(errno));
+- goto readsys_ret;
+- }
+- if (len == 0)
+- goto readsys_ret;
+-
+- value[len - 1] = '\0';
+-
+- string = malloc(strlen(value) + 1);
+- if (string)
+- strcpy(string, value);
+-
+-readsys_ret:
+- close(fd);
+- return string;
+-}
+-
+-int
+-setsysfs(char *dir, char *entry, char *value)
+-{
+- char filename[PATH_MAX];
+- char *oldvalue;
+- int fd, ret = 0;
+-
+- if (dir == NULL)
+- snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry);
+- else
+- snprintf(filename, PATH_MAX, "%s/%s/%s",
+- MICSYSFSDIR, dir, entry);
+-
+- oldvalue = readsysfs(dir, entry);
+-
+- fd = open(filename, O_RDWR);
+- if (fd < 0) {
+- ret = errno;
+- mpsslog("Failed to open sysfs entry '%s': %s\n",
+- filename, strerror(errno));
+- goto done;
+- }
+-
+- if (!oldvalue || strcmp(value, oldvalue)) {
+- if (write(fd, value, strlen(value)) < 0) {
+- ret = errno;
+- mpsslog("Failed to write new sysfs entry '%s': %s\n",
+- filename, strerror(errno));
+- }
+- }
+- close(fd);
+-done:
+- if (oldvalue)
+- free(oldvalue);
+- return ret;
+-}
+diff --git a/Makefile b/Makefile
+index 671e183bd507..10aec937e9e4 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ VERSION = 4
+ PATCHLEVEL = 4
+-SUBLEVEL = 52
++SUBLEVEL = 53
+ EXTRAVERSION =
+ NAME = Blurry Fish Butt
+
+diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
+index e74df327cdd3..20618a897c99 100644
+--- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts
++++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
+@@ -122,6 +122,8 @@
+ uart1: serial@f8020000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1_default>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
+ status = "okay";
+ };
+
+diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
+index da84e65b56ef..e27024cdf48b 100644
+--- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts
++++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
+@@ -110,6 +110,8 @@
+ };
+
+ usart3: serial@fc00c000 {
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
+ status = "okay";
+ };
+
+diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
+index 405aa1883307..23d5cad56ddc 100644
+--- a/arch/arm/include/asm/kvm_mmu.h
++++ b/arch/arm/include/asm/kvm_mmu.h
+@@ -204,18 +204,12 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
+ * and iterate over the range.
+ */
+
+- bool need_flush = !vcpu_has_cache_enabled(vcpu) || ipa_uncached;
+-
+ VM_BUG_ON(size & ~PAGE_MASK);
+
+- if (!need_flush && !icache_is_pipt())
+- goto vipt_cache;
+-
+ while (size) {
+ void *va = kmap_atomic_pfn(pfn);
+
+- if (need_flush)
+- kvm_flush_dcache_to_poc(va, PAGE_SIZE);
++ kvm_flush_dcache_to_poc(va, PAGE_SIZE);
+
+ if (icache_is_pipt())
+ __cpuc_coherent_user_range((unsigned long)va,
+@@ -227,7 +221,6 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
+ kunmap_atomic(va);
+ }
+
+-vipt_cache:
+ if (!icache_is_pipt() && !icache_is_vivt_asid_tagged()) {
+ /* any kind of VIPT cache */
+ __flush_icache_all();
+diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
+index 61505676d085..819b21a9851c 100644
+--- a/arch/arm64/include/asm/kvm_mmu.h
++++ b/arch/arm64/include/asm/kvm_mmu.h
+@@ -236,8 +236,7 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
+ {
+ void *va = page_address(pfn_to_page(pfn));
+
+- if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached)
+- kvm_flush_dcache_to_poc(va, size);
++ kvm_flush_dcache_to_poc(va, size);
+
+ if (!icache_is_aliasing()) { /* PIPT */
+ flush_icache_range((unsigned long)va,
+diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c
+index 52caa75bfe4e..e2f50d690624 100644
+--- a/arch/mips/bcm47xx/buttons.c
++++ b/arch/mips/bcm47xx/buttons.c
+@@ -17,6 +17,12 @@
+ .active_low = 1, \
+ }
+
++#define BCM47XX_GPIO_KEY_H(_gpio, _code) \
++ { \
++ .code = _code, \
++ .gpio = _gpio, \
++ }
++
+ /* Asus */
+
+ static const struct gpio_keys_button
+@@ -79,8 +85,8 @@ bcm47xx_buttons_asus_wl500gpv2[] __initconst = {
+
+ static const struct gpio_keys_button
+ bcm47xx_buttons_asus_wl500w[] __initconst = {
+- BCM47XX_GPIO_KEY(6, KEY_RESTART),
+- BCM47XX_GPIO_KEY(7, KEY_WPS_BUTTON),
++ BCM47XX_GPIO_KEY_H(6, KEY_RESTART),
++ BCM47XX_GPIO_KEY_H(7, KEY_WPS_BUTTON),
+ };
+
+ static const struct gpio_keys_button
+diff --git a/arch/mips/cavium-octeon/octeon-memcpy.S b/arch/mips/cavium-octeon/octeon-memcpy.S
+index 64e08df51d65..8b7004132491 100644
+--- a/arch/mips/cavium-octeon/octeon-memcpy.S
++++ b/arch/mips/cavium-octeon/octeon-memcpy.S
+@@ -208,18 +208,18 @@ EXC( STORE t2, UNIT(6)(dst), s_exc_p10u)
+ ADD src, src, 16*NBYTES
+ EXC( STORE t3, UNIT(7)(dst), s_exc_p9u)
+ ADD dst, dst, 16*NBYTES
+-EXC( LOAD t0, UNIT(-8)(src), l_exc_copy)
+-EXC( LOAD t1, UNIT(-7)(src), l_exc_copy)
+-EXC( LOAD t2, UNIT(-6)(src), l_exc_copy)
+-EXC( LOAD t3, UNIT(-5)(src), l_exc_copy)
++EXC( LOAD t0, UNIT(-8)(src), l_exc_copy_rewind16)
++EXC( LOAD t1, UNIT(-7)(src), l_exc_copy_rewind16)
++EXC( LOAD t2, UNIT(-6)(src), l_exc_copy_rewind16)
++EXC( LOAD t3, UNIT(-5)(src), l_exc_copy_rewind16)
+ EXC( STORE t0, UNIT(-8)(dst), s_exc_p8u)
+ EXC( STORE t1, UNIT(-7)(dst), s_exc_p7u)
+ EXC( STORE t2, UNIT(-6)(dst), s_exc_p6u)
+ EXC( STORE t3, UNIT(-5)(dst), s_exc_p5u)
+-EXC( LOAD t0, UNIT(-4)(src), l_exc_copy)
+-EXC( LOAD t1, UNIT(-3)(src), l_exc_copy)
+-EXC( LOAD t2, UNIT(-2)(src), l_exc_copy)
+-EXC( LOAD t3, UNIT(-1)(src), l_exc_copy)
++EXC( LOAD t0, UNIT(-4)(src), l_exc_copy_rewind16)
++EXC( LOAD t1, UNIT(-3)(src), l_exc_copy_rewind16)
++EXC( LOAD t2, UNIT(-2)(src), l_exc_copy_rewind16)
++EXC( LOAD t3, UNIT(-1)(src), l_exc_copy_rewind16)
+ EXC( STORE t0, UNIT(-4)(dst), s_exc_p4u)
+ EXC( STORE t1, UNIT(-3)(dst), s_exc_p3u)
+ EXC( STORE t2, UNIT(-2)(dst), s_exc_p2u)
+@@ -383,6 +383,10 @@ done:
+ nop
+ END(memcpy)
+
++l_exc_copy_rewind16:
++ /* Rewind src and dst by 16*NBYTES for l_exc_copy */
++ SUB src, src, 16*NBYTES
++ SUB dst, dst, 16*NBYTES
+ l_exc_copy:
+ /*
+ * Copy bytes from src until faulting load address (or until a
+diff --git a/arch/mips/include/asm/checksum.h b/arch/mips/include/asm/checksum.h
+index 3ceacde5eb6e..17f89f9670b2 100644
+--- a/arch/mips/include/asm/checksum.h
++++ b/arch/mips/include/asm/checksum.h
+@@ -186,7 +186,9 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr,
+ " daddu %0, %4 \n"
+ " dsll32 $1, %0, 0 \n"
+ " daddu %0, $1 \n"
++ " sltu $1, %0, $1 \n"
+ " dsra32 %0, %0, 0 \n"
++ " addu %0, $1 \n"
+ #endif
+ " .set pop"
+ : "=r" (sum)
+diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
+index 44a6f25e902e..fc537d1b649d 100644
+--- a/arch/mips/kernel/process.c
++++ b/arch/mips/kernel/process.c
+@@ -191,11 +191,9 @@ struct mips_frame_info {
+ #define J_TARGET(pc,target) \
+ (((unsigned long)(pc) & 0xf0000000) | ((target) << 2))
+
+-static inline int is_ra_save_ins(union mips_instruction *ip)
++static inline int is_ra_save_ins(union mips_instruction *ip, int *poff)
+ {
+ #ifdef CONFIG_CPU_MICROMIPS
+- union mips_instruction mmi;
+-
+ /*
+ * swsp ra,offset
+ * swm16 reglist,offset(sp)
+@@ -205,29 +203,71 @@ static inline int is_ra_save_ins(union mips_instruction *ip)
+ *
+ * microMIPS is way more fun...
+ */
+- if (mm_insn_16bit(ip->halfword[0])) {
+- mmi.word = (ip->halfword[0] << 16);
+- return (mmi.mm16_r5_format.opcode == mm_swsp16_op &&
+- mmi.mm16_r5_format.rt == 31) ||
+- (mmi.mm16_m_format.opcode == mm_pool16c_op &&
+- mmi.mm16_m_format.func == mm_swm16_op);
++ if (mm_insn_16bit(ip->halfword[1])) {
++ switch (ip->mm16_r5_format.opcode) {
++ case mm_swsp16_op:
++ if (ip->mm16_r5_format.rt != 31)
++ return 0;
++
++ *poff = ip->mm16_r5_format.simmediate;
++ *poff = (*poff << 2) / sizeof(ulong);
++ return 1;
++
++ case mm_pool16c_op:
++ switch (ip->mm16_m_format.func) {
++ case mm_swm16_op:
++ *poff = ip->mm16_m_format.imm;
++ *poff += 1 + ip->mm16_m_format.rlist;
++ *poff = (*poff << 2) / sizeof(ulong);
++ return 1;
++
++ default:
++ return 0;
++ }
++
++ default:
++ return 0;
++ }
+ }
+- else {
+- mmi.halfword[0] = ip->halfword[1];
+- mmi.halfword[1] = ip->halfword[0];
+- return (mmi.mm_m_format.opcode == mm_pool32b_op &&
+- mmi.mm_m_format.rd > 9 &&
+- mmi.mm_m_format.base == 29 &&
+- mmi.mm_m_format.func == mm_swm32_func) ||
+- (mmi.i_format.opcode == mm_sw32_op &&
+- mmi.i_format.rs == 29 &&
+- mmi.i_format.rt == 31);
++
++ switch (ip->i_format.opcode) {
++ case mm_sw32_op:
++ if (ip->i_format.rs != 29)
++ return 0;
++ if (ip->i_format.rt != 31)
++ return 0;
++
++ *poff = ip->i_format.simmediate / sizeof(ulong);
++ return 1;
++
++ case mm_pool32b_op:
++ switch (ip->mm_m_format.func) {
++ case mm_swm32_func:
++ if (ip->mm_m_format.rd < 0x10)
++ return 0;
++ if (ip->mm_m_format.base != 29)
++ return 0;
++
++ *poff = ip->mm_m_format.simmediate;
++ *poff += (ip->mm_m_format.rd & 0xf) * sizeof(u32);
++ *poff /= sizeof(ulong);
++ return 1;
++ default:
++ return 0;
++ }
++
++ default:
++ return 0;
+ }
+ #else
+ /* sw / sd $ra, offset($sp) */
+- return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
+- ip->i_format.rs == 29 &&
+- ip->i_format.rt == 31;
++ if ((ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
++ ip->i_format.rs == 29 && ip->i_format.rt == 31) {
++ *poff = ip->i_format.simmediate / sizeof(ulong);
++ return 1;
++ }
++
++ return 0;
+ #endif
+ }
+
+@@ -242,13 +282,16 @@ static inline int is_jump_ins(union mips_instruction *ip)
+ *
+ * microMIPS is kind of more fun...
+ */
+- union mips_instruction mmi;
+-
+- mmi.word = (ip->halfword[0] << 16);
++ if (mm_insn_16bit(ip->halfword[1])) {
++ if ((ip->mm16_r5_format.opcode == mm_pool16c_op &&
++ (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op))
++ return 1;
++ return 0;
++ }
+
+- if ((mmi.mm16_r5_format.opcode == mm_pool16c_op &&
+- (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) ||
+- ip->j_format.opcode == mm_jal32_op)
++ if (ip->j_format.opcode == mm_j32_op)
++ return 1;
++ if (ip->j_format.opcode == mm_jal32_op)
+ return 1;
+ if (ip->r_format.opcode != mm_pool32a_op ||
+ ip->r_format.func != mm_pool32axf_op)
+@@ -276,15 +319,13 @@ static inline int is_sp_move_ins(union mips_instruction *ip)
+ *
+ * microMIPS is not more fun...
+ */
+- if (mm_insn_16bit(ip->halfword[0])) {
+- union mips_instruction mmi;
+-
+- mmi.word = (ip->halfword[0] << 16);
+- return (mmi.mm16_r3_format.opcode == mm_pool16d_op &&
+- mmi.mm16_r3_format.simmediate && mm_addiusp_func) ||
+- (mmi.mm16_r5_format.opcode == mm_pool16d_op &&
+- mmi.mm16_r5_format.rt == 29);
++ if (mm_insn_16bit(ip->halfword[1])) {
++ return (ip->mm16_r3_format.opcode == mm_pool16d_op &&
++ ip->mm16_r3_format.simmediate && mm_addiusp_func) ||
++ (ip->mm16_r5_format.opcode == mm_pool16d_op &&
++ ip->mm16_r5_format.rt == 29);
+ }
++
+ return ip->mm_i_format.opcode == mm_addiu32_op &&
+ ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29;
+ #else
+@@ -299,30 +340,36 @@ static inline int is_sp_move_ins(union mips_instruction *ip)
+
+ static int get_frame_info(struct mips_frame_info *info)
+ {
+-#ifdef CONFIG_CPU_MICROMIPS
+- union mips_instruction *ip = (void *) (((char *) info->func) - 1);
+-#else
+- union mips_instruction *ip = info->func;
+-#endif
+- unsigned max_insns = info->func_size / sizeof(union mips_instruction);
+- unsigned i;
++ bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS);
++ union mips_instruction insn, *ip, *ip_end;
++ const unsigned int max_insns = 128;
++ unsigned int i;
+
+ info->pc_offset = -1;
+ info->frame_size = 0;
+
++ ip = (void *)msk_isa16_mode((ulong)info->func);
+ if (!ip)
+ goto err;
+
+- if (max_insns == 0)
+- max_insns = 128U; /* unknown function size */
+- max_insns = min(128U, max_insns);
++ ip_end = (void *)ip + info->func_size;
+
+- for (i = 0; i < max_insns; i++, ip++) {
++ for (i = 0; i < max_insns && ip < ip_end; i++, ip++) {
++ if (is_mmips && mm_insn_16bit(ip->halfword[0])) {
++ insn.halfword[0] = 0;
++ insn.halfword[1] = ip->halfword[0];
++ } else if (is_mmips) {
++ insn.halfword[0] = ip->halfword[1];
++ insn.halfword[1] = ip->halfword[0];
++ } else {
++ insn.word = ip->word;
++ }
+
+- if (is_jump_ins(ip))
++ if (is_jump_ins(&insn))
+ break;
++
+ if (!info->frame_size) {
+- if (is_sp_move_ins(ip))
++ if (is_sp_move_ins(&insn))
+ {
+ #ifdef CONFIG_CPU_MICROMIPS
+ if (mm_insn_16bit(ip->halfword[0]))
+@@ -345,11 +392,9 @@ static int get_frame_info(struct mips_frame_info *info)
+ }
+ continue;
+ }
+- if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
+- info->pc_offset =
+- ip->i_format.simmediate / sizeof(long);
++ if (info->pc_offset == -1 &&
++ is_ra_save_ins(&insn, &info->pc_offset))
+ break;
+- }
+ }
+ if (info->frame_size && info->pc_offset >= 0) /* nested */
+ return 0;
+diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
+index 80554e8f6037..3e390a4e3897 100644
+--- a/arch/mips/lantiq/xway/sysctrl.c
++++ b/arch/mips/lantiq/xway/sysctrl.c
+@@ -545,7 +545,7 @@ void __init ltq_soc_init(void)
+ clkdev_add_pmu("1a800000.pcie", "msi", 1, 1, PMU1_PCIE2_MSI);
+ clkdev_add_pmu("1a800000.pcie", "pdi", 1, 1, PMU1_PCIE2_PDI);
+ clkdev_add_pmu("1a800000.pcie", "ctl", 1, 1, PMU1_PCIE2_CTL);
+- clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH | PMU_PPE_DP);
++ clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP);
+ clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
+ clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+ } else if (of_machine_is_compatible("lantiq,ar10")) {
+@@ -553,7 +553,7 @@ void __init ltq_soc_init(void)
+ ltq_ar10_fpi_hz(), ltq_ar10_pp32_hz());
+ clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+ clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1);
+- clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH |
++ clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH |
+ PMU_PPE_DP | PMU_PPE_TC);
+ clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
+ clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
+@@ -575,11 +575,11 @@ void __init ltq_soc_init(void)
+ clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS);
+
+ clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
+- clkdev_add_pmu("1e108000.eth", NULL, 1, 0,
++ clkdev_add_pmu("1e108000.eth", NULL, 0, 0,
+ PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
+ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
+ PMU_PPE_QSB | PMU_PPE_TOP);
+- clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
++ clkdev_add_pmu("1f203000.rcu", "gphy", 0, 0, PMU_GPHY);
+ clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
+ clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+ clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
+diff --git a/arch/mips/mm/sc-ip22.c b/arch/mips/mm/sc-ip22.c
+index dc7c5a5214a9..efaf364fe581 100644
+--- a/arch/mips/mm/sc-ip22.c
++++ b/arch/mips/mm/sc-ip22.c
+@@ -31,26 +31,40 @@ static inline void indy_sc_wipe(unsigned long first, unsigned long last)
+ unsigned long tmp;
+
+ __asm__ __volatile__(
+- ".set\tpush\t\t\t# indy_sc_wipe\n\t"
+- ".set\tnoreorder\n\t"
+- ".set\tmips3\n\t"
+- ".set\tnoat\n\t"
+- "mfc0\t%2, $12\n\t"
+- "li\t$1, 0x80\t\t\t# Go 64 bit\n\t"
+- "mtc0\t$1, $12\n\t"
+-
+- "dli\t$1, 0x9000000080000000\n\t"
+- "or\t%0, $1\t\t\t# first line to flush\n\t"
+- "or\t%1, $1\t\t\t# last line to flush\n\t"
+- ".set\tat\n\t"
+-
+- "1:\tsw\t$0, 0(%0)\n\t"
+- "bne\t%0, %1, 1b\n\t"
+- " daddu\t%0, 32\n\t"
+-
+- "mtc0\t%2, $12\t\t\t# Back to 32 bit\n\t"
+- "nop; nop; nop; nop;\n\t"
+- ".set\tpop"
++ " .set push # indy_sc_wipe \n"
++ " .set noreorder \n"
++ " .set mips3 \n"
++ " .set noat \n"
++ " mfc0 %2, $12 \n"
++ " li $1, 0x80 # Go 64 bit \n"
++ " mtc0 $1, $12 \n"
++ " \n"
++ " # \n"
++ " # Open code a dli $1, 0x9000000080000000 \n"
++ " # \n"
++ " # Required because binutils 2.25 will happily accept \n"
++ " # 64 bit instructions in .set mips3 mode but puke on \n"
++ " # 64 bit constants when generating 32 bit ELF \n"
++ " # \n"
++ " lui $1,0x9000 \n"
++ " dsll $1,$1,0x10 \n"
++ " ori $1,$1,0x8000 \n"
++ " dsll $1,$1,0x10 \n"
++ " \n"
++ " or %0, $1 # first line to flush \n"
++ " or %1, $1 # last line to flush \n"
++ " .set at \n"
++ " \n"
++ "1: sw $0, 0(%0) \n"
++ " bne %0, %1, 1b \n"
++ " daddu %0, 32 \n"
++ " \n"
++ " mtc0 %2, $12 # Back to 32 bit \n"
++ " nop # pipeline hazard \n"
++ " nop \n"
++ " nop \n"
++ " nop \n"
++ " .set pop \n"
+ : "=r" (first), "=r" (last), "=&r" (tmp)
+ : "0" (first), "1" (last));
+ }
+diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
+index 05e804cdecaa..fdf48785d3e9 100644
+--- a/arch/powerpc/kernel/hw_breakpoint.c
++++ b/arch/powerpc/kernel/hw_breakpoint.c
+@@ -227,8 +227,10 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
+ rcu_read_lock();
+
+ bp = __this_cpu_read(bp_per_reg);
+- if (!bp)
++ if (!bp) {
++ rc = NOTIFY_DONE;
+ goto out;
++ }
+ info = counter_arch_bp(bp);
+
+ /*
+diff --git a/crypto/testmgr.h b/crypto/testmgr.h
+index da0a8fd765f4..0e02c60a57b6 100644
+--- a/crypto/testmgr.h
++++ b/crypto/testmgr.h
+@@ -21778,7 +21778,7 @@ static struct aead_testvec aes_ccm_enc_tv_template[] = {
+ "\x09\x75\x9a\x9b\x3c\x9b\x27\x39",
+ .klen = 32,
+ .iv = "\x03\xf9\xd9\x4e\x63\xb5\x3d\x9d"
+- "\x43\xf6\x1e\x50",
++ "\x43\xf6\x1e\x50\0\0\0\0",
+ .assoc = "\x57\xf5\x6b\x8b\x57\x5c\x3d\x3b"
+ "\x13\x02\x01\x0c\x83\x4c\x96\x35"
+ "\x8e\xd6\x39\xcf\x7d\x14\x9b\x94"
+diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
+index 59d8d0d14824..327f9e374b44 100644
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -640,8 +640,11 @@ static int bcma_device_probe(struct device *dev)
+ drv);
+ int err = 0;
+
++ get_device(dev);
+ if (adrv->probe)
+ err = adrv->probe(core);
++ if (err)
++ put_device(dev);
+
+ return err;
+ }
+@@ -654,6 +657,7 @@ static int bcma_device_remove(struct device *dev)
+
+ if (adrv->remove)
+ adrv->remove(core);
++ put_device(dev);
+
+ return 0;
+ }
+diff --git a/drivers/block/loop.c b/drivers/block/loop.c
+index ab0b2dd3f629..cec36d5c24f5 100644
+--- a/drivers/block/loop.c
++++ b/drivers/block/loop.c
+@@ -1108,9 +1108,12 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
+ if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE)
+ return -EINVAL;
+
++ /* I/O need to be drained during transfer transition */
++ blk_mq_freeze_queue(lo->lo_queue);
++
+ err = loop_release_xfer(lo);
+ if (err)
+- return err;
++ goto exit;
+
+ if (info->lo_encrypt_type) {
+ unsigned int type = info->lo_encrypt_type;
+@@ -1125,12 +1128,14 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
+
+ err = loop_init_xfer(lo, xfer, info);
+ if (err)
+- return err;
++ goto exit;
+
+ if (lo->lo_offset != info->lo_offset ||
+ lo->lo_sizelimit != info->lo_sizelimit)
+- if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit))
+- return -EFBIG;
++ if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) {
++ err = -EFBIG;
++ goto exit;
++ }
+
+ loop_config_discard(lo);
+
+@@ -1148,13 +1153,6 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
+ (info->lo_flags & LO_FLAGS_AUTOCLEAR))
+ lo->lo_flags ^= LO_FLAGS_AUTOCLEAR;
+
+- if ((info->lo_flags & LO_FLAGS_PARTSCAN) &&
+- !(lo->lo_flags & LO_FLAGS_PARTSCAN)) {
+- lo->lo_flags |= LO_FLAGS_PARTSCAN;
+- lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
+- loop_reread_partitions(lo, lo->lo_device);
+- }
+-
+ lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
+ lo->lo_init[0] = info->lo_init[0];
+ lo->lo_init[1] = info->lo_init[1];
+@@ -1167,7 +1165,17 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
+ /* update dio if lo_offset or transfer is changed */
+ __loop_update_dio(lo, lo->use_dio);
+
+- return 0;
++ exit:
++ blk_mq_unfreeze_queue(lo->lo_queue);
++
++ if (!err && (info->lo_flags & LO_FLAGS_PARTSCAN) &&
++ !(lo->lo_flags & LO_FLAGS_PARTSCAN)) {
++ lo->lo_flags |= LO_FLAGS_PARTSCAN;
++ lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
++ loop_reread_partitions(lo, lo->lo_device);
++ }
++
++ return err;
+ }
+
+ static int
+diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c
+index dd184b50e5b4..284627806b88 100644
+--- a/drivers/dma/ipu/ipu_irq.c
++++ b/drivers/dma/ipu/ipu_irq.c
+@@ -272,7 +272,7 @@ static void ipu_irq_handler(struct irq_desc *desc)
+ u32 status;
+ int i, line;
+
+- for (i = IPU_IRQ_NR_FN_BANKS; i < IPU_IRQ_NR_BANKS; i++) {
++ for (i = 0; i < IPU_IRQ_NR_BANKS; i++) {
+ struct ipu_irq_bank *bank = irq_bank + i;
+
+ raw_spin_lock(&bank_lock);
+diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
+index 63194a9a7189..89fd0113aa5c 100644
+--- a/drivers/hv/hv.c
++++ b/drivers/hv/hv.c
+@@ -422,7 +422,7 @@ int hv_synic_alloc(void)
+ goto err;
+ }
+
+- for_each_online_cpu(cpu) {
++ for_each_present_cpu(cpu) {
+ hv_context.event_dpc[cpu] = kmalloc(size, GFP_ATOMIC);
+ if (hv_context.event_dpc[cpu] == NULL) {
+ pr_err("Unable to allocate event dpc\n");
+@@ -461,6 +461,8 @@ int hv_synic_alloc(void)
+ pr_err("Unable to allocate post msg page\n");
+ goto err;
+ }
++
++ INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
+ }
+
+ return 0;
+@@ -485,7 +487,7 @@ void hv_synic_free(void)
+ int cpu;
+
+ kfree(hv_context.hv_numa_map);
+- for_each_online_cpu(cpu)
++ for_each_present_cpu(cpu)
+ hv_synic_free_cpu(cpu);
+ }
+
+@@ -555,8 +557,6 @@ void hv_synic_init(void *arg)
+ rdmsrl(HV_X64_MSR_VP_INDEX, vp_index);
+ hv_context.vp_index[cpu] = (u32)vp_index;
+
+- INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
+-
+ /*
+ * Register the per-cpu clockevent source.
+ */
+diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
+index c37a71e13de0..1fb02dcbc500 100644
+--- a/drivers/hv/hv_fcopy.c
++++ b/drivers/hv/hv_fcopy.c
+@@ -61,6 +61,7 @@ static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
+ static const char fcopy_devname[] = "vmbus/hv_fcopy";
+ static u8 *recv_buffer;
+ static struct hvutil_transport *hvt;
++static struct completion release_event;
+ /*
+ * This state maintains the version number registered by the daemon.
+ */
+@@ -312,12 +313,14 @@ static void fcopy_on_reset(void)
+
+ if (cancel_delayed_work_sync(&fcopy_timeout_work))
+ fcopy_respond_to_host(HV_E_FAIL);
++ complete(&release_event);
+ }
+
+ int hv_fcopy_init(struct hv_util_service *srv)
+ {
+ recv_buffer = srv->recv_buffer;
+
++ init_completion(&release_event);
+ /*
+ * When this driver loads, the user level daemon that
+ * processes the host requests may not yet be running.
+@@ -339,4 +342,5 @@ void hv_fcopy_deinit(void)
+ fcopy_transaction.state = HVUTIL_DEVICE_DYING;
+ cancel_delayed_work_sync(&fcopy_timeout_work);
+ hvutil_transport_destroy(hvt);
++ wait_for_completion(&release_event);
+ }
+diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
+index 2a3420c4ca59..ce4d3a935491 100644
+--- a/drivers/hv/hv_kvp.c
++++ b/drivers/hv/hv_kvp.c
+@@ -86,6 +86,7 @@ static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
+ static const char kvp_devname[] = "vmbus/hv_kvp";
+ static u8 *recv_buffer;
+ static struct hvutil_transport *hvt;
++static struct completion release_event;
+ /*
+ * Register the kernel component with the user-level daemon.
+ * As part of this registration, pass the LIC version number.
+@@ -682,6 +683,7 @@ static void kvp_on_reset(void)
+ if (cancel_delayed_work_sync(&kvp_timeout_work))
+ kvp_respond_to_host(NULL, HV_E_FAIL);
+ kvp_transaction.state = HVUTIL_DEVICE_INIT;
++ complete(&release_event);
+ }
+
+ int
+@@ -689,6 +691,7 @@ hv_kvp_init(struct hv_util_service *srv)
+ {
+ recv_buffer = srv->recv_buffer;
+
++ init_completion(&release_event);
+ /*
+ * When this driver loads, the user level daemon that
+ * processes the host requests may not yet be running.
+@@ -711,4 +714,5 @@ void hv_kvp_deinit(void)
+ cancel_delayed_work_sync(&kvp_timeout_work);
+ cancel_work_sync(&kvp_sendkey_work);
+ hvutil_transport_destroy(hvt);
++ wait_for_completion(&release_event);
+ }
+diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
+index 81882d4848bd..faad79ae318a 100644
+--- a/drivers/hv/hv_snapshot.c
++++ b/drivers/hv/hv_snapshot.c
+@@ -66,6 +66,7 @@ static int dm_reg_value;
+ static const char vss_devname[] = "vmbus/hv_vss";
+ static __u8 *recv_buffer;
+ static struct hvutil_transport *hvt;
++static struct completion release_event;
+
+ static void vss_send_op(struct work_struct *dummy);
+ static void vss_timeout_func(struct work_struct *dummy);
+@@ -326,11 +327,13 @@ static void vss_on_reset(void)
+ if (cancel_delayed_work_sync(&vss_timeout_work))
+ vss_respond_to_host(HV_E_FAIL);
+ vss_transaction.state = HVUTIL_DEVICE_INIT;
++ complete(&release_event);
+ }
+
+ int
+ hv_vss_init(struct hv_util_service *srv)
+ {
++ init_completion(&release_event);
+ if (vmbus_proto_version < VERSION_WIN8_1) {
+ pr_warn("Integration service 'Backup (volume snapshot)'"
+ " not supported on this host version.\n");
+@@ -360,4 +363,5 @@ void hv_vss_deinit(void)
+ cancel_delayed_work_sync(&vss_timeout_work);
+ cancel_work_sync(&vss_send_op_work);
+ hvutil_transport_destroy(hvt);
++ wait_for_completion(&release_event);
+ }
+diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c
+index a0d7deeac62f..3f90985d545e 100644
+--- a/drivers/iio/pressure/mpl115.c
++++ b/drivers/iio/pressure/mpl115.c
+@@ -136,6 +136,7 @@ static const struct iio_chan_spec mpl115_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
++ .info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),
+ },
+ };
+diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c
+index 01b2e0b18878..0f5b8767ec2e 100644
+--- a/drivers/iio/pressure/mpl3115.c
++++ b/drivers/iio/pressure/mpl3115.c
+@@ -182,7 +182,7 @@ static const struct iio_chan_spec mpl3115_channels[] = {
+ {
+ .type = IIO_PRESSURE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+- BIT(IIO_CHAN_INFO_SCALE),
++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+@@ -195,7 +195,7 @@ static const struct iio_chan_spec mpl3115_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+- BIT(IIO_CHAN_INFO_SCALE),
++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 's',
+diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
+index c9dcad6a53bf..3f5741a3e728 100644
+--- a/drivers/infiniband/core/cma.c
++++ b/drivers/infiniband/core/cma.c
+@@ -3349,6 +3349,9 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
+ struct iw_cm_conn_param iw_param;
+ int ret;
+
++ if (!conn_param)
++ return -EINVAL;
++
+ ret = cma_modify_qp_rtr(id_priv, conn_param);
+ if (ret)
+ return ret;
+diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
+index 9413b0726237..f0fc6f7b5d98 100644
+--- a/drivers/iommu/intel-iommu.c
++++ b/drivers/iommu/intel-iommu.c
+@@ -3238,13 +3238,14 @@ static int __init init_dmars(void)
+ iommu_identity_mapping |= IDENTMAP_GFX;
+ #endif
+
++ check_tylersburg_isoch();
++
+ if (iommu_identity_mapping) {
+ ret = si_domain_init(hw_pass_through);
+ if (ret)
+ goto free_iommu;
+ }
+
+- check_tylersburg_isoch();
+
+ /*
+ * If we copied translations from a previous kernel in the kdump
+diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
+index 515f83e7d9ab..b59615ddf6ba 100644
+--- a/drivers/md/dm-cache-target.c
++++ b/drivers/md/dm-cache-target.c
+@@ -251,7 +251,7 @@ struct cache {
+ /*
+ * Fields for converting from sectors to blocks.
+ */
+- uint32_t sectors_per_block;
++ sector_t sectors_per_block;
+ int sectors_per_block_shift;
+
+ spinlock_t lock;
+@@ -3547,11 +3547,11 @@ static void cache_status(struct dm_target *ti, status_type_t type,
+
+ residency = policy_residency(cache->policy);
+
+- DMEMIT("%u %llu/%llu %u %llu/%llu %u %u %u %u %u %u %lu ",
++ DMEMIT("%u %llu/%llu %llu %llu/%llu %u %u %u %u %u %u %lu ",
+ (unsigned)DM_CACHE_METADATA_BLOCK_SIZE,
+ (unsigned long long)(nr_blocks_metadata - nr_free_blocks_metadata),
+ (unsigned long long)nr_blocks_metadata,
+- cache->sectors_per_block,
++ (unsigned long long)cache->sectors_per_block,
+ (unsigned long long) from_cblock(residency),
+ (unsigned long long) from_cblock(cache->cache_size),
+ (unsigned) atomic_read(&cache->stats.read_hit),
+diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c
+index 8289804ccd99..d5ea9f28ae70 100644
+--- a/drivers/md/dm-stats.c
++++ b/drivers/md/dm-stats.c
+@@ -175,6 +175,7 @@ static void dm_stat_free(struct rcu_head *head)
+ int cpu;
+ struct dm_stat *s = container_of(head, struct dm_stat, rcu_head);
+
++ kfree(s->histogram_boundaries);
+ kfree(s->program_id);
+ kfree(s->aux_data);
+ for_each_possible_cpu(cpu) {
+diff --git a/drivers/md/linear.c b/drivers/md/linear.c
+index b7fe7e9fc777..6ba3227e29b2 100644
+--- a/drivers/md/linear.c
++++ b/drivers/md/linear.c
+@@ -52,18 +52,26 @@ static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector)
+ return conf->disks + lo;
+ }
+
++/*
++ * In linear_congested() conf->raid_disks is used as a copy of
++ * mddev->raid_disks to iterate conf->disks[], because conf->raid_disks
++ * and conf->disks[] are created in linear_conf(), they are always
++ * consitent with each other, but mddev->raid_disks does not.
++ */
+ static int linear_congested(struct mddev *mddev, int bits)
+ {
+ struct linear_conf *conf;
+ int i, ret = 0;
+
+- conf = mddev->private;
++ rcu_read_lock();
++ conf = rcu_dereference(mddev->private);
+
+- for (i = 0; i < mddev->raid_disks && !ret ; i++) {
++ for (i = 0; i < conf->raid_disks && !ret ; i++) {
+ struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev);
+ ret |= bdi_congested(&q->backing_dev_info, bits);
+ }
+
++ rcu_read_unlock();
+ return ret;
+ }
+
+@@ -143,6 +151,19 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks)
+ conf->disks[i-1].end_sector +
+ conf->disks[i].rdev->sectors;
+
++ /*
++ * conf->raid_disks is copy of mddev->raid_disks. The reason to
++ * keep a copy of mddev->raid_disks in struct linear_conf is,
++ * mddev->raid_disks may not be consistent with pointers number of
++ * conf->disks[] when it is updated in linear_add() and used to
++ * iterate old conf->disks[] earray in linear_congested().
++ * Here conf->raid_disks is always consitent with number of
++ * pointers in conf->disks[] array, and mddev->private is updated
++ * with rcu_assign_pointer() in linear_addr(), such race can be
++ * avoided.
++ */
++ conf->raid_disks = raid_disks;
++
+ return conf;
+
+ out:
+@@ -195,15 +216,23 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev)
+ if (!newconf)
+ return -ENOMEM;
+
++ /* newconf->raid_disks already keeps a copy of * the increased
++ * value of mddev->raid_disks, WARN_ONCE() is just used to make
++ * sure of this. It is possible that oldconf is still referenced
++ * in linear_congested(), therefore kfree_rcu() is used to free
++ * oldconf until no one uses it anymore.
++ */
+ mddev_suspend(mddev);
+- oldconf = mddev->private;
++ oldconf = rcu_dereference(mddev->private);
+ mddev->raid_disks++;
+- mddev->private = newconf;
++ WARN_ONCE(mddev->raid_disks != newconf->raid_disks,
++ "copied raid_disks doesn't match mddev->raid_disks");
++ rcu_assign_pointer(mddev->private, newconf);
+ md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
+ set_capacity(mddev->gendisk, mddev->array_sectors);
+ mddev_resume(mddev);
+ revalidate_disk(mddev->gendisk);
+- kfree(oldconf);
++ kfree_rcu(oldconf, rcu);
+ return 0;
+ }
+
+diff --git a/drivers/md/linear.h b/drivers/md/linear.h
+index b685ddd7d7f7..8d392e6098b3 100644
+--- a/drivers/md/linear.h
++++ b/drivers/md/linear.h
+@@ -10,6 +10,7 @@ struct linear_conf
+ {
+ struct rcu_head rcu;
+ sector_t array_sectors;
++ int raid_disks; /* a copy of mddev->raid_disks */
+ struct dev_info disks[0];
+ };
+ #endif
+diff --git a/drivers/media/pci/dm1105/Kconfig b/drivers/media/pci/dm1105/Kconfig
+index 173daf0c0847..14fa7e40f2a6 100644
+--- a/drivers/media/pci/dm1105/Kconfig
++++ b/drivers/media/pci/dm1105/Kconfig
+@@ -1,6 +1,6 @@
+ config DVB_DM1105
+ tristate "SDMC DM1105 based PCI cards"
+- depends on DVB_CORE && PCI && I2C
++ depends on DVB_CORE && PCI && I2C && I2C_ALGOBIT
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
+diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
+index ba780c45f645..572bc043b62d 100644
+--- a/drivers/media/platform/am437x/am437x-vpfe.c
++++ b/drivers/media/platform/am437x/am437x-vpfe.c
+@@ -1576,7 +1576,7 @@ static int vpfe_s_fmt(struct file *file, void *priv,
+ return -EBUSY;
+ }
+
+- ret = vpfe_try_fmt(file, priv, &format);
++ ret = __vpfe_get_format(vpfe, &format, &bpp);
+ if (ret)
+ return ret;
+
+diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
+index cfb868a48b5f..ff6feff21e94 100644
+--- a/drivers/media/usb/uvc/uvc_queue.c
++++ b/drivers/media/usb/uvc/uvc_queue.c
+@@ -416,7 +416,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+ nextbuf = NULL;
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+- buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
++ buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
+ vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
+ vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
+
+diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
+index a731720f1d13..449b2a47f9a8 100644
+--- a/drivers/net/can/usb/usb_8dev.c
++++ b/drivers/net/can/usb/usb_8dev.c
+@@ -954,8 +954,8 @@ static int usb_8dev_probe(struct usb_interface *intf,
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+
+- priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg),
+- GFP_KERNEL);
++ priv->cmd_msg_buffer = devm_kzalloc(&intf->dev, sizeof(struct usb_8dev_cmd_msg),
++ GFP_KERNEL);
+ if (!priv->cmd_msg_buffer)
+ goto cleanup_candev;
+
+@@ -969,7 +969,7 @@ static int usb_8dev_probe(struct usb_interface *intf,
+ if (err) {
+ netdev_err(netdev,
+ "couldn't register CAN device: %d\n", err);
+- goto cleanup_cmd_msg_buffer;
++ goto cleanup_candev;
+ }
+
+ err = usb_8dev_cmd_version(priv, &version);
+@@ -990,9 +990,6 @@ static int usb_8dev_probe(struct usb_interface *intf,
+ cleanup_unregister_candev:
+ unregister_netdev(priv->netdev);
+
+-cleanup_cmd_msg_buffer:
+- kfree(priv->cmd_msg_buffer);
+-
+ cleanup_candev:
+ free_candev(netdev);
+
+diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+index dc44cfef7517..16e052d02c94 100644
+--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
++++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+@@ -502,8 +502,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ break;
+ return -EOPNOTSUPP;
+ default:
+- WARN_ON(1);
+- return -EINVAL;
++ return -EOPNOTSUPP;
+ }
+
+ mutex_lock(&ah->lock);
+diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+index 694ca2e680e5..74670e08e6da 100644
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+@@ -73,13 +73,13 @@
+ #define AR9300_OTP_BASE \
+ ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000)
+ #define AR9300_OTP_STATUS \
+- ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30018 : 0x15f18)
++ ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x31018 : 0x15f18)
+ #define AR9300_OTP_STATUS_TYPE 0x7
+ #define AR9300_OTP_STATUS_VALID 0x4
+ #define AR9300_OTP_STATUS_ACCESS_BUSY 0x2
+ #define AR9300_OTP_STATUS_SM_BUSY 0x1
+ #define AR9300_OTP_READ_DATA \
+- ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3001c : 0x15f1c)
++ ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3101c : 0x15f1c)
+
+ enum targetPowerHTRates {
+ HT_TARGET_RATE_0_8_16,
+diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
+index b42f4a963ef4..a660e40f2df1 100644
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -959,6 +959,7 @@ struct ath_softc {
+ struct survey_info *cur_survey;
+ struct survey_info survey[ATH9K_NUM_CHANNELS];
+
++ spinlock_t intr_lock;
+ struct tasklet_struct intr_tq;
+ struct tasklet_struct bcon_tasklet;
+ struct ath_hw *sc_ah;
+diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
+index bc70ce62bc03..0f5672f5c9ba 100644
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -619,6 +619,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
+ common->bt_ant_diversity = 1;
+
+ spin_lock_init(&common->cc_lock);
++ spin_lock_init(&sc->intr_lock);
+ spin_lock_init(&sc->sc_serial_rw);
+ spin_lock_init(&sc->sc_pm_lock);
+ spin_lock_init(&sc->chan_lock);
+diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
+index bba85d1a6cd1..d937c39b3a0b 100644
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -805,21 +805,12 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
+ }
+ EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
+
+-void ath9k_hw_enable_interrupts(struct ath_hw *ah)
++static void __ath9k_hw_enable_interrupts(struct ath_hw *ah)
+ {
+ struct ath_common *common = ath9k_hw_common(ah);
+ u32 sync_default = AR_INTR_SYNC_DEFAULT;
+ u32 async_mask;
+
+- if (!(ah->imask & ATH9K_INT_GLOBAL))
+- return;
+-
+- if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
+- ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
+- atomic_read(&ah->intr_ref_cnt));
+- return;
+- }
+-
+ if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah))
+ sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
+@@ -841,6 +832,39 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
+ ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
+ REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
+ }
++
++void ath9k_hw_resume_interrupts(struct ath_hw *ah)
++{
++ struct ath_common *common = ath9k_hw_common(ah);
++
++ if (!(ah->imask & ATH9K_INT_GLOBAL))
++ return;
++
++ if (atomic_read(&ah->intr_ref_cnt) != 0) {
++ ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
++ atomic_read(&ah->intr_ref_cnt));
++ return;
++ }
++
++ __ath9k_hw_enable_interrupts(ah);
++}
++EXPORT_SYMBOL(ath9k_hw_resume_interrupts);
++
++void ath9k_hw_enable_interrupts(struct ath_hw *ah)
++{
++ struct ath_common *common = ath9k_hw_common(ah);
++
++ if (!(ah->imask & ATH9K_INT_GLOBAL))
++ return;
++
++ if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
++ ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
++ atomic_read(&ah->intr_ref_cnt));
++ return;
++ }
++
++ __ath9k_hw_enable_interrupts(ah);
++}
+ EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
+
+ void ath9k_hw_set_interrupts(struct ath_hw *ah)
+diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
+index 7fbf7f965f61..1b63d26f30ce 100644
+--- a/drivers/net/wireless/ath/ath9k/mac.h
++++ b/drivers/net/wireless/ath/ath9k/mac.h
+@@ -748,6 +748,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah);
+ void ath9k_hw_enable_interrupts(struct ath_hw *ah);
+ void ath9k_hw_disable_interrupts(struct ath_hw *ah);
+ void ath9k_hw_kill_interrupts(struct ath_hw *ah);
++void ath9k_hw_resume_interrupts(struct ath_hw *ah);
+
+ void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
+
+diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
+index 8c5d2cf9c979..b114e57a823f 100644
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -373,21 +373,20 @@ void ath9k_tasklet(unsigned long data)
+ struct ath_common *common = ath9k_hw_common(ah);
+ enum ath_reset_type type;
+ unsigned long flags;
+- u32 status = sc->intrstatus;
++ u32 status;
+ u32 rxmask;
+
++ spin_lock_irqsave(&sc->intr_lock, flags);
++ status = sc->intrstatus;
++ sc->intrstatus = 0;
++ spin_unlock_irqrestore(&sc->intr_lock, flags);
++
+ ath9k_ps_wakeup(sc);
+ spin_lock(&sc->sc_pcu_lock);
+
+ if (status & ATH9K_INT_FATAL) {
+ type = RESET_TYPE_FATAL_INT;
+ ath9k_queue_reset(sc, type);
+-
+- /*
+- * Increment the ref. counter here so that
+- * interrupts are enabled in the reset routine.
+- */
+- atomic_inc(&ah->intr_ref_cnt);
+ ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
+ goto out;
+ }
+@@ -403,11 +402,6 @@ void ath9k_tasklet(unsigned long data)
+ type = RESET_TYPE_BB_WATCHDOG;
+ ath9k_queue_reset(sc, type);
+
+- /*
+- * Increment the ref. counter here so that
+- * interrupts are enabled in the reset routine.
+- */
+- atomic_inc(&ah->intr_ref_cnt);
+ ath_dbg(common, RESET,
+ "BB_WATCHDOG: Skipping interrupts\n");
+ goto out;
+@@ -420,7 +414,6 @@ void ath9k_tasklet(unsigned long data)
+ if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) {
+ type = RESET_TYPE_TX_GTT;
+ ath9k_queue_reset(sc, type);
+- atomic_inc(&ah->intr_ref_cnt);
+ ath_dbg(common, RESET,
+ "GTT: Skipping interrupts\n");
+ goto out;
+@@ -477,7 +470,7 @@ void ath9k_tasklet(unsigned long data)
+ ath9k_btcoex_handle_interrupt(sc, status);
+
+ /* re-enable hardware interrupt */
+- ath9k_hw_enable_interrupts(ah);
++ ath9k_hw_resume_interrupts(ah);
+ out:
+ spin_unlock(&sc->sc_pcu_lock);
+ ath9k_ps_restore(sc);
+@@ -541,7 +534,9 @@ irqreturn_t ath_isr(int irq, void *dev)
+ return IRQ_NONE;
+
+ /* Cache the status */
+- sc->intrstatus = status;
++ spin_lock(&sc->intr_lock);
++ sc->intrstatus |= status;
++ spin_unlock(&sc->intr_lock);
+
+ if (status & SCHED_INTR)
+ sched = true;
+@@ -587,7 +582,7 @@ chip_reset:
+
+ if (sched) {
+ /* turn off every interrupt */
+- ath9k_hw_disable_interrupts(ah);
++ ath9k_hw_kill_interrupts(ah);
+ tasklet_schedule(&sc->intr_tq);
+ }
+
+diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h
+index 5da6703942d9..672f81ea02d0 100644
+--- a/drivers/net/wireless/realtek/rtlwifi/pci.h
++++ b/drivers/net/wireless/realtek/rtlwifi/pci.h
+@@ -275,10 +275,10 @@ struct mp_adapter {
+ };
+
+ struct rtl_pci_priv {
++ struct bt_coexist_info bt_coexist;
++ struct rtl_led_ctl ledctl;
+ struct rtl_pci dev;
+ struct mp_adapter ndis_adapter;
+- struct rtl_led_ctl ledctl;
+- struct bt_coexist_info bt_coexist;
+ };
+
+ #define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv))
+diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
+index 5f14308e8eb3..b1601441991d 100644
+--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
+@@ -1003,7 +1003,7 @@ static void _rtl92ee_hw_configure(struct ieee80211_hw *hw)
+ rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x100a);
+
+ /* Note Data sheet don't define */
+- rtl_write_word(rtlpriv, 0x4C7, 0x80);
++ rtl_write_byte(rtlpriv, 0x4C7, 0x80);
+
+ rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x20);
+
+diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
+index bbb789f8990b..c2103e7a8132 100644
+--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
+@@ -1127,7 +1127,7 @@ static u8 _rtl8821ae_dbi_read(struct rtl_priv *rtlpriv, u16 addr)
+ }
+ if (0 == tmp) {
+ read_addr = REG_DBI_RDATA + addr % 4;
+- ret = rtl_read_word(rtlpriv, read_addr);
++ ret = rtl_read_byte(rtlpriv, read_addr);
+ }
+ return ret;
+ }
+diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.h b/drivers/net/wireless/realtek/rtlwifi/usb.h
+index 685273ca9561..441c4412130c 100644
+--- a/drivers/net/wireless/realtek/rtlwifi/usb.h
++++ b/drivers/net/wireless/realtek/rtlwifi/usb.h
+@@ -150,8 +150,9 @@ struct rtl_usb {
+ };
+
+ struct rtl_usb_priv {
+- struct rtl_usb dev;
++ struct bt_coexist_info bt_coexist;
+ struct rtl_led_ctl ledctl;
++ struct rtl_usb dev;
+ };
+
+ #define rtl_usbpriv(hw) (((struct rtl_usb_priv *)(rtl_priv(hw))->priv))
+diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
+index 732ac71b82cd..88dbbeb8569b 100644
+--- a/drivers/regulator/core.c
++++ b/drivers/regulator/core.c
+@@ -4273,12 +4273,13 @@ static void regulator_summary_show_subtree(struct seq_file *s,
+ seq_puts(s, "\n");
+
+ list_for_each_entry(consumer, &rdev->consumer_list, list) {
+- if (consumer->dev->class == &regulator_class)
++ if (consumer->dev && consumer->dev->class == &regulator_class)
+ continue;
+
+ seq_printf(s, "%*s%-*s ",
+ (level + 1) * 3 + 1, "",
+- 30 - (level + 1) * 3, dev_name(consumer->dev));
++ 30 - (level + 1) * 3,
++ consumer->dev ? dev_name(consumer->dev) : "deviceless");
+
+ switch (rdev->desc->type) {
+ case REGULATOR_VOLTAGE:
+diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
+index c169a2cd4727..e29cc9fca0bf 100644
+--- a/drivers/rtc/rtc-sun6i.c
++++ b/drivers/rtc/rtc-sun6i.c
+@@ -37,9 +37,11 @@
+
+ /* Control register */
+ #define SUN6I_LOSC_CTRL 0x0000
++#define SUN6I_LOSC_CTRL_KEY (0x16aa << 16)
+ #define SUN6I_LOSC_CTRL_ALM_DHMS_ACC BIT(9)
+ #define SUN6I_LOSC_CTRL_RTC_HMS_ACC BIT(8)
+ #define SUN6I_LOSC_CTRL_RTC_YMD_ACC BIT(7)
++#define SUN6I_LOSC_CTRL_EXT_OSC BIT(0)
+ #define SUN6I_LOSC_CTRL_ACC_MASK GENMASK(9, 7)
+
+ /* RTC */
+@@ -114,13 +116,17 @@ struct sun6i_rtc_dev {
+ void __iomem *base;
+ int irq;
+ unsigned long alarm;
++
++ spinlock_t lock;
+ };
+
+ static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
+ {
+ struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id;
++ irqreturn_t ret = IRQ_NONE;
+ u32 val;
+
++ spin_lock(&chip->lock);
+ val = readl(chip->base + SUN6I_ALRM_IRQ_STA);
+
+ if (val & SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND) {
+@@ -129,10 +135,11 @@ static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
+
+ rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
+
+- return IRQ_HANDLED;
++ ret = IRQ_HANDLED;
+ }
++ spin_unlock(&chip->lock);
+
+- return IRQ_NONE;
++ return ret;
+ }
+
+ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
+@@ -140,6 +147,7 @@ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
+ u32 alrm_val = 0;
+ u32 alrm_irq_val = 0;
+ u32 alrm_wake_val = 0;
++ unsigned long flags;
+
+ if (to) {
+ alrm_val = SUN6I_ALRM_EN_CNT_EN;
+@@ -150,9 +158,11 @@ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
+ chip->base + SUN6I_ALRM_IRQ_STA);
+ }
+
++ spin_lock_irqsave(&chip->lock, flags);
+ writel(alrm_val, chip->base + SUN6I_ALRM_EN);
+ writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN);
+ writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG);
++ spin_unlock_irqrestore(&chip->lock, flags);
+ }
+
+ static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
+@@ -191,11 +201,15 @@ static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
+ static int sun6i_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+ {
+ struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
++ unsigned long flags;
+ u32 alrm_st;
+ u32 alrm_en;
+
++ spin_lock_irqsave(&chip->lock, flags);
+ alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN);
+ alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA);
++ spin_unlock_irqrestore(&chip->lock, flags);
++
+ wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN);
+ wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN);
+ rtc_time_to_tm(chip->alarm, &wkalrm->time);
+@@ -356,6 +370,7 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
++ spin_lock_init(&chip->lock);
+
+ platform_set_drvdata(pdev, chip);
+ chip->dev = &pdev->dev;
+@@ -404,6 +419,10 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
+ /* disable alarm wakeup */
+ writel(0, chip->base + SUN6I_ALARM_CONFIG);
+
++ /* switch to the external, more precise, oscillator */
++ writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC,
++ chip->base + SUN6I_LOSC_CTRL);
++
+ chip->rtc = rtc_device_register("rtc-sun6i", &pdev->dev,
+ &sun6i_rtc_ops, THIS_MODULE);
+ if (IS_ERR(chip->rtc)) {
+diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
+index bc0203f3d243..e415e1c58eb5 100644
+--- a/drivers/scsi/aacraid/src.c
++++ b/drivers/scsi/aacraid/src.c
+@@ -413,16 +413,23 @@ static int aac_src_check_health(struct aac_dev *dev)
+ u32 status = src_readl(dev, MUnit.OMR);
+
+ /*
++ * Check to see if the board panic'd.
++ */
++ if (unlikely(status & KERNEL_PANIC))
++ goto err_blink;
++
++ /*
+ * Check to see if the board failed any self tests.
+ */
+ if (unlikely(status & SELF_TEST_FAILED))
+- return -1;
++ goto err_out;
+
+ /*
+- * Check to see if the board panic'd.
++ * Check to see if the board failed any self tests.
+ */
+- if (unlikely(status & KERNEL_PANIC))
+- return (status >> 16) & 0xFF;
++ if (unlikely(status & MONITOR_PANIC))
++ goto err_out;
++
+ /*
+ * Wait for the adapter to be up and running.
+ */
+@@ -432,6 +439,12 @@ static int aac_src_check_health(struct aac_dev *dev)
+ * Everything is OK
+ */
+ return 0;
++
++err_out:
++ return -1;
++
++err_blink:
++ return (status > 16) & 0xFF;
+ }
+
+ /**
+diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
+index 33ec4fa39ccb..f224cdb2fce4 100644
+--- a/drivers/scsi/lpfc/lpfc_hw4.h
++++ b/drivers/scsi/lpfc/lpfc_hw4.h
+@@ -1182,6 +1182,7 @@ struct lpfc_mbx_wq_create {
+ #define lpfc_mbx_wq_create_page_size_SHIFT 0
+ #define lpfc_mbx_wq_create_page_size_MASK 0x000000FF
+ #define lpfc_mbx_wq_create_page_size_WORD word1
++#define LPFC_WQ_PAGE_SIZE_4096 0x1
+ #define lpfc_mbx_wq_create_wqe_size_SHIFT 8
+ #define lpfc_mbx_wq_create_wqe_size_MASK 0x0000000F
+ #define lpfc_mbx_wq_create_wqe_size_WORD word1
+@@ -1253,6 +1254,7 @@ struct rq_context {
+ #define lpfc_rq_context_page_size_SHIFT 0 /* Version 1 Only */
+ #define lpfc_rq_context_page_size_MASK 0x000000FF
+ #define lpfc_rq_context_page_size_WORD word0
++#define LPFC_RQ_PAGE_SIZE_4096 0x1
+ uint32_t reserved1;
+ uint32_t word2;
+ #define lpfc_rq_context_cq_id_SHIFT 16
+diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
+index 92dfd6a5178c..f5aeda8f014f 100644
+--- a/drivers/scsi/lpfc/lpfc_sli.c
++++ b/drivers/scsi/lpfc/lpfc_sli.c
+@@ -13475,7 +13475,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
+ LPFC_WQ_WQE_SIZE_128);
+ bf_set(lpfc_mbx_wq_create_page_size,
+ &wq_create->u.request_1,
+- (PAGE_SIZE/SLI4_PAGE_SIZE));
++ LPFC_WQ_PAGE_SIZE_4096);
+ page = wq_create->u.request_1.page;
+ break;
+ }
+@@ -13501,8 +13501,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
+ LPFC_WQ_WQE_SIZE_128);
+ break;
+ }
+- bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1,
+- (PAGE_SIZE/SLI4_PAGE_SIZE));
++ bf_set(lpfc_mbx_wq_create_page_size,
++ &wq_create->u.request_1,
++ LPFC_WQ_PAGE_SIZE_4096);
+ page = wq_create->u.request_1.page;
+ break;
+ default:
+@@ -13688,7 +13689,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
+ LPFC_RQE_SIZE_8);
+ bf_set(lpfc_rq_context_page_size,
+ &rq_create->u.request.context,
+- (PAGE_SIZE/SLI4_PAGE_SIZE));
++ LPFC_RQ_PAGE_SIZE_4096);
+ } else {
+ switch (hrq->entry_count) {
+ default:
+diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
+index e7649ed3f667..4d655b568269 100644
+--- a/drivers/scsi/scsi_dh.c
++++ b/drivers/scsi/scsi_dh.c
+@@ -289,20 +289,6 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
+ }
+ EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
+
+-static struct scsi_device *get_sdev_from_queue(struct request_queue *q)
+-{
+- struct scsi_device *sdev;
+- unsigned long flags;
+-
+- spin_lock_irqsave(q->queue_lock, flags);
+- sdev = q->queuedata;
+- if (!sdev || !get_device(&sdev->sdev_gendev))
+- sdev = NULL;
+- spin_unlock_irqrestore(q->queue_lock, flags);
+-
+- return sdev;
+-}
+-
+ /*
+ * scsi_dh_activate - activate the path associated with the scsi_device
+ * corresponding to the given request queue.
+@@ -321,7 +307,7 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
+ struct scsi_device *sdev;
+ int err = SCSI_DH_NOSYS;
+
+- sdev = get_sdev_from_queue(q);
++ sdev = scsi_device_from_queue(q);
+ if (!sdev) {
+ if (fn)
+ fn(data, err);
+@@ -368,7 +354,7 @@ int scsi_dh_set_params(struct request_queue *q, const char *params)
+ struct scsi_device *sdev;
+ int err = -SCSI_DH_NOSYS;
+
+- sdev = get_sdev_from_queue(q);
++ sdev = scsi_device_from_queue(q);
+ if (!sdev)
+ return err;
+
+@@ -391,7 +377,7 @@ int scsi_dh_attach(struct request_queue *q, const char *name)
+ struct scsi_device_handler *scsi_dh;
+ int err = 0;
+
+- sdev = get_sdev_from_queue(q);
++ sdev = scsi_device_from_queue(q);
+ if (!sdev)
+ return -ENODEV;
+
+@@ -429,7 +415,7 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
+ struct scsi_device *sdev;
+ const char *handler_name = NULL;
+
+- sdev = get_sdev_from_queue(q);
++ sdev = scsi_device_from_queue(q);
+ if (!sdev)
+ return NULL;
+
+diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+index 8558e3886960..887045ae5d10 100644
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -2215,6 +2215,29 @@ void scsi_mq_destroy_tags(struct Scsi_Host *shost)
+ blk_mq_free_tag_set(&shost->tag_set);
+ }
+
++/**
++ * scsi_device_from_queue - return sdev associated with a request_queue
++ * @q: The request queue to return the sdev from
++ *
++ * Return the sdev associated with a request queue or NULL if the
++ * request_queue does not reference a SCSI device.
++ */
++struct scsi_device *scsi_device_from_queue(struct request_queue *q)
++{
++ struct scsi_device *sdev = NULL;
++
++ if (q->mq_ops) {
++ if (q->mq_ops == &scsi_mq_ops)
++ sdev = q->queuedata;
++ } else if (q->request_fn == scsi_request_fn)
++ sdev = q->queuedata;
++ if (!sdev || !get_device(&sdev->sdev_gendev))
++ sdev = NULL;
++
++ return sdev;
++}
++EXPORT_SYMBOL_GPL(scsi_device_from_queue);
++
+ /*
+ * Function: scsi_block_requests()
+ *
+diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
+index 6ee50742f6a5..78430ef28ea4 100644
+--- a/drivers/scsi/sd.c
++++ b/drivers/scsi/sd.c
+@@ -1398,11 +1398,15 @@ static int media_not_present(struct scsi_disk *sdkp,
+ **/
+ static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing)
+ {
+- struct scsi_disk *sdkp = scsi_disk(disk);
+- struct scsi_device *sdp = sdkp->device;
++ struct scsi_disk *sdkp = scsi_disk_get(disk);
++ struct scsi_device *sdp;
+ struct scsi_sense_hdr *sshdr = NULL;
+ int retval;
+
++ if (!sdkp)
++ return 0;
++
++ sdp = sdkp->device;
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n"));
+
+ /*
+@@ -1459,6 +1463,7 @@ out:
+ kfree(sshdr);
+ retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
+ sdp->changed = 0;
++ scsi_disk_put(sdkp);
+ return retval;
+ }
+
+diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
+index 0f636cc4c809..cd5c1c060481 100644
+--- a/drivers/scsi/storvsc_drv.c
++++ b/drivers/scsi/storvsc_drv.c
+@@ -135,6 +135,8 @@ struct hv_fc_wwn_packet {
+ #define SRB_FLAGS_PORT_DRIVER_RESERVED 0x0F000000
+ #define SRB_FLAGS_CLASS_DRIVER_RESERVED 0xF0000000
+
++#define SP_UNTAGGED ((unsigned char) ~0)
++#define SRB_SIMPLE_TAG_REQUEST 0x20
+
+ /*
+ * Platform neutral description of a scsi request -
+@@ -354,6 +356,7 @@ enum storvsc_request_type {
+ #define SRB_STATUS_SUCCESS 0x01
+ #define SRB_STATUS_ABORTED 0x02
+ #define SRB_STATUS_ERROR 0x04
++#define SRB_STATUS_DATA_OVERRUN 0x12
+
+ #define SRB_STATUS(status) \
+ (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
+@@ -864,6 +867,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
+ switch (SRB_STATUS(vm_srb->srb_status)) {
+ case SRB_STATUS_ERROR:
+ /*
++ * Let upper layer deal with error when
++ * sense message is present.
++ */
++
++ if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)
++ break;
++ /*
+ * If there is an error; offline the device since all
+ * error recovery strategies would have already been
+ * deployed on the host side. However, if the command
+@@ -927,6 +937,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
+ struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
+ struct scsi_sense_hdr sense_hdr;
+ struct vmscsi_request *vm_srb;
++ u32 data_transfer_length;
+ struct Scsi_Host *host;
+ struct storvsc_device *stor_dev;
+ struct hv_device *dev = host_dev->dev;
+@@ -937,6 +948,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
+ host = stor_dev->host;
+
+ vm_srb = &cmd_request->vstor_packet.vm_srb;
++ data_transfer_length = vm_srb->data_transfer_length;
+
+ scmnd->result = vm_srb->scsi_status;
+
+@@ -947,13 +959,20 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
+ &sense_hdr);
+ }
+
+- if (vm_srb->srb_status != SRB_STATUS_SUCCESS)
++ if (vm_srb->srb_status != SRB_STATUS_SUCCESS) {
+ storvsc_handle_error(vm_srb, scmnd, host, sense_hdr.asc,
+ sense_hdr.ascq);
++ /*
++ * The Windows driver set data_transfer_length on
++ * SRB_STATUS_DATA_OVERRUN. On other errors, this value
++ * is untouched. In these cases we set it to 0.
++ */
++ if (vm_srb->srb_status != SRB_STATUS_DATA_OVERRUN)
++ data_transfer_length = 0;
++ }
+
+ scsi_set_resid(scmnd,
+- cmd_request->payload->range.len -
+- vm_srb->data_transfer_length);
++ cmd_request->payload->range.len - data_transfer_length);
+
+ scmnd->scsi_done(scmnd);
+
+@@ -1409,6 +1428,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
+ vm_srb->win8_extension.srb_flags |=
+ SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
++ if (scmnd->device->tagged_supported) {
++ vm_srb->win8_extension.srb_flags |=
++ (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE);
++ vm_srb->win8_extension.queue_tag = SP_UNTAGGED;
++ vm_srb->win8_extension.queue_action = SRB_SIMPLE_TAG_REQUEST;
++ }
++
+ /* Build the SRB */
+ switch (scmnd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c
+index 110b8c0b6cd7..0f2fe34e14c2 100644
+--- a/drivers/staging/rtl8188eu/core/rtw_recv.c
++++ b/drivers/staging/rtl8188eu/core/rtw_recv.c
+@@ -1405,6 +1405,9 @@ static int wlanhdr_to_ethhdr(struct recv_frame *precvframe)
+ ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
+ }
+
++ if (!ptr)
++ return _FAIL;
++
+ memcpy(ptr, pattrib->dst, ETH_ALEN);
+ memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN);
+
+diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
+index 4ff530155187..04ac23cc47a8 100644
+--- a/drivers/staging/rtl8712/rtl871x_recv.c
++++ b/drivers/staging/rtl8712/rtl871x_recv.c
+@@ -641,11 +641,16 @@ sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe)
+ /* append rx status for mp test packets */
+ ptr = recvframe_pull(precvframe, (rmv_len -
+ sizeof(struct ethhdr) + 2) - 24);
++ if (!ptr)
++ return _FAIL;
+ memcpy(ptr, get_rxmem(precvframe), 24);
+ ptr += 24;
+- } else
++ } else {
+ ptr = recvframe_pull(precvframe, (rmv_len -
+ sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
++ if (!ptr)
++ return _FAIL;
++ }
+
+ memcpy(ptr, pattrib->dst, ETH_ALEN);
+ memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN);
+diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
+index bd810c109277..6ed80b05d674 100644
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -3436,7 +3436,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
+
+ if ((tpg->tpg_attrib.generate_node_acls == 0) &&
+ (tpg->tpg_attrib.demo_mode_discovery == 0) &&
+- (!core_tpg_get_initiator_node_acl(&tpg->tpg_se_tpg,
++ (!target_tpg_has_node_acl(&tpg->tpg_se_tpg,
+ cmd->conn->sess->sess_ops->InitiatorName))) {
+ continue;
+ }
+diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
+index 5fb9dd7f08bb..028854cda97b 100644
+--- a/drivers/target/target_core_tpg.c
++++ b/drivers/target/target_core_tpg.c
+@@ -75,9 +75,21 @@ struct se_node_acl *core_tpg_get_initiator_node_acl(
+ unsigned char *initiatorname)
+ {
+ struct se_node_acl *acl;
+-
++ /*
++ * Obtain se_node_acl->acl_kref using fabric driver provided
++ * initiatorname[] during node acl endpoint lookup driven by
++ * new se_session login.
++ *
++ * The reference is held until se_session shutdown -> release
++ * occurs via fabric driver invoked transport_deregister_session()
++ * or transport_free_session() code.
++ */
+ mutex_lock(&tpg->acl_node_mutex);
+ acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
++ if (acl) {
++ if (!kref_get_unless_zero(&acl->acl_kref))
++ acl = NULL;
++ }
+ mutex_unlock(&tpg->acl_node_mutex);
+
+ return acl;
+@@ -232,6 +244,25 @@ static void target_add_node_acl(struct se_node_acl *acl)
+ acl->initiatorname);
+ }
+
++bool target_tpg_has_node_acl(struct se_portal_group *tpg,
++ const char *initiatorname)
++{
++ struct se_node_acl *acl;
++ bool found = false;
++
++ mutex_lock(&tpg->acl_node_mutex);
++ list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
++ if (!strcmp(acl->initiatorname, initiatorname)) {
++ found = true;
++ break;
++ }
++ }
++ mutex_unlock(&tpg->acl_node_mutex);
++
++ return found;
++}
++EXPORT_SYMBOL(target_tpg_has_node_acl);
++
+ struct se_node_acl *core_tpg_check_initiator_node_acl(
+ struct se_portal_group *tpg,
+ unsigned char *initiatorname)
+@@ -248,6 +279,15 @@ struct se_node_acl *core_tpg_check_initiator_node_acl(
+ acl = target_alloc_node_acl(tpg, initiatorname);
+ if (!acl)
+ return NULL;
++ /*
++ * When allocating a dynamically generated node_acl, go ahead
++ * and take the extra kref now before returning to the fabric
++ * driver caller.
++ *
++ * Note this reference will be released at session shutdown
++ * time within transport_free_session() code.
++ */
++ kref_get(&acl->acl_kref);
+ acl->dynamic_node_acl = 1;
+
+ /*
+diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
+index aa517c4fadb9..befe22744802 100644
+--- a/drivers/target/target_core_transport.c
++++ b/drivers/target/target_core_transport.c
+@@ -341,7 +341,6 @@ void __transport_register_session(
+ &buf[0], PR_REG_ISID_LEN);
+ se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]);
+ }
+- kref_get(&se_nacl->acl_kref);
+
+ spin_lock_irq(&se_nacl->nacl_sess_lock);
+ /*
+@@ -424,14 +423,27 @@ static void target_complete_nacl(struct kref *kref)
+ {
+ struct se_node_acl *nacl = container_of(kref,
+ struct se_node_acl, acl_kref);
++ struct se_portal_group *se_tpg = nacl->se_tpg;
+
+- complete(&nacl->acl_free_comp);
++ if (!nacl->dynamic_stop) {
++ complete(&nacl->acl_free_comp);
++ return;
++ }
++
++ mutex_lock(&se_tpg->acl_node_mutex);
++ list_del(&nacl->acl_list);
++ mutex_unlock(&se_tpg->acl_node_mutex);
++
++ core_tpg_wait_for_nacl_pr_ref(nacl);
++ core_free_device_list_for_node(nacl, se_tpg);
++ kfree(nacl);
+ }
+
+ void target_put_nacl(struct se_node_acl *nacl)
+ {
+ kref_put(&nacl->acl_kref, target_complete_nacl);
+ }
++EXPORT_SYMBOL(target_put_nacl);
+
+ void transport_deregister_session_configfs(struct se_session *se_sess)
+ {
+@@ -464,6 +476,42 @@ EXPORT_SYMBOL(transport_deregister_session_configfs);
+
+ void transport_free_session(struct se_session *se_sess)
+ {
++ struct se_node_acl *se_nacl = se_sess->se_node_acl;
++
++ /*
++ * Drop the se_node_acl->nacl_kref obtained from within
++ * core_tpg_get_initiator_node_acl().
++ */
++ if (se_nacl) {
++ struct se_portal_group *se_tpg = se_nacl->se_tpg;
++ const struct target_core_fabric_ops *se_tfo = se_tpg->se_tpg_tfo;
++ unsigned long flags;
++
++ se_sess->se_node_acl = NULL;
++
++ /*
++ * Also determine if we need to drop the extra ->cmd_kref if
++ * it had been previously dynamically generated, and
++ * the endpoint is not caching dynamic ACLs.
++ */
++ mutex_lock(&se_tpg->acl_node_mutex);
++ if (se_nacl->dynamic_node_acl &&
++ !se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
++ spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags);
++ if (list_empty(&se_nacl->acl_sess_list))
++ se_nacl->dynamic_stop = true;
++ spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags);
++
++ if (se_nacl->dynamic_stop)
++ list_del(&se_nacl->acl_list);
++ }
++ mutex_unlock(&se_tpg->acl_node_mutex);
++
++ if (se_nacl->dynamic_stop)
++ target_put_nacl(se_nacl);
++
++ target_put_nacl(se_nacl);
++ }
+ if (se_sess->sess_cmd_map) {
+ percpu_ida_destroy(&se_sess->sess_tag_pool);
+ kvfree(se_sess->sess_cmd_map);
+@@ -475,16 +523,12 @@ EXPORT_SYMBOL(transport_free_session);
+ void transport_deregister_session(struct se_session *se_sess)
+ {
+ struct se_portal_group *se_tpg = se_sess->se_tpg;
+- const struct target_core_fabric_ops *se_tfo;
+- struct se_node_acl *se_nacl;
+ unsigned long flags;
+- bool comp_nacl = true, drop_nacl = false;
+
+ if (!se_tpg) {
+ transport_free_session(se_sess);
+ return;
+ }
+- se_tfo = se_tpg->se_tpg_tfo;
+
+ spin_lock_irqsave(&se_tpg->session_lock, flags);
+ list_del(&se_sess->sess_list);
+@@ -492,37 +536,16 @@ void transport_deregister_session(struct se_session *se_sess)
+ se_sess->fabric_sess_ptr = NULL;
+ spin_unlock_irqrestore(&se_tpg->session_lock, flags);
+
+- /*
+- * Determine if we need to do extra work for this initiator node's
+- * struct se_node_acl if it had been previously dynamically generated.
+- */
+- se_nacl = se_sess->se_node_acl;
+-
+- mutex_lock(&se_tpg->acl_node_mutex);
+- if (se_nacl && se_nacl->dynamic_node_acl) {
+- if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
+- list_del(&se_nacl->acl_list);
+- se_tpg->num_node_acls--;
+- drop_nacl = true;
+- }
+- }
+- mutex_unlock(&se_tpg->acl_node_mutex);
+-
+- if (drop_nacl) {
+- core_tpg_wait_for_nacl_pr_ref(se_nacl);
+- core_free_device_list_for_node(se_nacl, se_tpg);
+- kfree(se_nacl);
+- comp_nacl = false;
+- }
+ pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n",
+ se_tpg->se_tpg_tfo->get_fabric_name());
+ /*
+ * If last kref is dropping now for an explicit NodeACL, awake sleeping
+ * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group
+- * removal context.
++ * removal context from within transport_free_session() code.
++ *
++ * For dynamic ACL, target_put_nacl() uses target_complete_nacl()
++ * to release all remaining generate_node_acl=1 created ACL resources.
+ */
+- if (se_nacl && comp_nacl)
+- target_put_nacl(se_nacl);
+
+ transport_free_session(se_sess);
+ }
+diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
+index aab5221d6c2e..aac0ce8aeb0b 100644
+--- a/drivers/usb/gadget/udc/fsl_udc_core.c
++++ b/drivers/usb/gadget/udc/fsl_udc_core.c
+@@ -1249,6 +1249,12 @@ static const struct usb_gadget_ops fsl_gadget_ops = {
+ .udc_stop = fsl_udc_stop,
+ };
+
++/*
++ * Empty complete function used by this driver to fill in the req->complete
++ * field when creating a request since the complete field is mandatory.
++ */
++static void fsl_noop_complete(struct usb_ep *ep, struct usb_request *req) { }
++
+ /* Set protocol stall on ep0, protocol stall will automatically be cleared
+ on new transaction */
+ static void ep0stall(struct fsl_udc *udc)
+@@ -1283,7 +1289,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
+ req->req.length = 0;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+- req->req.complete = NULL;
++ req->req.complete = fsl_noop_complete;
+ req->dtd_count = 0;
+
+ ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+@@ -1366,7 +1372,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
+ req->req.length = 2;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+- req->req.complete = NULL;
++ req->req.complete = fsl_noop_complete;
+ req->dtd_count = 0;
+
+ ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
+index 4fe7c9b56bc0..19cb32a65161 100644
+--- a/drivers/usb/host/xhci-plat.c
++++ b/drivers/usb/host/xhci-plat.c
+@@ -162,9 +162,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
+ (pdata && pdata->usb3_lpm_capable))
+ xhci->quirks |= XHCI_LPM_SUPPORT;
+
+- if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
+- xhci->shared_hcd->can_do_streams = 1;
+-
+ hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
+ if (IS_ERR(hcd->usb_phy)) {
+ ret = PTR_ERR(hcd->usb_phy);
+@@ -181,6 +178,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
+ if (ret)
+ goto disable_usb_phy;
+
++ if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
++ xhci->shared_hcd->can_do_streams = 1;
++
+ ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+ if (ret)
+ goto dealloc_usb2_hcd;
+diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
+index b03d3b867fca..9a9c82a4d35d 100644
+--- a/drivers/usb/musb/da8xx.c
++++ b/drivers/usb/musb/da8xx.c
+@@ -458,15 +458,11 @@ static int da8xx_musb_exit(struct musb *musb)
+ }
+
+ static const struct musb_platform_ops da8xx_ops = {
+- .quirks = MUSB_DMA_CPPI | MUSB_INDEXED_EP,
++ .quirks = MUSB_INDEXED_EP,
+ .init = da8xx_musb_init,
+ .exit = da8xx_musb_exit,
+
+ .fifo_mode = 2,
+-#ifdef CONFIG_USB_TI_CPPI_DMA
+- .dma_init = cppi_dma_controller_create,
+- .dma_exit = cppi_dma_controller_destroy,
+-#endif
+ .enable = da8xx_musb_enable,
+ .disable = da8xx_musb_disable,
+
+diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
+index 049a884a756f..59d74d1b47a8 100644
+--- a/drivers/w1/masters/ds2490.c
++++ b/drivers/w1/masters/ds2490.c
+@@ -153,6 +153,9 @@ struct ds_device
+ */
+ u16 spu_bit;
+
++ u8 st_buf[ST_SIZE];
++ u8 byte_buf;
++
+ struct w1_bus_master master;
+ };
+
+@@ -174,7 +177,6 @@ struct ds_status
+ u8 data_in_buffer_status;
+ u8 reserved1;
+ u8 reserved2;
+-
+ };
+
+ static struct usb_device_id ds_id_table [] = {
+@@ -244,28 +246,6 @@ static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
+ return err;
+ }
+
+-static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
+- unsigned char *buf, int size)
+-{
+- int count, err;
+-
+- memset(st, 0, sizeof(*st));
+-
+- count = 0;
+- err = usb_interrupt_msg(dev->udev, usb_rcvintpipe(dev->udev,
+- dev->ep[EP_STATUS]), buf, size, &count, 1000);
+- if (err < 0) {
+- pr_err("Failed to read 1-wire data from 0x%x: err=%d.\n",
+- dev->ep[EP_STATUS], err);
+- return err;
+- }
+-
+- if (count >= sizeof(*st))
+- memcpy(st, buf, sizeof(*st));
+-
+- return count;
+-}
+-
+ static inline void ds_print_msg(unsigned char *buf, unsigned char *str, int off)
+ {
+ pr_info("%45s: %8x\n", str, buf[off]);
+@@ -324,6 +304,35 @@ static void ds_dump_status(struct ds_device *dev, unsigned char *buf, int count)
+ }
+ }
+
++static int ds_recv_status(struct ds_device *dev, struct ds_status *st,
++ bool dump)
++{
++ int count, err;
++
++ if (st)
++ memset(st, 0, sizeof(*st));
++
++ count = 0;
++ err = usb_interrupt_msg(dev->udev,
++ usb_rcvintpipe(dev->udev,
++ dev->ep[EP_STATUS]),
++ dev->st_buf, sizeof(dev->st_buf),
++ &count, 1000);
++ if (err < 0) {
++ pr_err("Failed to read 1-wire data from 0x%x: err=%d.\n",
++ dev->ep[EP_STATUS], err);
++ return err;
++ }
++
++ if (dump)
++ ds_dump_status(dev, dev->st_buf, count);
++
++ if (st && count >= sizeof(*st))
++ memcpy(st, dev->st_buf, sizeof(*st));
++
++ return count;
++}
++
+ static void ds_reset_device(struct ds_device *dev)
+ {
+ ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
+@@ -344,7 +353,6 @@ static void ds_reset_device(struct ds_device *dev)
+ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
+ {
+ int count, err;
+- struct ds_status st;
+
+ /* Careful on size. If size is less than what is available in
+ * the input buffer, the device fails the bulk transfer and
+@@ -359,14 +367,9 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
+ err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
+ buf, size, &count, 1000);
+ if (err < 0) {
+- u8 buf[ST_SIZE];
+- int count;
+-
+ pr_info("Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
+ usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
+-
+- count = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
+- ds_dump_status(dev, buf, count);
++ ds_recv_status(dev, NULL, true);
+ return err;
+ }
+
+@@ -404,7 +407,6 @@ int ds_stop_pulse(struct ds_device *dev, int limit)
+ {
+ struct ds_status st;
+ int count = 0, err = 0;
+- u8 buf[ST_SIZE];
+
+ do {
+ err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
+@@ -413,7 +415,7 @@ int ds_stop_pulse(struct ds_device *dev, int limit)
+ err = ds_send_control(dev, CTL_RESUME_EXE, 0);
+ if (err)
+ break;
+- err = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
++ err = ds_recv_status(dev, &st, false);
+ if (err)
+ break;
+
+@@ -456,18 +458,17 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
+
+ static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
+ {
+- u8 buf[ST_SIZE];
+ int err, count = 0;
+
+ do {
+ st->status = 0;
+- err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
++ err = ds_recv_status(dev, st, false);
+ #if 0
+ if (err >= 0) {
+ int i;
+ printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
+ for (i=0; i<err; ++i)
+- printk("%02x ", buf[i]);
++ printk("%02x ", dev->st_buf[i]);
+ printk("\n");
+ }
+ #endif
+@@ -485,7 +486,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
+ * can do something with it).
+ */
+ if (err > 16 || count >= 100 || err < 0)
+- ds_dump_status(dev, buf, err);
++ ds_dump_status(dev, dev->st_buf, err);
+
+ /* Extended data isn't an error. Well, a short is, but the dump
+ * would have already told the user that and we can't do anything
+@@ -608,7 +609,6 @@ static int ds_write_byte(struct ds_device *dev, u8 byte)
+ {
+ int err;
+ struct ds_status st;
+- u8 rbyte;
+
+ err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | dev->spu_bit, byte);
+ if (err)
+@@ -621,11 +621,11 @@ static int ds_write_byte(struct ds_device *dev, u8 byte)
+ if (err)
+ return err;
+
+- err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
++ err = ds_recv_data(dev, &dev->byte_buf, 1);
+ if (err < 0)
+ return err;
+
+- return !(byte == rbyte);
++ return !(byte == dev->byte_buf);
+ }
+
+ static int ds_read_byte(struct ds_device *dev, u8 *byte)
+@@ -712,7 +712,6 @@ static void ds9490r_search(void *data, struct w1_master *master,
+ int err;
+ u16 value, index;
+ struct ds_status st;
+- u8 st_buf[ST_SIZE];
+ int search_limit;
+ int found = 0;
+ int i;
+@@ -724,7 +723,12 @@ static void ds9490r_search(void *data, struct w1_master *master,
+ /* FIFO 128 bytes, bulk packet size 64, read a multiple of the
+ * packet size.
+ */
+- u64 buf[2*64/8];
++ const size_t bufsize = 2 * 64;
++ u64 *buf;
++
++ buf = kmalloc(bufsize, GFP_KERNEL);
++ if (!buf)
++ return;
+
+ mutex_lock(&master->bus_mutex);
+
+@@ -745,10 +749,9 @@ static void ds9490r_search(void *data, struct w1_master *master,
+ do {
+ schedule_timeout(jtime);
+
+- if (ds_recv_status_nodump(dev, &st, st_buf, sizeof(st_buf)) <
+- sizeof(st)) {
++ err = ds_recv_status(dev, &st, false);
++ if (err < 0 || err < sizeof(st))
+ break;
+- }
+
+ if (st.data_in_buffer_status) {
+ /* Bulk in can receive partial ids, but when it does
+@@ -758,7 +761,7 @@ static void ds9490r_search(void *data, struct w1_master *master,
+ * bulk without first checking if status says there
+ * is data to read.
+ */
+- err = ds_recv_data(dev, (u8 *)buf, sizeof(buf));
++ err = ds_recv_data(dev, (u8 *)buf, bufsize);
+ if (err < 0)
+ break;
+ for (i = 0; i < err/8; ++i) {
+@@ -794,9 +797,14 @@ static void ds9490r_search(void *data, struct w1_master *master,
+ }
+ search_out:
+ mutex_unlock(&master->bus_mutex);
++ kfree(buf);
+ }
+
+ #if 0
++/*
++ * FIXME: if this disabled code is ever used in the future all ds_send_data()
++ * calls must be changed to use a DMAable buffer.
++ */
+ static int ds_match_access(struct ds_device *dev, u64 init)
+ {
+ int err;
+@@ -845,13 +853,12 @@ static int ds_set_path(struct ds_device *dev, u64 init)
+
+ static u8 ds9490r_touch_bit(void *data, u8 bit)
+ {
+- u8 ret;
+ struct ds_device *dev = data;
+
+- if (ds_touch_bit(dev, bit, &ret))
++ if (ds_touch_bit(dev, bit, &dev->byte_buf))
+ return 0;
+
+- return ret;
++ return dev->byte_buf;
+ }
+
+ #if 0
+@@ -866,13 +873,12 @@ static u8 ds9490r_read_bit(void *data)
+ {
+ struct ds_device *dev = data;
+ int err;
+- u8 bit = 0;
+
+- err = ds_touch_bit(dev, 1, &bit);
++ err = ds_touch_bit(dev, 1, &dev->byte_buf);
+ if (err)
+ return 0;
+
+- return bit & 1;
++ return dev->byte_buf & 1;
+ }
+ #endif
+
+@@ -887,32 +893,52 @@ static u8 ds9490r_read_byte(void *data)
+ {
+ struct ds_device *dev = data;
+ int err;
+- u8 byte = 0;
+
+- err = ds_read_byte(dev, &byte);
++ err = ds_read_byte(dev, &dev->byte_buf);
+ if (err)
+ return 0;
+
+- return byte;
++ return dev->byte_buf;
+ }
+
+ static void ds9490r_write_block(void *data, const u8 *buf, int len)
+ {
+ struct ds_device *dev = data;
++ u8 *tbuf;
++
++ if (len <= 0)
++ return;
++
++ tbuf = kmalloc(len, GFP_KERNEL);
++ if (!tbuf)
++ return;
+
+- ds_write_block(dev, (u8 *)buf, len);
++ memcpy(tbuf, buf, len);
++ ds_write_block(dev, tbuf, len);
++
++ kfree(tbuf);
+ }
+
+ static u8 ds9490r_read_block(void *data, u8 *buf, int len)
+ {
+ struct ds_device *dev = data;
+ int err;
++ u8 *tbuf;
+
+- err = ds_read_block(dev, buf, len);
+- if (err < 0)
++ if (len <= 0)
++ return 0;
++
++ tbuf = kmalloc(len, GFP_KERNEL);
++ if (!tbuf)
+ return 0;
+
+- return len;
++ err = ds_read_block(dev, tbuf, len);
++ if (err >= 0)
++ memcpy(buf, tbuf, len);
++
++ kfree(tbuf);
++
++ return err >= 0 ? len : 0;
+ }
+
+ static u8 ds9490r_reset(void *data)
+diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
+index c9a7ff67d395..39886edfa222 100644
+--- a/drivers/w1/w1.c
++++ b/drivers/w1/w1.c
+@@ -763,6 +763,7 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
+ dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
+ sl->name);
+ w1_family_put(sl->family);
++ atomic_dec(&sl->master->refcnt);
+ kfree(sl);
+ return err;
+ }
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index 9da42ace762a..8a456f9b8a44 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -5362,7 +5362,8 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
+ ext4_lblk_t stop, *iterator, ex_start, ex_end;
+
+ /* Let path point to the last extent */
+- path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, 0);
++ path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL,
++ EXT4_EX_NOCACHE);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+@@ -5371,15 +5372,15 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
+ if (!extent)
+ goto out;
+
+- stop = le32_to_cpu(extent->ee_block) +
+- ext4_ext_get_actual_len(extent);
++ stop = le32_to_cpu(extent->ee_block);
+
+ /*
+ * In case of left shift, Don't start shifting extents until we make
+ * sure the hole is big enough to accommodate the shift.
+ */
+ if (SHIFT == SHIFT_LEFT) {
+- path = ext4_find_extent(inode, start - 1, &path, 0);
++ path = ext4_find_extent(inode, start - 1, &path,
++ EXT4_EX_NOCACHE);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+ depth = path->p_depth;
+@@ -5411,9 +5412,14 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
+ else
+ iterator = &stop;
+
+- /* Its safe to start updating extents */
+- while (start < stop) {
+- path = ext4_find_extent(inode, *iterator, &path, 0);
++ /*
++ * Its safe to start updating extents. Start and stop are unsigned, so
++ * in case of right shift if extent with 0 block is reached, iterator
++ * becomes NULL to indicate the end of the loop.
++ */
++ while (iterator && start <= stop) {
++ path = ext4_find_extent(inode, *iterator, &path,
++ EXT4_EX_NOCACHE);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+ depth = path->p_depth;
+@@ -5440,8 +5446,11 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
+ ext4_ext_get_actual_len(extent);
+ } else {
+ extent = EXT_FIRST_EXTENT(path[depth].p_hdr);
+- *iterator = le32_to_cpu(extent->ee_block) > 0 ?
+- le32_to_cpu(extent->ee_block) - 1 : 0;
++ if (le32_to_cpu(extent->ee_block) > 0)
++ *iterator = le32_to_cpu(extent->ee_block) - 1;
++ else
++ /* Beginning is reached, end of the loop */
++ iterator = NULL;
+ /* Update path extent in case we need to stop */
+ while (le32_to_cpu(extent->ee_block) < start)
+ extent++;
+diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
+index 8968a93e2150..d4be4e23bc21 100644
+--- a/fs/ext4/inline.c
++++ b/fs/ext4/inline.c
+@@ -933,8 +933,15 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
+ struct page *page)
+ {
+ int i_size_changed = 0;
++ int ret;
+
+- copied = ext4_write_inline_data_end(inode, pos, len, copied, page);
++ ret = ext4_write_inline_data_end(inode, pos, len, copied, page);
++ if (ret < 0) {
++ unlock_page(page);
++ put_page(page);
++ return ret;
++ }
++ copied = ret;
+
+ /*
+ * No need to use i_size_read() here, the i_size
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 10690e5ba2eb..e0f862146793 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -1165,8 +1165,11 @@ static int ext4_write_end(struct file *file,
+ if (ext4_has_inline_data(inode)) {
+ ret = ext4_write_inline_data_end(inode, pos, len,
+ copied, page);
+- if (ret < 0)
++ if (ret < 0) {
++ unlock_page(page);
++ put_page(page);
+ goto errout;
++ }
+ copied = ret;
+ } else
+ copied = block_write_end(file, mapping, pos,
+@@ -1220,7 +1223,9 @@ errout:
+ * set the buffer to be dirty, since in data=journalled mode we need
+ * to call ext4_handle_dirty_metadata() instead.
+ */
+-static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
++static void ext4_journalled_zero_new_buffers(handle_t *handle,
++ struct page *page,
++ unsigned from, unsigned to)
+ {
+ unsigned int block_start = 0, block_end;
+ struct buffer_head *head, *bh;
+@@ -1237,7 +1242,7 @@ static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
+ size = min(to, block_end) - start;
+
+ zero_user(page, start, size);
+- set_buffer_uptodate(bh);
++ write_end_fn(handle, bh);
+ }
+ clear_buffer_new(bh);
+ }
+@@ -1266,18 +1271,25 @@ static int ext4_journalled_write_end(struct file *file,
+
+ BUG_ON(!ext4_handle_valid(handle));
+
+- if (ext4_has_inline_data(inode))
+- copied = ext4_write_inline_data_end(inode, pos, len,
+- copied, page);
+- else {
+- if (copied < len) {
+- if (!PageUptodate(page))
+- copied = 0;
+- zero_new_buffers(page, from+copied, to);
++ if (ext4_has_inline_data(inode)) {
++ ret = ext4_write_inline_data_end(inode, pos, len,
++ copied, page);
++ if (ret < 0) {
++ unlock_page(page);
++ put_page(page);
++ goto errout;
+ }
+-
++ copied = ret;
++ } else if (unlikely(copied < len) && !PageUptodate(page)) {
++ copied = 0;
++ ext4_journalled_zero_new_buffers(handle, page, from, to);
++ } else {
++ if (unlikely(copied < len))
++ ext4_journalled_zero_new_buffers(handle, page,
++ from + copied, to);
+ ret = ext4_walk_page_buffers(handle, page_buffers(page), from,
+- to, &partial, write_end_fn);
++ from + copied, &partial,
++ write_end_fn);
+ if (!partial)
+ SetPageUptodate(page);
+ }
+@@ -1303,6 +1315,7 @@ static int ext4_journalled_write_end(struct file *file,
+ */
+ ext4_orphan_add(handle, inode);
+
++errout:
+ ret2 = ext4_journal_stop(handle);
+ if (!ret)
+ ret = ret2;
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index b7a3957a9dca..84cd77663e1f 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -3120,6 +3120,13 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
+ if (ar->pright && start + size - 1 >= ar->lright)
+ size -= start + size - ar->lright;
+
++ /*
++ * Trim allocation request for filesystems with artificially small
++ * groups.
++ */
++ if (size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb))
++ size = EXT4_BLOCKS_PER_GROUP(ac->ac_sb);
++
+ end = start + size;
+
+ /* check we don't cross already preallocated blocks */
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index b405a7b74ce0..6fe8e30eeb99 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -793,6 +793,7 @@ static void ext4_put_super(struct super_block *sb)
+ {
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_super_block *es = sbi->s_es;
++ int aborted = 0;
+ int i, err;
+
+ ext4_unregister_li_request(sb);
+@@ -802,9 +803,10 @@ static void ext4_put_super(struct super_block *sb)
+ destroy_workqueue(sbi->rsv_conversion_wq);
+
+ if (sbi->s_journal) {
++ aborted = is_journal_aborted(sbi->s_journal);
+ err = jbd2_journal_destroy(sbi->s_journal);
+ sbi->s_journal = NULL;
+- if (err < 0)
++ if ((err < 0) && !aborted)
+ ext4_abort(sb, "Couldn't clean up the journal");
+ }
+
+@@ -816,7 +818,7 @@ static void ext4_put_super(struct super_block *sb)
+ ext4_ext_release(sb);
+ ext4_xattr_put_super(sb);
+
+- if (!(sb->s_flags & MS_RDONLY)) {
++ if (!(sb->s_flags & MS_RDONLY) && !aborted) {
+ ext4_clear_feature_journal_needs_recovery(sb);
+ es->s_state = cpu_to_le16(sbi->s_mount_state);
+ }
+@@ -3746,7 +3748,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
+ * root first: it may be modified in the journal!
+ */
+ if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) {
+- if (ext4_load_journal(sb, es, journal_devnum))
++ err = ext4_load_journal(sb, es, journal_devnum);
++ if (err)
+ goto failed_mount3a;
+ } else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
+ ext4_has_feature_journal_needs_recovery(sb)) {
+diff --git a/fs/fuse/file.c b/fs/fuse/file.c
+index 8821c380a71a..11538a8be9f0 100644
+--- a/fs/fuse/file.c
++++ b/fs/fuse/file.c
+@@ -100,6 +100,7 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
+ iput(req->misc.release.inode);
+ fuse_put_request(ff->fc, req);
+ } else if (sync) {
++ __set_bit(FR_FORCE, &req->flags);
+ __clear_bit(FR_BACKGROUND, &req->flags);
+ fuse_request_send(ff->fc, req);
+ iput(req->misc.release.inode);
+diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
+index 32e74710b1aa..9cd8c92b953d 100644
+--- a/fs/gfs2/glock.c
++++ b/fs/gfs2/glock.c
+@@ -651,9 +651,11 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
+ struct kmem_cache *cachep;
+ int ret, tries = 0;
+
++ rcu_read_lock();
+ gl = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms);
+ if (gl && !lockref_get_not_dead(&gl->gl_lockref))
+ gl = NULL;
++ rcu_read_unlock();
+
+ *glp = gl;
+ if (gl)
+@@ -721,15 +723,18 @@ again:
+
+ if (ret == -EEXIST) {
+ ret = 0;
++ rcu_read_lock();
+ tmp = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms);
+ if (tmp == NULL || !lockref_get_not_dead(&tmp->gl_lockref)) {
+ if (++tries < 100) {
++ rcu_read_unlock();
+ cond_resched();
+ goto again;
+ }
+ tmp = NULL;
+ ret = -ENOMEM;
+ }
++ rcu_read_unlock();
+ } else {
+ WARN_ON_ONCE(ret);
+ }
+diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
+index fa1b8e0dcacf..a2e724053919 100644
+--- a/fs/jbd2/transaction.c
++++ b/fs/jbd2/transaction.c
+@@ -1876,7 +1876,9 @@ static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
+
+ __blist_del_buffer(list, jh);
+ jh->b_jlist = BJ_None;
+- if (test_clear_buffer_jbddirty(bh))
++ if (transaction && is_journal_aborted(transaction->t_journal))
++ clear_buffer_jbddirty(bh);
++ else if (test_clear_buffer_jbddirty(bh))
+ mark_buffer_dirty(bh); /* Expose it to the VM */
+ }
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 9a524e763c3e..4e3679b25b9b 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -2452,6 +2452,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
+ ret = PTR_ERR(state);
+ if (IS_ERR(state))
+ goto out;
++ ctx->state = state;
+ if (server->caps & NFS_CAP_POSIX_LOCK)
+ set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
+
+@@ -2474,7 +2475,6 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
+ if (ret != 0)
+ goto out;
+
+- ctx->state = state;
+ if (d_inode(dentry) == state->inode) {
+ nfs_inode_attach_open_context(ctx);
+ if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
+@@ -4711,7 +4711,7 @@ out:
+ */
+ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
+ {
+- struct page *pages[NFS4ACL_MAXPAGES] = {NULL, };
++ struct page *pages[NFS4ACL_MAXPAGES + 1] = {NULL, };
+ struct nfs_getaclargs args = {
+ .fh = NFS_FH(inode),
+ .acl_pages = pages,
+@@ -4725,13 +4725,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+- unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
++ unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
+ int ret = -ENOMEM, i;
+
+- /* As long as we're doing a round trip to the server anyway,
+- * let's be prepared for a page of acl data. */
+- if (npages == 0)
+- npages = 1;
+ if (npages > ARRAY_SIZE(pages))
+ return -ERANGE;
+
+diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
+index 4e4441216804..1cb50bb898b0 100644
+--- a/fs/nfs/nfs4xdr.c
++++ b/fs/nfs/nfs4xdr.c
+@@ -2487,7 +2487,7 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
+ encode_compound_hdr(xdr, req, &hdr);
+ encode_sequence(xdr, &args->seq_args, &hdr);
+ encode_putfh(xdr, args->fh, &hdr);
+- replen = hdr.replen + op_decode_hdr_maxsz + 1;
++ replen = hdr.replen + op_decode_hdr_maxsz;
+ encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
+
+ xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
+diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
+index 994d66fbb446..91e0c5429b4d 100644
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -369,7 +369,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
+ __be32 err;
+ int host_err;
+ bool get_write_count;
+- int size_change = 0;
++ bool size_change = (iap->ia_valid & ATTR_SIZE);
+
+ if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
+ accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
+@@ -382,11 +382,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
+ /* Get inode */
+ err = fh_verify(rqstp, fhp, ftype, accmode);
+ if (err)
+- goto out;
++ return err;
+ if (get_write_count) {
+ host_err = fh_want_write(fhp);
+ if (host_err)
+- return nfserrno(host_err);
++ goto out;
+ }
+
+ dentry = fhp->fh_dentry;
+@@ -397,20 +397,28 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
+ iap->ia_valid &= ~ATTR_MODE;
+
+ if (!iap->ia_valid)
+- goto out;
++ return 0;
+
+ nfsd_sanitize_attrs(inode, iap);
+
++ if (check_guard && guardtime != inode->i_ctime.tv_sec)
++ return nfserr_notsync;
++
+ /*
+ * The size case is special, it changes the file in addition to the
+- * attributes.
++ * attributes, and file systems don't expect it to be mixed with
++ * "random" attribute changes. We thus split out the size change
++ * into a separate call to ->setattr, and do the rest as a separate
++ * setattr call.
+ */
+- if (iap->ia_valid & ATTR_SIZE) {
++ if (size_change) {
+ err = nfsd_get_write_access(rqstp, fhp, iap);
+ if (err)
+- goto out;
+- size_change = 1;
++ return err;
++ }
+
++ fh_lock(fhp);
++ if (size_change) {
+ /*
+ * RFC5661, Section 18.30.4:
+ * Changing the size of a file with SETATTR indirectly
+@@ -418,29 +426,36 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
+ *
+ * (and similar for the older RFCs)
+ */
+- if (iap->ia_size != i_size_read(inode))
+- iap->ia_valid |= ATTR_MTIME;
+- }
++ struct iattr size_attr = {
++ .ia_valid = ATTR_SIZE | ATTR_CTIME | ATTR_MTIME,
++ .ia_size = iap->ia_size,
++ };
+
+- iap->ia_valid |= ATTR_CTIME;
++ host_err = notify_change(dentry, &size_attr, NULL);
++ if (host_err)
++ goto out_unlock;
++ iap->ia_valid &= ~ATTR_SIZE;
+
+- if (check_guard && guardtime != inode->i_ctime.tv_sec) {
+- err = nfserr_notsync;
+- goto out_put_write_access;
++ /*
++ * Avoid the additional setattr call below if the only other
++ * attribute that the client sends is the mtime, as we update
++ * it as part of the size change above.
++ */
++ if ((iap->ia_valid & ~ATTR_MTIME) == 0)
++ goto out_unlock;
+ }
+
+- fh_lock(fhp);
++ iap->ia_valid |= ATTR_CTIME;
+ host_err = notify_change(dentry, iap, NULL);
+- fh_unlock(fhp);
+- err = nfserrno(host_err);
+
+-out_put_write_access:
++out_unlock:
++ fh_unlock(fhp);
+ if (size_change)
+ put_write_access(inode);
+- if (!err)
+- err = nfserrno(commit_metadata(fhp));
+ out:
+- return err;
++ if (!host_err)
++ host_err = commit_metadata(fhp);
++ return nfserrno(host_err);
+ }
+
+ #if defined(CONFIG_NFSD_V4)
+diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
+index d49e26c6cdc7..23e129ef6726 100644
+--- a/include/linux/intel-iommu.h
++++ b/include/linux/intel-iommu.h
+@@ -153,8 +153,8 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
+ #define DMA_TLB_GLOBAL_FLUSH (((u64)1) << 60)
+ #define DMA_TLB_DSI_FLUSH (((u64)2) << 60)
+ #define DMA_TLB_PSI_FLUSH (((u64)3) << 60)
+-#define DMA_TLB_IIRG(type) ((type >> 60) & 7)
+-#define DMA_TLB_IAIG(val) (((val) >> 57) & 7)
++#define DMA_TLB_IIRG(type) ((type >> 60) & 3)
++#define DMA_TLB_IAIG(val) (((val) >> 57) & 3)
+ #define DMA_TLB_READ_DRAIN (((u64)1) << 49)
+ #define DMA_TLB_WRITE_DRAIN (((u64)1) << 48)
+ #define DMA_TLB_DID(id) (((u64)((id) & 0xffff)) << 32)
+@@ -164,9 +164,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
+
+ /* INVALID_DESC */
+ #define DMA_CCMD_INVL_GRANU_OFFSET 61
+-#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 3)
+-#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 3)
+-#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 3)
++#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 4)
++#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 4)
++#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 4)
+ #define DMA_ID_TLB_READ_DRAIN (((u64)1) << 7)
+ #define DMA_ID_TLB_WRITE_DRAIN (((u64)1) << 6)
+ #define DMA_ID_TLB_DID(id) (((u64)((id & 0xffff) << 16)))
+@@ -316,8 +316,8 @@ enum {
+ #define QI_DEV_EIOTLB_SIZE (((u64)1) << 11)
+ #define QI_DEV_EIOTLB_GLOB(g) ((u64)g)
+ #define QI_DEV_EIOTLB_PASID(p) (((u64)p) << 32)
+-#define QI_DEV_EIOTLB_SID(sid) ((u64)((sid) & 0xffff) << 32)
+-#define QI_DEV_EIOTLB_QDEP(qd) (((qd) & 0x1f) << 16)
++#define QI_DEV_EIOTLB_SID(sid) ((u64)((sid) & 0xffff) << 16)
++#define QI_DEV_EIOTLB_QDEP(qd) ((u64)((qd) & 0x1f) << 4)
+ #define QI_DEV_EIOTLB_MAX_INVS 32
+
+ #define QI_PGRP_IDX(idx) (((u64)(idx)) << 55)
+diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h
+index 301969552d0a..b43e64d69734 100644
+--- a/include/rdma/ib_sa.h
++++ b/include/rdma/ib_sa.h
+@@ -138,12 +138,12 @@ struct ib_sa_path_rec {
+ union ib_gid sgid;
+ __be16 dlid;
+ __be16 slid;
+- int raw_traffic;
++ u8 raw_traffic;
+ /* reserved */
+ __be32 flow_label;
+ u8 hop_limit;
+ u8 traffic_class;
+- int reversible;
++ u8 reversible;
+ u8 numb_path;
+ __be16 pkey;
+ __be16 qos_class;
+@@ -204,7 +204,7 @@ struct ib_sa_mcmember_rec {
+ u8 hop_limit;
+ u8 scope;
+ u8 join_state;
+- int proxy_join;
++ u8 proxy_join;
+ };
+
+ /* Service Record Component Mask Sec 15.2.5.14 Ver 1.1 */
+diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
+index 4f6ba34cdee6..293b9a7f53bc 100644
+--- a/include/scsi/scsi_device.h
++++ b/include/scsi/scsi_device.h
+@@ -307,6 +307,7 @@ extern void scsi_remove_device(struct scsi_device *);
+ extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh);
+ void scsi_attach_vpd(struct scsi_device *sdev);
+
++extern struct scsi_device *scsi_device_from_queue(struct request_queue *q);
+ extern int scsi_device_get(struct scsi_device *);
+ extern void scsi_device_put(struct scsi_device *);
+ extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *,
+diff --git a/include/soc/at91/at91sam9_ddrsdr.h b/include/soc/at91/at91sam9_ddrsdr.h
+index dc10c52e0e91..393362bdb860 100644
+--- a/include/soc/at91/at91sam9_ddrsdr.h
++++ b/include/soc/at91/at91sam9_ddrsdr.h
+@@ -81,6 +81,7 @@
+ #define AT91_DDRSDRC_LPCB_POWER_DOWN 2
+ #define AT91_DDRSDRC_LPCB_DEEP_POWER_DOWN 3
+ #define AT91_DDRSDRC_CLKFR (1 << 2) /* Clock Frozen */
++#define AT91_DDRSDRC_LPDDR2_PWOFF (1 << 3) /* LPDDR Power Off */
+ #define AT91_DDRSDRC_PASR (7 << 4) /* Partial Array Self Refresh */
+ #define AT91_DDRSDRC_TCSR (3 << 8) /* Temperature Compensated Self Refresh */
+ #define AT91_DDRSDRC_DS (3 << 10) /* Drive Strength */
+@@ -96,7 +97,9 @@
+ #define AT91_DDRSDRC_MD_SDR 0
+ #define AT91_DDRSDRC_MD_LOW_POWER_SDR 1
+ #define AT91_DDRSDRC_MD_LOW_POWER_DDR 3
++#define AT91_DDRSDRC_MD_LPDDR3 5
+ #define AT91_DDRSDRC_MD_DDR2 6 /* [SAM9 Only] */
++#define AT91_DDRSDRC_MD_LPDDR2 7
+ #define AT91_DDRSDRC_DBW (1 << 4) /* Data Bus Width */
+ #define AT91_DDRSDRC_DBW_32BITS (0 << 4)
+ #define AT91_DDRSDRC_DBW_16BITS (1 << 4)
+diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
+index 6afc6f388edf..800fe16cc36f 100644
+--- a/include/target/target_core_base.h
++++ b/include/target/target_core_base.h
+@@ -544,6 +544,7 @@ struct se_node_acl {
+ /* Used to signal demo mode created ACL, disabled by default */
+ bool dynamic_node_acl;
+ bool acl_stop:1;
++ bool dynamic_stop;
+ u32 queue_depth;
+ u32 acl_index;
+ enum target_prot_type saved_prot_type;
+diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
+index ce9ea736f1d7..97069ecabe49 100644
+--- a/include/target/target_core_fabric.h
++++ b/include/target/target_core_fabric.h
+@@ -168,6 +168,8 @@ void core_allocate_nexus_loss_ua(struct se_node_acl *acl);
+
+ struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
+ unsigned char *);
++bool target_tpg_has_node_acl(struct se_portal_group *tpg,
++ const char *);
+ struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *,
+ unsigned char *);
+ int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *,
+diff --git a/ipc/shm.c b/ipc/shm.c
+index 3174634ca4e5..4982a4e7f009 100644
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -1083,8 +1083,8 @@ out_unlock1:
+ * "raddr" thing points to kernel space, and there has to be a wrapper around
+ * this.
+ */
+-long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
+- unsigned long shmlba)
++long do_shmat(int shmid, char __user *shmaddr, int shmflg,
++ ulong *raddr, unsigned long shmlba)
+ {
+ struct shmid_kernel *shp;
+ unsigned long addr;
+@@ -1105,8 +1105,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
+ goto out;
+ else if ((addr = (ulong)shmaddr)) {
+ if (addr & (shmlba - 1)) {
+- if (shmflg & SHM_RND)
+- addr &= ~(shmlba - 1); /* round down */
++ /*
++ * Round down to the nearest multiple of shmlba.
++ * For sane do_mmap_pgoff() parameters, avoid
++ * round downs that trigger nil-page and MAP_FIXED.
++ */
++ if ((shmflg & SHM_RND) && addr >= shmlba)
++ addr &= ~(shmlba - 1);
+ else
+ #ifndef __ARCH_FORCE_SHMLBA
+ if (addr & ~PAGE_MASK)
+diff --git a/kernel/membarrier.c b/kernel/membarrier.c
+index 536c727a56e9..9f9284f37f8d 100644
+--- a/kernel/membarrier.c
++++ b/kernel/membarrier.c
+@@ -16,6 +16,7 @@
+
+ #include <linux/syscalls.h>
+ #include <linux/membarrier.h>
++#include <linux/tick.h>
+
+ /*
+ * Bitmask made from a "or" of all commands within enum membarrier_cmd,
+@@ -51,6 +52,9 @@
+ */
+ SYSCALL_DEFINE2(membarrier, int, cmd, int, flags)
+ {
++ /* MEMBARRIER_CMD_SHARED is not compatible with nohz_full. */
++ if (tick_nohz_full_enabled())
++ return -ENOSYS;
+ if (unlikely(flags))
+ return -EINVAL;
+ switch (cmd) {
+diff --git a/mm/filemap.c b/mm/filemap.c
+index c33c31d75a2b..69f75c77c098 100644
+--- a/mm/filemap.c
++++ b/mm/filemap.c
+@@ -865,9 +865,12 @@ void page_endio(struct page *page, int rw, int err)
+ unlock_page(page);
+ } else { /* rw == WRITE */
+ if (err) {
++ struct address_space *mapping;
++
+ SetPageError(page);
+- if (page->mapping)
+- mapping_set_error(page->mapping, err);
++ mapping = page_mapping(page);
++ if (mapping)
++ mapping_set_error(mapping, err);
+ }
+ end_page_writeback(page);
+ }
+diff --git a/mm/page_alloc.c b/mm/page_alloc.c
+index 6a117213feb8..6f9005dcca2e 100644
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -2467,7 +2467,7 @@ static bool zone_local(struct zone *local_zone, struct zone *zone)
+
+ static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
+ {
+- return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) <
++ return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) <=
+ RECLAIM_DISTANCE;
+ }
+ #else /* CONFIG_NUMA */
+diff --git a/mm/vmpressure.c b/mm/vmpressure.c
+index c5afd573d7da..3fb15c25af87 100644
+--- a/mm/vmpressure.c
++++ b/mm/vmpressure.c
+@@ -112,9 +112,16 @@ static enum vmpressure_levels vmpressure_calc_level(unsigned long scanned,
+ unsigned long reclaimed)
+ {
+ unsigned long scale = scanned + reclaimed;
+- unsigned long pressure;
++ unsigned long pressure = 0;
+
+ /*
++ * reclaimed can be greater than scanned in cases
++ * like THP, where the scanned is 1 and reclaimed
++ * could be 512
++ */
++ if (reclaimed >= scanned)
++ goto out;
++ /*
+ * We calculate the ratio (in percents) of how many pages were
+ * scanned vs. reclaimed in a given time frame (window). Note that
+ * time is in VM reclaimer's "ticks", i.e. number of pages
+@@ -124,6 +131,7 @@ static enum vmpressure_levels vmpressure_calc_level(unsigned long scanned,
+ pressure = scale - (reclaimed * scale / scanned);
+ pressure = pressure * 100 / scale;
+
++out:
+ pr_debug("%s: %3lu (s: %lu r: %lu)\n", __func__, pressure,
+ scanned, reclaimed);
+
+diff --git a/samples/mic/mpssd/.gitignore b/samples/mic/mpssd/.gitignore
+new file mode 100644
+index 000000000000..8b7c72f07c92
+--- /dev/null
++++ b/samples/mic/mpssd/.gitignore
+@@ -0,0 +1 @@
++mpssd
+diff --git a/samples/mic/mpssd/Makefile b/samples/mic/mpssd/Makefile
+new file mode 100644
+index 000000000000..3e3ef91fed6b
+--- /dev/null
++++ b/samples/mic/mpssd/Makefile
+@@ -0,0 +1,27 @@
++ifndef CROSS_COMPILE
++uname_M := $(shell uname -m 2>/dev/null || echo not)
++ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
++
++ifeq ($(ARCH),x86)
++
++PROGS := mpssd
++CC = $(CROSS_COMPILE)gcc
++CFLAGS := -I../../../usr/include -I../../../tools/include
++
++ifdef DEBUG
++CFLAGS += -DDEBUG=$(DEBUG)
++endif
++
++all: $(PROGS)
++mpssd: mpssd.c sysfs.c
++ $(CC) $(CFLAGS) mpssd.c sysfs.c -o mpssd -lpthread
++
++install:
++ install mpssd /usr/sbin/mpssd
++ install micctrl /usr/sbin/micctrl
++
++clean:
++ rm -fr $(PROGS)
++
++endif
++endif
+diff --git a/samples/mic/mpssd/micctrl b/samples/mic/mpssd/micctrl
+new file mode 100644
+index 000000000000..8f2629b41c5f
+--- /dev/null
++++ b/samples/mic/mpssd/micctrl
+@@ -0,0 +1,173 @@
++#!/bin/bash
++# Intel MIC Platform Software Stack (MPSS)
++#
++# Copyright(c) 2013 Intel Corporation.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License, version 2, as
++# published by the Free Software Foundation.
++#
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++#
++# The full GNU General Public License is included in this distribution in
++# the file called "COPYING".
++#
++# Intel MIC User Space Tools.
++#
++# micctrl - Controls MIC boot/start/stop.
++#
++# chkconfig: 2345 95 05
++# description: start MPSS stack processing.
++#
++### BEGIN INIT INFO
++# Provides: micctrl
++### END INIT INFO
++
++# Source function library.
++. /etc/init.d/functions
++
++sysfs="/sys/class/mic"
++
++_status()
++{
++ f=$sysfs/$1
++ echo -e $1 state: "`cat $f/state`" shutdown_status: "`cat $f/shutdown_status`"
++}
++
++status()
++{
++ if [ "`echo $1 | head -c3`" == "mic" ]; then
++ _status $1
++ return $?
++ fi
++ for f in $sysfs/*
++ do
++ _status `basename $f`
++ RETVAL=$?
++ [ $RETVAL -ne 0 ] && return $RETVAL
++ done
++ return 0
++}
++
++_reset()
++{
++ f=$sysfs/$1
++ echo reset > $f/state
++}
++
++reset()
++{
++ if [ "`echo $1 | head -c3`" == "mic" ]; then
++ _reset $1
++ return $?
++ fi
++ for f in $sysfs/*
++ do
++ _reset `basename $f`
++ RETVAL=$?
++ [ $RETVAL -ne 0 ] && return $RETVAL
++ done
++ return 0
++}
++
++_boot()
++{
++ f=$sysfs/$1
++ echo "linux" > $f/bootmode
++ echo "mic/uos.img" > $f/firmware
++ echo "mic/$1.image" > $f/ramdisk
++ echo "boot" > $f/state
++}
++
++boot()
++{
++ if [ "`echo $1 | head -c3`" == "mic" ]; then
++ _boot $1
++ return $?
++ fi
++ for f in $sysfs/*
++ do
++ _boot `basename $f`
++ RETVAL=$?
++ [ $RETVAL -ne 0 ] && return $RETVAL
++ done
++ return 0
++}
++
++_shutdown()
++{
++ f=$sysfs/$1
++ echo shutdown > $f/state
++}
++
++shutdown()
++{
++ if [ "`echo $1 | head -c3`" == "mic" ]; then
++ _shutdown $1
++ return $?
++ fi
++ for f in $sysfs/*
++ do
++ _shutdown `basename $f`
++ RETVAL=$?
++ [ $RETVAL -ne 0 ] && return $RETVAL
++ done
++ return 0
++}
++
++_wait()
++{
++ f=$sysfs/$1
++ while [ "`cat $f/state`" != "offline" -a "`cat $f/state`" != "online" ]
++ do
++ sleep 1
++ echo -e "Waiting for $1 to go offline"
++ done
++}
++
++wait()
++{
++ if [ "`echo $1 | head -c3`" == "mic" ]; then
++ _wait $1
++ return $?
++ fi
++ # Wait for the cards to go offline
++ for f in $sysfs/*
++ do
++ _wait `basename $f`
++ RETVAL=$?
++ [ $RETVAL -ne 0 ] && return $RETVAL
++ done
++ return 0
++}
++
++if [ ! -d "$sysfs" ]; then
++ echo -e $"Module unloaded "
++ exit 3
++fi
++
++case $1 in
++ -s)
++ status $2
++ ;;
++ -r)
++ reset $2
++ ;;
++ -b)
++ boot $2
++ ;;
++ -S)
++ shutdown $2
++ ;;
++ -w)
++ wait $2
++ ;;
++ *)
++ echo $"Usage: $0 {-s (status) |-r (reset) |-b (boot) |-S (shutdown) |-w (wait)}"
++ exit 2
++esac
++
++exit $?
+diff --git a/samples/mic/mpssd/mpss b/samples/mic/mpssd/mpss
+new file mode 100644
+index 000000000000..09ea90931649
+--- /dev/null
++++ b/samples/mic/mpssd/mpss
+@@ -0,0 +1,200 @@
++#!/bin/bash
++# Intel MIC Platform Software Stack (MPSS)
++#
++# Copyright(c) 2013 Intel Corporation.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License, version 2, as
++# published by the Free Software Foundation.
++#
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++#
++# The full GNU General Public License is included in this distribution in
++# the file called "COPYING".
++#
++# Intel MIC User Space Tools.
++#
++# mpss Start mpssd.
++#
++# chkconfig: 2345 95 05
++# description: start MPSS stack processing.
++#
++### BEGIN INIT INFO
++# Provides: mpss
++# Required-Start:
++# Required-Stop:
++# Short-Description: MPSS stack control
++# Description: MPSS stack control
++### END INIT INFO
++
++# Source function library.
++. /etc/init.d/functions
++
++exec=/usr/sbin/mpssd
++sysfs="/sys/class/mic"
++mic_modules="mic_host mic_x100_dma scif"
++
++start()
++{
++ [ -x $exec ] || exit 5
++
++ if [ "`ps -e | awk '{print $4}' | grep mpssd | head -1`" = "mpssd" ]; then
++ echo -e $"MPSSD already running! "
++ success
++ echo
++ return 0
++ fi
++
++ echo -e $"Starting MPSS Stack"
++ echo -e $"Loading MIC drivers:" $mic_modules
++
++ modprobe -a $mic_modules
++ RETVAL=$?
++ if [ $RETVAL -ne 0 ]; then
++ failure
++ echo
++ return $RETVAL
++ fi
++
++ # Start the daemon
++ echo -n $"Starting MPSSD "
++ $exec
++ RETVAL=$?
++ if [ $RETVAL -ne 0 ]; then
++ failure
++ echo
++ return $RETVAL
++ fi
++ success
++ echo
++
++ sleep 5
++
++ # Boot the cards
++ micctrl -b
++
++ # Wait till ping works
++ for f in $sysfs/*
++ do
++ count=100
++ ipaddr=`cat $f/cmdline`
++ ipaddr=${ipaddr#*address,}
++ ipaddr=`echo $ipaddr | cut -d, -f1 | cut -d\; -f1`
++ while [ $count -ge 0 ]
++ do
++ echo -e "Pinging "`basename $f`" "
++ ping -c 1 $ipaddr &> /dev/null
++ RETVAL=$?
++ if [ $RETVAL -eq 0 ]; then
++ success
++ break
++ fi
++ sleep 1
++ count=`expr $count - 1`
++ done
++ [ $RETVAL -ne 0 ] && failure || success
++ echo
++ done
++ return $RETVAL
++}
++
++stop()
++{
++ echo -e $"Shutting down MPSS Stack: "
++
++ # Bail out if module is unloaded
++ if [ ! -d "$sysfs" ]; then
++ echo -n $"Module unloaded "
++ success
++ echo
++ return 0
++ fi
++
++ # Shut down the cards.
++ micctrl -S
++
++ # Wait for the cards to go offline
++ for f in $sysfs/*
++ do
++ while [ "`cat $f/state`" != "ready" ]
++ do
++ sleep 1
++ echo -e "Waiting for "`basename $f`" to become ready"
++ done
++ done
++
++ # Display the status of the cards
++ micctrl -s
++
++ # Kill MPSSD now
++ echo -n $"Killing MPSSD"
++ killall -9 mpssd 2>/dev/null
++ RETVAL=$?
++ [ $RETVAL -ne 0 ] && failure || success
++ echo
++ return $RETVAL
++}
++
++restart()
++{
++ stop
++ sleep 5
++ start
++}
++
++status()
++{
++ micctrl -s
++ if [ "`ps -e | awk '{print $4}' | grep mpssd | head -n 1`" = "mpssd" ]; then
++ echo "mpssd is running"
++ else
++ echo "mpssd is stopped"
++ fi
++ return 0
++}
++
++unload()
++{
++ if [ ! -d "$sysfs" ]; then
++ echo -n $"No MIC_HOST Module: "
++ success
++ echo
++ return
++ fi
++
++ stop
++
++ sleep 5
++ echo -n $"Removing MIC drivers:" $mic_modules
++ modprobe -r $mic_modules
++ RETVAL=$?
++ [ $RETVAL -ne 0 ] && failure || success
++ echo
++ return $RETVAL
++}
++
++case $1 in
++ start)
++ start
++ ;;
++ stop)
++ stop
++ ;;
++ restart)
++ restart
++ ;;
++ status)
++ status
++ ;;
++ unload)
++ unload
++ ;;
++ *)
++ echo $"Usage: $0 {start|stop|restart|status|unload}"
++ exit 2
++esac
++
++exit $?
+diff --git a/samples/mic/mpssd/mpssd.c b/samples/mic/mpssd/mpssd.c
+new file mode 100644
+index 000000000000..c99a75968c01
+--- /dev/null
++++ b/samples/mic/mpssd/mpssd.c
+@@ -0,0 +1,1826 @@
++/*
++ * Intel MIC Platform Software Stack (MPSS)
++ *
++ * Copyright(c) 2013 Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License, version 2, as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ * Intel MIC User Space Tools.
++ */
++
++#define _GNU_SOURCE
++
++#include <stdlib.h>
++#include <fcntl.h>
++#include <getopt.h>
++#include <assert.h>
++#include <unistd.h>
++#include <stdbool.h>
++#include <signal.h>
++#include <poll.h>
++#include <features.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/mman.h>
++#include <sys/socket.h>
++#include <linux/virtio_ring.h>
++#include <linux/virtio_net.h>
++#include <linux/virtio_console.h>
++#include <linux/virtio_blk.h>
++#include <linux/version.h>
++#include "mpssd.h"
++#include <linux/mic_ioctl.h>
++#include <linux/mic_common.h>
++#include <tools/endian.h>
++
++static void *init_mic(void *arg);
++
++static FILE *logfp;
++static struct mic_info mic_list;
++
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++
++#define min_t(type, x, y) ({ \
++ type __min1 = (x); \
++ type __min2 = (y); \
++ __min1 < __min2 ? __min1 : __min2; })
++
++/* align addr on a size boundary - adjust address up/down if needed */
++#define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1)))
++#define _ALIGN_UP(addr, size) _ALIGN_DOWN(addr + size - 1, size)
++
++/* align addr on a size boundary - adjust address up if needed */
++#define _ALIGN(addr, size) _ALIGN_UP(addr, size)
++
++/* to align the pointer to the (next) page boundary */
++#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
++
++#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
++
++#define GSO_ENABLED 1
++#define MAX_GSO_SIZE (64 * 1024)
++#define ETH_H_LEN 14
++#define MAX_NET_PKT_SIZE (_ALIGN_UP(MAX_GSO_SIZE + ETH_H_LEN, 64))
++#define MIC_DEVICE_PAGE_END 0x1000
++
++#ifndef VIRTIO_NET_HDR_F_DATA_VALID
++#define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */
++#endif
++
++static struct {
++ struct mic_device_desc dd;
++ struct mic_vqconfig vqconfig[2];
++ __u32 host_features, guest_acknowledgements;
++ struct virtio_console_config cons_config;
++} virtcons_dev_page = {
++ .dd = {
++ .type = VIRTIO_ID_CONSOLE,
++ .num_vq = ARRAY_SIZE(virtcons_dev_page.vqconfig),
++ .feature_len = sizeof(virtcons_dev_page.host_features),
++ .config_len = sizeof(virtcons_dev_page.cons_config),
++ },
++ .vqconfig[0] = {
++ .num = htole16(MIC_VRING_ENTRIES),
++ },
++ .vqconfig[1] = {
++ .num = htole16(MIC_VRING_ENTRIES),
++ },
++};
++
++static struct {
++ struct mic_device_desc dd;
++ struct mic_vqconfig vqconfig[2];
++ __u32 host_features, guest_acknowledgements;
++ struct virtio_net_config net_config;
++} virtnet_dev_page = {
++ .dd = {
++ .type = VIRTIO_ID_NET,
++ .num_vq = ARRAY_SIZE(virtnet_dev_page.vqconfig),
++ .feature_len = sizeof(virtnet_dev_page.host_features),
++ .config_len = sizeof(virtnet_dev_page.net_config),
++ },
++ .vqconfig[0] = {
++ .num = htole16(MIC_VRING_ENTRIES),
++ },
++ .vqconfig[1] = {
++ .num = htole16(MIC_VRING_ENTRIES),
++ },
++#if GSO_ENABLED
++ .host_features = htole32(
++ 1 << VIRTIO_NET_F_CSUM |
++ 1 << VIRTIO_NET_F_GSO |
++ 1 << VIRTIO_NET_F_GUEST_TSO4 |
++ 1 << VIRTIO_NET_F_GUEST_TSO6 |
++ 1 << VIRTIO_NET_F_GUEST_ECN),
++#else
++ .host_features = 0,
++#endif
++};
++
++static const char *mic_config_dir = "/etc/mpss";
++static const char *virtblk_backend = "VIRTBLK_BACKEND";
++static struct {
++ struct mic_device_desc dd;
++ struct mic_vqconfig vqconfig[1];
++ __u32 host_features, guest_acknowledgements;
++ struct virtio_blk_config blk_config;
++} virtblk_dev_page = {
++ .dd = {
++ .type = VIRTIO_ID_BLOCK,
++ .num_vq = ARRAY_SIZE(virtblk_dev_page.vqconfig),
++ .feature_len = sizeof(virtblk_dev_page.host_features),
++ .config_len = sizeof(virtblk_dev_page.blk_config),
++ },
++ .vqconfig[0] = {
++ .num = htole16(MIC_VRING_ENTRIES),
++ },
++ .host_features =
++ htole32(1<<VIRTIO_BLK_F_SEG_MAX),
++ .blk_config = {
++ .seg_max = htole32(MIC_VRING_ENTRIES - 2),
++ .capacity = htole64(0),
++ }
++};
++
++static char *myname;
++
++static int
++tap_configure(struct mic_info *mic, char *dev)
++{
++ pid_t pid;
++ char *ifargv[7];
++ char ipaddr[IFNAMSIZ];
++ int ret = 0;
++
++ pid = fork();
++ if (pid == 0) {
++ ifargv[0] = "ip";
++ ifargv[1] = "link";
++ ifargv[2] = "set";
++ ifargv[3] = dev;
++ ifargv[4] = "up";
++ ifargv[5] = NULL;
++ mpsslog("Configuring %s\n", dev);
++ ret = execvp("ip", ifargv);
++ if (ret < 0) {
++ mpsslog("%s execvp failed errno %s\n",
++ mic->name, strerror(errno));
++ return ret;
++ }
++ }
++ if (pid < 0) {
++ mpsslog("%s fork failed errno %s\n",
++ mic->name, strerror(errno));
++ return ret;
++ }
++
++ ret = waitpid(pid, NULL, 0);
++ if (ret < 0) {
++ mpsslog("%s waitpid failed errno %s\n",
++ mic->name, strerror(errno));
++ return ret;
++ }
++
++ snprintf(ipaddr, IFNAMSIZ, "172.31.%d.254/24", mic->id + 1);
++
++ pid = fork();
++ if (pid == 0) {
++ ifargv[0] = "ip";
++ ifargv[1] = "addr";
++ ifargv[2] = "add";
++ ifargv[3] = ipaddr;
++ ifargv[4] = "dev";
++ ifargv[5] = dev;
++ ifargv[6] = NULL;
++ mpsslog("Configuring %s ipaddr %s\n", dev, ipaddr);
++ ret = execvp("ip", ifargv);
++ if (ret < 0) {
++ mpsslog("%s execvp failed errno %s\n",
++ mic->name, strerror(errno));
++ return ret;
++ }
++ }
++ if (pid < 0) {
++ mpsslog("%s fork failed errno %s\n",
++ mic->name, strerror(errno));
++ return ret;
++ }
++
++ ret = waitpid(pid, NULL, 0);
++ if (ret < 0) {
++ mpsslog("%s waitpid failed errno %s\n",
++ mic->name, strerror(errno));
++ return ret;
++ }
++ mpsslog("MIC name %s %s %d DONE!\n",
++ mic->name, __func__, __LINE__);
++ return 0;
++}
++
++static int tun_alloc(struct mic_info *mic, char *dev)
++{
++ struct ifreq ifr;
++ int fd, err;
++#if GSO_ENABLED
++ unsigned offload;
++#endif
++ fd = open("/dev/net/tun", O_RDWR);
++ if (fd < 0) {
++ mpsslog("Could not open /dev/net/tun %s\n", strerror(errno));
++ goto done;
++ }
++
++ memset(&ifr, 0, sizeof(ifr));
++
++ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
++ if (*dev)
++ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
++
++ err = ioctl(fd, TUNSETIFF, (void *)&ifr);
++ if (err < 0) {
++ mpsslog("%s %s %d TUNSETIFF failed %s\n",
++ mic->name, __func__, __LINE__, strerror(errno));
++ close(fd);
++ return err;
++ }
++#if GSO_ENABLED
++ offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_TSO_ECN;
++
++ err = ioctl(fd, TUNSETOFFLOAD, offload);
++ if (err < 0) {
++ mpsslog("%s %s %d TUNSETOFFLOAD failed %s\n",
++ mic->name, __func__, __LINE__, strerror(errno));
++ close(fd);
++ return err;
++ }
++#endif
++ strcpy(dev, ifr.ifr_name);
++ mpsslog("Created TAP %s\n", dev);
++done:
++ return fd;
++}
++
++#define NET_FD_VIRTIO_NET 0
++#define NET_FD_TUN 1
++#define MAX_NET_FD 2
++
++static void set_dp(struct mic_info *mic, int type, void *dp)
++{
++ switch (type) {
++ case VIRTIO_ID_CONSOLE:
++ mic->mic_console.console_dp = dp;
++ return;
++ case VIRTIO_ID_NET:
++ mic->mic_net.net_dp = dp;
++ return;
++ case VIRTIO_ID_BLOCK:
++ mic->mic_virtblk.block_dp = dp;
++ return;
++ }
++ mpsslog("%s %s %d not found\n", mic->name, __func__, type);
++ assert(0);
++}
++
++static void *get_dp(struct mic_info *mic, int type)
++{
++ switch (type) {
++ case VIRTIO_ID_CONSOLE:
++ return mic->mic_console.console_dp;
++ case VIRTIO_ID_NET:
++ return mic->mic_net.net_dp;
++ case VIRTIO_ID_BLOCK:
++ return mic->mic_virtblk.block_dp;
++ }
++ mpsslog("%s %s %d not found\n", mic->name, __func__, type);
++ assert(0);
++ return NULL;
++}
++
++static struct mic_device_desc *get_device_desc(struct mic_info *mic, int type)
++{
++ struct mic_device_desc *d;
++ int i;
++ void *dp = get_dp(mic, type);
++
++ for (i = sizeof(struct mic_bootparam); i < PAGE_SIZE;
++ i += mic_total_desc_size(d)) {
++ d = dp + i;
++
++ /* End of list */
++ if (d->type == 0)
++ break;
++
++ if (d->type == -1)
++ continue;
++
++ mpsslog("%s %s d-> type %d d %p\n",
++ mic->name, __func__, d->type, d);
++
++ if (d->type == (__u8)type)
++ return d;
++ }
++ mpsslog("%s %s %d not found\n", mic->name, __func__, type);
++ return NULL;
++}
++
++/* See comments in vhost.c for explanation of next_desc() */
++static unsigned next_desc(struct vring_desc *desc)
++{
++ unsigned int next;
++
++ if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT))
++ return -1U;
++ next = le16toh(desc->next);
++ return next;
++}
++
++/* Sum up all the IOVEC length */
++static ssize_t
++sum_iovec_len(struct mic_copy_desc *copy)
++{
++ ssize_t sum = 0;
++ int i;
++
++ for (i = 0; i < copy->iovcnt; i++)
++ sum += copy->iov[i].iov_len;
++ return sum;
++}
++
++static inline void verify_out_len(struct mic_info *mic,
++ struct mic_copy_desc *copy)
++{
++ if (copy->out_len != sum_iovec_len(copy)) {
++ mpsslog("%s %s %d BUG copy->out_len 0x%x len 0x%zx\n",
++ mic->name, __func__, __LINE__,
++ copy->out_len, sum_iovec_len(copy));
++ assert(copy->out_len == sum_iovec_len(copy));
++ }
++}
++
++/* Display an iovec */
++static void
++disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy,
++ const char *s, int line)
++{
++ int i;
++
++ for (i = 0; i < copy->iovcnt; i++)
++ mpsslog("%s %s %d copy->iov[%d] addr %p len 0x%zx\n",
++ mic->name, s, line, i,
++ copy->iov[i].iov_base, copy->iov[i].iov_len);
++}
++
++static inline __u16 read_avail_idx(struct mic_vring *vr)
++{
++ return ACCESS_ONCE(vr->info->avail_idx);
++}
++
++static inline void txrx_prepare(int type, bool tx, struct mic_vring *vr,
++ struct mic_copy_desc *copy, ssize_t len)
++{
++ copy->vr_idx = tx ? 0 : 1;
++ copy->update_used = true;
++ if (type == VIRTIO_ID_NET)
++ copy->iov[1].iov_len = len - sizeof(struct virtio_net_hdr);
++ else
++ copy->iov[0].iov_len = len;
++}
++
++/* Central API which triggers the copies */
++static int
++mic_virtio_copy(struct mic_info *mic, int fd,
++ struct mic_vring *vr, struct mic_copy_desc *copy)
++{
++ int ret;
++
++ ret = ioctl(fd, MIC_VIRTIO_COPY_DESC, copy);
++ if (ret) {
++ mpsslog("%s %s %d errno %s ret %d\n",
++ mic->name, __func__, __LINE__,
++ strerror(errno), ret);
++ }
++ return ret;
++}
++
++static inline unsigned _vring_size(unsigned int num, unsigned long align)
++{
++ return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (3 + num)
++ + align - 1) & ~(align - 1))
++ + sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
++}
++
++/*
++ * This initialization routine requires at least one
++ * vring i.e. vr0. vr1 is optional.
++ */
++static void *
++init_vr(struct mic_info *mic, int fd, int type,
++ struct mic_vring *vr0, struct mic_vring *vr1, int num_vq)
++{
++ int vr_size;
++ char *va;
++
++ vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES,
++ MIC_VIRTIO_RING_ALIGN) +
++ sizeof(struct _mic_vring_info));
++ va = mmap(NULL, MIC_DEVICE_PAGE_END + vr_size * num_vq,
++ PROT_READ, MAP_SHARED, fd, 0);
++ if (MAP_FAILED == va) {
++ mpsslog("%s %s %d mmap failed errno %s\n",
++ mic->name, __func__, __LINE__,
++ strerror(errno));
++ goto done;
++ }
++ set_dp(mic, type, va);
++ vr0->va = (struct mic_vring *)&va[MIC_DEVICE_PAGE_END];
++ vr0->info = vr0->va +
++ _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN);
++ vring_init(&vr0->vr,
++ MIC_VRING_ENTRIES, vr0->va, MIC_VIRTIO_RING_ALIGN);
++ mpsslog("%s %s vr0 %p vr0->info %p vr_size 0x%x vring 0x%x ",
++ __func__, mic->name, vr0->va, vr0->info, vr_size,
++ _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
++ mpsslog("magic 0x%x expected 0x%x\n",
++ le32toh(vr0->info->magic), MIC_MAGIC + type);
++ assert(le32toh(vr0->info->magic) == MIC_MAGIC + type);
++ if (vr1) {
++ vr1->va = (struct mic_vring *)
++ &va[MIC_DEVICE_PAGE_END + vr_size];
++ vr1->info = vr1->va + _vring_size(MIC_VRING_ENTRIES,
++ MIC_VIRTIO_RING_ALIGN);
++ vring_init(&vr1->vr,
++ MIC_VRING_ENTRIES, vr1->va, MIC_VIRTIO_RING_ALIGN);
++ mpsslog("%s %s vr1 %p vr1->info %p vr_size 0x%x vring 0x%x ",
++ __func__, mic->name, vr1->va, vr1->info, vr_size,
++ _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
++ mpsslog("magic 0x%x expected 0x%x\n",
++ le32toh(vr1->info->magic), MIC_MAGIC + type + 1);
++ assert(le32toh(vr1->info->magic) == MIC_MAGIC + type + 1);
++ }
++done:
++ return va;
++}
++
++static int
++wait_for_card_driver(struct mic_info *mic, int fd, int type)
++{
++ struct pollfd pollfd;
++ int err;
++ struct mic_device_desc *desc = get_device_desc(mic, type);
++ __u8 prev_status;
++
++ if (!desc)
++ return -ENODEV;
++ prev_status = desc->status;
++ pollfd.fd = fd;
++ mpsslog("%s %s Waiting .... desc-> type %d status 0x%x\n",
++ mic->name, __func__, type, desc->status);
++
++ while (1) {
++ pollfd.events = POLLIN;
++ pollfd.revents = 0;
++ err = poll(&pollfd, 1, -1);
++ if (err < 0) {
++ mpsslog("%s %s poll failed %s\n",
++ mic->name, __func__, strerror(errno));
++ continue;
++ }
++
++ if (pollfd.revents) {
++ if (desc->status != prev_status) {
++ mpsslog("%s %s Waiting... desc-> type %d "
++ "status 0x%x\n",
++ mic->name, __func__, type,
++ desc->status);
++ prev_status = desc->status;
++ }
++ if (desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
++ mpsslog("%s %s poll.revents %d\n",
++ mic->name, __func__, pollfd.revents);
++ mpsslog("%s %s desc-> type %d status 0x%x\n",
++ mic->name, __func__, type,
++ desc->status);
++ break;
++ }
++ }
++ }
++ return 0;
++}
++
++/* Spin till we have some descriptors */
++static void
++spin_for_descriptors(struct mic_info *mic, struct mic_vring *vr)
++{
++ __u16 avail_idx = read_avail_idx(vr);
++
++ while (avail_idx == le16toh(ACCESS_ONCE(vr->vr.avail->idx))) {
++#ifdef DEBUG
++ mpsslog("%s %s waiting for desc avail %d info_avail %d\n",
++ mic->name, __func__,
++ le16toh(vr->vr.avail->idx), vr->info->avail_idx);
++#endif
++ sched_yield();
++ }
++}
++
++static void *
++virtio_net(void *arg)
++{
++ static __u8 vnet_hdr[2][sizeof(struct virtio_net_hdr)];
++ static __u8 vnet_buf[2][MAX_NET_PKT_SIZE] __attribute__ ((aligned(64)));
++ struct iovec vnet_iov[2][2] = {
++ { { .iov_base = vnet_hdr[0], .iov_len = sizeof(vnet_hdr[0]) },
++ { .iov_base = vnet_buf[0], .iov_len = sizeof(vnet_buf[0]) } },
++ { { .iov_base = vnet_hdr[1], .iov_len = sizeof(vnet_hdr[1]) },
++ { .iov_base = vnet_buf[1], .iov_len = sizeof(vnet_buf[1]) } },
++ };
++ struct iovec *iov0 = vnet_iov[0], *iov1 = vnet_iov[1];
++ struct mic_info *mic = (struct mic_info *)arg;
++ char if_name[IFNAMSIZ];
++ struct pollfd net_poll[MAX_NET_FD];
++ struct mic_vring tx_vr, rx_vr;
++ struct mic_copy_desc copy;
++ struct mic_device_desc *desc;
++ int err;
++
++ snprintf(if_name, IFNAMSIZ, "mic%d", mic->id);
++ mic->mic_net.tap_fd = tun_alloc(mic, if_name);
++ if (mic->mic_net.tap_fd < 0)
++ goto done;
++
++ if (tap_configure(mic, if_name))
++ goto done;
++ mpsslog("MIC name %s id %d\n", mic->name, mic->id);
++
++ net_poll[NET_FD_VIRTIO_NET].fd = mic->mic_net.virtio_net_fd;
++ net_poll[NET_FD_VIRTIO_NET].events = POLLIN;
++ net_poll[NET_FD_TUN].fd = mic->mic_net.tap_fd;
++ net_poll[NET_FD_TUN].events = POLLIN;
++
++ if (MAP_FAILED == init_vr(mic, mic->mic_net.virtio_net_fd,
++ VIRTIO_ID_NET, &tx_vr, &rx_vr,
++ virtnet_dev_page.dd.num_vq)) {
++ mpsslog("%s init_vr failed %s\n",
++ mic->name, strerror(errno));
++ goto done;
++ }
++
++ copy.iovcnt = 2;
++ desc = get_device_desc(mic, VIRTIO_ID_NET);
++
++ while (1) {
++ ssize_t len;
++
++ net_poll[NET_FD_VIRTIO_NET].revents = 0;
++ net_poll[NET_FD_TUN].revents = 0;
++
++ /* Start polling for data from tap and virtio net */
++ err = poll(net_poll, 2, -1);
++ if (err < 0) {
++ mpsslog("%s poll failed %s\n",
++ __func__, strerror(errno));
++ continue;
++ }
++ if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
++ err = wait_for_card_driver(mic,
++ mic->mic_net.virtio_net_fd,
++ VIRTIO_ID_NET);
++ if (err) {
++ mpsslog("%s %s %d Exiting...\n",
++ mic->name, __func__, __LINE__);
++ break;
++ }
++ }
++ /*
++ * Check if there is data to be read from TUN and write to
++ * virtio net fd if there is.
++ */
++ if (net_poll[NET_FD_TUN].revents & POLLIN) {
++ copy.iov = iov0;
++ len = readv(net_poll[NET_FD_TUN].fd,
++ copy.iov, copy.iovcnt);
++ if (len > 0) {
++ struct virtio_net_hdr *hdr
++ = (struct virtio_net_hdr *)vnet_hdr[0];
++
++ /* Disable checksums on the card since we are on
++ a reliable PCIe link */
++ hdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID;
++#ifdef DEBUG
++ mpsslog("%s %s %d hdr->flags 0x%x ", mic->name,
++ __func__, __LINE__, hdr->flags);
++ mpsslog("copy.out_len %d hdr->gso_type 0x%x\n",
++ copy.out_len, hdr->gso_type);
++#endif
++#ifdef DEBUG
++ disp_iovec(mic, copy, __func__, __LINE__);
++ mpsslog("%s %s %d read from tap 0x%lx\n",
++ mic->name, __func__, __LINE__,
++ len);
++#endif
++ spin_for_descriptors(mic, &tx_vr);
++ txrx_prepare(VIRTIO_ID_NET, 1, &tx_vr, &copy,
++ len);
++
++ err = mic_virtio_copy(mic,
++ mic->mic_net.virtio_net_fd, &tx_vr,
++ &copy);
++ if (err < 0) {
++ mpsslog("%s %s %d mic_virtio_copy %s\n",
++ mic->name, __func__, __LINE__,
++ strerror(errno));
++ }
++ if (!err)
++ verify_out_len(mic, &copy);
++#ifdef DEBUG
++ disp_iovec(mic, copy, __func__, __LINE__);
++ mpsslog("%s %s %d wrote to net 0x%lx\n",
++ mic->name, __func__, __LINE__,
++ sum_iovec_len(&copy));
++#endif
++ /* Reinitialize IOV for next run */
++ iov0[1].iov_len = MAX_NET_PKT_SIZE;
++ } else if (len < 0) {
++ disp_iovec(mic, &copy, __func__, __LINE__);
++ mpsslog("%s %s %d read failed %s ", mic->name,
++ __func__, __LINE__, strerror(errno));
++ mpsslog("cnt %d sum %zd\n",
++ copy.iovcnt, sum_iovec_len(&copy));
++ }
++ }
++
++ /*
++ * Check if there is data to be read from virtio net and
++ * write to TUN if there is.
++ */
++ if (net_poll[NET_FD_VIRTIO_NET].revents & POLLIN) {
++ while (rx_vr.info->avail_idx !=
++ le16toh(rx_vr.vr.avail->idx)) {
++ copy.iov = iov1;
++ txrx_prepare(VIRTIO_ID_NET, 0, &rx_vr, &copy,
++ MAX_NET_PKT_SIZE
++ + sizeof(struct virtio_net_hdr));
++
++ err = mic_virtio_copy(mic,
++ mic->mic_net.virtio_net_fd, &rx_vr,
++ &copy);
++ if (!err) {
++#ifdef DEBUG
++ struct virtio_net_hdr *hdr
++ = (struct virtio_net_hdr *)
++ vnet_hdr[1];
++
++ mpsslog("%s %s %d hdr->flags 0x%x, ",
++ mic->name, __func__, __LINE__,
++ hdr->flags);
++ mpsslog("out_len %d gso_type 0x%x\n",
++ copy.out_len,
++ hdr->gso_type);
++#endif
++ /* Set the correct output iov_len */
++ iov1[1].iov_len = copy.out_len -
++ sizeof(struct virtio_net_hdr);
++ verify_out_len(mic, &copy);
++#ifdef DEBUG
++ disp_iovec(mic, copy, __func__,
++ __LINE__);
++ mpsslog("%s %s %d ",
++ mic->name, __func__, __LINE__);
++ mpsslog("read from net 0x%lx\n",
++ sum_iovec_len(copy));
++#endif
++ len = writev(net_poll[NET_FD_TUN].fd,
++ copy.iov, copy.iovcnt);
++ if (len != sum_iovec_len(&copy)) {
++ mpsslog("Tun write failed %s ",
++ strerror(errno));
++ mpsslog("len 0x%zx ", len);
++ mpsslog("read_len 0x%zx\n",
++ sum_iovec_len(&copy));
++ } else {
++#ifdef DEBUG
++ disp_iovec(mic, &copy, __func__,
++ __LINE__);
++ mpsslog("%s %s %d ",
++ mic->name, __func__,
++ __LINE__);
++ mpsslog("wrote to tap 0x%lx\n",
++ len);
++#endif
++ }
++ } else {
++ mpsslog("%s %s %d mic_virtio_copy %s\n",
++ mic->name, __func__, __LINE__,
++ strerror(errno));
++ break;
++ }
++ }
++ }
++ if (net_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
++ mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
++ }
++done:
++ pthread_exit(NULL);
++}
++
++/* virtio_console */
++#define VIRTIO_CONSOLE_FD 0
++#define MONITOR_FD (VIRTIO_CONSOLE_FD + 1)
++#define MAX_CONSOLE_FD (MONITOR_FD + 1) /* must be the last one + 1 */
++#define MAX_BUFFER_SIZE PAGE_SIZE
++
++static void *
++virtio_console(void *arg)
++{
++ static __u8 vcons_buf[2][PAGE_SIZE];
++ struct iovec vcons_iov[2] = {
++ { .iov_base = vcons_buf[0], .iov_len = sizeof(vcons_buf[0]) },
++ { .iov_base = vcons_buf[1], .iov_len = sizeof(vcons_buf[1]) },
++ };
++ struct iovec *iov0 = &vcons_iov[0], *iov1 = &vcons_iov[1];
++ struct mic_info *mic = (struct mic_info *)arg;
++ int err;
++ struct pollfd console_poll[MAX_CONSOLE_FD];
++ int pty_fd;
++ char *pts_name;
++ ssize_t len;
++ struct mic_vring tx_vr, rx_vr;
++ struct mic_copy_desc copy;
++ struct mic_device_desc *desc;
++
++ pty_fd = posix_openpt(O_RDWR);
++ if (pty_fd < 0) {
++ mpsslog("can't open a pseudoterminal master device: %s\n",
++ strerror(errno));
++ goto _return;
++ }
++ pts_name = ptsname(pty_fd);
++ if (pts_name == NULL) {
++ mpsslog("can't get pts name\n");
++ goto _close_pty;
++ }
++ printf("%s console message goes to %s\n", mic->name, pts_name);
++ mpsslog("%s console message goes to %s\n", mic->name, pts_name);
++ err = grantpt(pty_fd);
++ if (err < 0) {
++ mpsslog("can't grant access: %s %s\n",
++ pts_name, strerror(errno));
++ goto _close_pty;
++ }
++ err = unlockpt(pty_fd);
++ if (err < 0) {
++ mpsslog("can't unlock a pseudoterminal: %s %s\n",
++ pts_name, strerror(errno));
++ goto _close_pty;
++ }
++ console_poll[MONITOR_FD].fd = pty_fd;
++ console_poll[MONITOR_FD].events = POLLIN;
++
++ console_poll[VIRTIO_CONSOLE_FD].fd = mic->mic_console.virtio_console_fd;
++ console_poll[VIRTIO_CONSOLE_FD].events = POLLIN;
++
++ if (MAP_FAILED == init_vr(mic, mic->mic_console.virtio_console_fd,
++ VIRTIO_ID_CONSOLE, &tx_vr, &rx_vr,
++ virtcons_dev_page.dd.num_vq)) {
++ mpsslog("%s init_vr failed %s\n",
++ mic->name, strerror(errno));
++ goto _close_pty;
++ }
++
++ copy.iovcnt = 1;
++ desc = get_device_desc(mic, VIRTIO_ID_CONSOLE);
++
++ for (;;) {
++ console_poll[MONITOR_FD].revents = 0;
++ console_poll[VIRTIO_CONSOLE_FD].revents = 0;
++ err = poll(console_poll, MAX_CONSOLE_FD, -1);
++ if (err < 0) {
++ mpsslog("%s %d: poll failed: %s\n", __func__, __LINE__,
++ strerror(errno));
++ continue;
++ }
++ if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
++ err = wait_for_card_driver(mic,
++ mic->mic_console.virtio_console_fd,
++ VIRTIO_ID_CONSOLE);
++ if (err) {
++ mpsslog("%s %s %d Exiting...\n",
++ mic->name, __func__, __LINE__);
++ break;
++ }
++ }
++
++ if (console_poll[MONITOR_FD].revents & POLLIN) {
++ copy.iov = iov0;
++ len = readv(pty_fd, copy.iov, copy.iovcnt);
++ if (len > 0) {
++#ifdef DEBUG
++ disp_iovec(mic, copy, __func__, __LINE__);
++ mpsslog("%s %s %d read from tap 0x%lx\n",
++ mic->name, __func__, __LINE__,
++ len);
++#endif
++ spin_for_descriptors(mic, &tx_vr);
++ txrx_prepare(VIRTIO_ID_CONSOLE, 1, &tx_vr,
++ &copy, len);
++
++ err = mic_virtio_copy(mic,
++ mic->mic_console.virtio_console_fd,
++ &tx_vr, &copy);
++ if (err < 0) {
++ mpsslog("%s %s %d mic_virtio_copy %s\n",
++ mic->name, __func__, __LINE__,
++ strerror(errno));
++ }
++ if (!err)
++ verify_out_len(mic, &copy);
++#ifdef DEBUG
++ disp_iovec(mic, copy, __func__, __LINE__);
++ mpsslog("%s %s %d wrote to net 0x%lx\n",
++ mic->name, __func__, __LINE__,
++ sum_iovec_len(copy));
++#endif
++ /* Reinitialize IOV for next run */
++ iov0->iov_len = PAGE_SIZE;
++ } else if (len < 0) {
++ disp_iovec(mic, &copy, __func__, __LINE__);
++ mpsslog("%s %s %d read failed %s ",
++ mic->name, __func__, __LINE__,
++ strerror(errno));
++ mpsslog("cnt %d sum %zd\n",
++ copy.iovcnt, sum_iovec_len(&copy));
++ }
++ }
++
++ if (console_poll[VIRTIO_CONSOLE_FD].revents & POLLIN) {
++ while (rx_vr.info->avail_idx !=
++ le16toh(rx_vr.vr.avail->idx)) {
++ copy.iov = iov1;
++ txrx_prepare(VIRTIO_ID_CONSOLE, 0, &rx_vr,
++ &copy, PAGE_SIZE);
++
++ err = mic_virtio_copy(mic,
++ mic->mic_console.virtio_console_fd,
++ &rx_vr, &copy);
++ if (!err) {
++ /* Set the correct output iov_len */
++ iov1->iov_len = copy.out_len;
++ verify_out_len(mic, &copy);
++#ifdef DEBUG
++ disp_iovec(mic, copy, __func__,
++ __LINE__);
++ mpsslog("%s %s %d ",
++ mic->name, __func__, __LINE__);
++ mpsslog("read from net 0x%lx\n",
++ sum_iovec_len(copy));
++#endif
++ len = writev(pty_fd,
++ copy.iov, copy.iovcnt);
++ if (len != sum_iovec_len(&copy)) {
++ mpsslog("Tun write failed %s ",
++ strerror(errno));
++ mpsslog("len 0x%zx ", len);
++ mpsslog("read_len 0x%zx\n",
++ sum_iovec_len(&copy));
++ } else {
++#ifdef DEBUG
++ disp_iovec(mic, copy, __func__,
++ __LINE__);
++ mpsslog("%s %s %d ",
++ mic->name, __func__,
++ __LINE__);
++ mpsslog("wrote to tap 0x%lx\n",
++ len);
++#endif
++ }
++ } else {
++ mpsslog("%s %s %d mic_virtio_copy %s\n",
++ mic->name, __func__, __LINE__,
++ strerror(errno));
++ break;
++ }
++ }
++ }
++ if (console_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
++ mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
++ }
++_close_pty:
++ close(pty_fd);
++_return:
++ pthread_exit(NULL);
++}
++
++static void
++add_virtio_device(struct mic_info *mic, struct mic_device_desc *dd)
++{
++ char path[PATH_MAX];
++ int fd, err;
++
++ snprintf(path, PATH_MAX, "/dev/mic%d", mic->id);
++ fd = open(path, O_RDWR);
++ if (fd < 0) {
++ mpsslog("Could not open %s %s\n", path, strerror(errno));
++ return;
++ }
++
++ err = ioctl(fd, MIC_VIRTIO_ADD_DEVICE, dd);
++ if (err < 0) {
++ mpsslog("Could not add %d %s\n", dd->type, strerror(errno));
++ close(fd);
++ return;
++ }
++ switch (dd->type) {
++ case VIRTIO_ID_NET:
++ mic->mic_net.virtio_net_fd = fd;
++ mpsslog("Added VIRTIO_ID_NET for %s\n", mic->name);
++ break;
++ case VIRTIO_ID_CONSOLE:
++ mic->mic_console.virtio_console_fd = fd;
++ mpsslog("Added VIRTIO_ID_CONSOLE for %s\n", mic->name);
++ break;
++ case VIRTIO_ID_BLOCK:
++ mic->mic_virtblk.virtio_block_fd = fd;
++ mpsslog("Added VIRTIO_ID_BLOCK for %s\n", mic->name);
++ break;
++ }
++}
++
++static bool
++set_backend_file(struct mic_info *mic)
++{
++ FILE *config;
++ char buff[PATH_MAX], *line, *evv, *p;
++
++ snprintf(buff, PATH_MAX, "%s/mpssd%03d.conf", mic_config_dir, mic->id);
++ config = fopen(buff, "r");
++ if (config == NULL)
++ return false;
++ do { /* look for "virtblk_backend=XXXX" */
++ line = fgets(buff, PATH_MAX, config);
++ if (line == NULL)
++ break;
++ if (*line == '#')
++ continue;
++ p = strchr(line, '\n');
++ if (p)
++ *p = '\0';
++ } while (strncmp(line, virtblk_backend, strlen(virtblk_backend)) != 0);
++ fclose(config);
++ if (line == NULL)
++ return false;
++ evv = strchr(line, '=');
++ if (evv == NULL)
++ return false;
++ mic->mic_virtblk.backend_file = malloc(strlen(evv) + 1);
++ if (mic->mic_virtblk.backend_file == NULL) {
++ mpsslog("%s %d can't allocate memory\n", mic->name, mic->id);
++ return false;
++ }
++ strcpy(mic->mic_virtblk.backend_file, evv + 1);
++ return true;
++}
++
++#define SECTOR_SIZE 512
++static bool
++set_backend_size(struct mic_info *mic)
++{
++ mic->mic_virtblk.backend_size = lseek(mic->mic_virtblk.backend, 0,
++ SEEK_END);
++ if (mic->mic_virtblk.backend_size < 0) {
++ mpsslog("%s: can't seek: %s\n",
++ mic->name, mic->mic_virtblk.backend_file);
++ return false;
++ }
++ virtblk_dev_page.blk_config.capacity =
++ mic->mic_virtblk.backend_size / SECTOR_SIZE;
++ if ((mic->mic_virtblk.backend_size % SECTOR_SIZE) != 0)
++ virtblk_dev_page.blk_config.capacity++;
++
++ virtblk_dev_page.blk_config.capacity =
++ htole64(virtblk_dev_page.blk_config.capacity);
++
++ return true;
++}
++
++static bool
++open_backend(struct mic_info *mic)
++{
++ if (!set_backend_file(mic))
++ goto _error_exit;
++ mic->mic_virtblk.backend = open(mic->mic_virtblk.backend_file, O_RDWR);
++ if (mic->mic_virtblk.backend < 0) {
++ mpsslog("%s: can't open: %s\n", mic->name,
++ mic->mic_virtblk.backend_file);
++ goto _error_free;
++ }
++ if (!set_backend_size(mic))
++ goto _error_close;
++ mic->mic_virtblk.backend_addr = mmap(NULL,
++ mic->mic_virtblk.backend_size,
++ PROT_READ|PROT_WRITE, MAP_SHARED,
++ mic->mic_virtblk.backend, 0L);
++ if (mic->mic_virtblk.backend_addr == MAP_FAILED) {
++ mpsslog("%s: can't map: %s %s\n",
++ mic->name, mic->mic_virtblk.backend_file,
++ strerror(errno));
++ goto _error_close;
++ }
++ return true;
++
++ _error_close:
++ close(mic->mic_virtblk.backend);
++ _error_free:
++ free(mic->mic_virtblk.backend_file);
++ _error_exit:
++ return false;
++}
++
++static void
++close_backend(struct mic_info *mic)
++{
++ munmap(mic->mic_virtblk.backend_addr, mic->mic_virtblk.backend_size);
++ close(mic->mic_virtblk.backend);
++ free(mic->mic_virtblk.backend_file);
++}
++
++static bool
++start_virtblk(struct mic_info *mic, struct mic_vring *vring)
++{
++ if (((unsigned long)&virtblk_dev_page.blk_config % 8) != 0) {
++ mpsslog("%s: blk_config is not 8 byte aligned.\n",
++ mic->name);
++ return false;
++ }
++ add_virtio_device(mic, &virtblk_dev_page.dd);
++ if (MAP_FAILED == init_vr(mic, mic->mic_virtblk.virtio_block_fd,
++ VIRTIO_ID_BLOCK, vring, NULL,
++ virtblk_dev_page.dd.num_vq)) {
++ mpsslog("%s init_vr failed %s\n",
++ mic->name, strerror(errno));
++ return false;
++ }
++ return true;
++}
++
++static void
++stop_virtblk(struct mic_info *mic)
++{
++ int vr_size, ret;
++
++ vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES,
++ MIC_VIRTIO_RING_ALIGN) +
++ sizeof(struct _mic_vring_info));
++ ret = munmap(mic->mic_virtblk.block_dp,
++ MIC_DEVICE_PAGE_END + vr_size * virtblk_dev_page.dd.num_vq);
++ if (ret < 0)
++ mpsslog("%s munmap errno %d\n", mic->name, errno);
++ close(mic->mic_virtblk.virtio_block_fd);
++}
++
++static __u8
++header_error_check(struct vring_desc *desc)
++{
++ if (le32toh(desc->len) != sizeof(struct virtio_blk_outhdr)) {
++ mpsslog("%s() %d: length is not sizeof(virtio_blk_outhd)\n",
++ __func__, __LINE__);
++ return -EIO;
++ }
++ if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT)) {
++ mpsslog("%s() %d: alone\n",
++ __func__, __LINE__);
++ return -EIO;
++ }
++ if (le16toh(desc->flags) & VRING_DESC_F_WRITE) {
++ mpsslog("%s() %d: not read\n",
++ __func__, __LINE__);
++ return -EIO;
++ }
++ return 0;
++}
++
++static int
++read_header(int fd, struct virtio_blk_outhdr *hdr, __u32 desc_idx)
++{
++ struct iovec iovec;
++ struct mic_copy_desc copy;
++
++ iovec.iov_len = sizeof(*hdr);
++ iovec.iov_base = hdr;
++ copy.iov = &iovec;
++ copy.iovcnt = 1;
++ copy.vr_idx = 0; /* only one vring on virtio_block */
++ copy.update_used = false; /* do not update used index */
++ return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
++}
++
++static int
++transfer_blocks(int fd, struct iovec *iovec, __u32 iovcnt)
++{
++ struct mic_copy_desc copy;
++
++ copy.iov = iovec;
++ copy.iovcnt = iovcnt;
++ copy.vr_idx = 0; /* only one vring on virtio_block */
++ copy.update_used = false; /* do not update used index */
++ return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
++}
++
++static __u8
++status_error_check(struct vring_desc *desc)
++{
++ if (le32toh(desc->len) != sizeof(__u8)) {
++ mpsslog("%s() %d: length is not sizeof(status)\n",
++ __func__, __LINE__);
++ return -EIO;
++ }
++ return 0;
++}
++
++static int
++write_status(int fd, __u8 *status)
++{
++ struct iovec iovec;
++ struct mic_copy_desc copy;
++
++ iovec.iov_base = status;
++ iovec.iov_len = sizeof(*status);
++ copy.iov = &iovec;
++ copy.iovcnt = 1;
++ copy.vr_idx = 0; /* only one vring on virtio_block */
++ copy.update_used = true; /* Update used index */
++ return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
++}
++
++#ifndef VIRTIO_BLK_T_GET_ID
++#define VIRTIO_BLK_T_GET_ID 8
++#endif
++
++static void *
++virtio_block(void *arg)
++{
++ struct mic_info *mic = (struct mic_info *)arg;
++ int ret;
++ struct pollfd block_poll;
++ struct mic_vring vring;
++ __u16 avail_idx;
++ __u32 desc_idx;
++ struct vring_desc *desc;
++ struct iovec *iovec, *piov;
++ __u8 status;
++ __u32 buffer_desc_idx;
++ struct virtio_blk_outhdr hdr;
++ void *fos;
++
++ for (;;) { /* forever */
++ if (!open_backend(mic)) { /* No virtblk */
++ for (mic->mic_virtblk.signaled = 0;
++ !mic->mic_virtblk.signaled;)
++ sleep(1);
++ continue;
++ }
++
++ /* backend file is specified. */
++ if (!start_virtblk(mic, &vring))
++ goto _close_backend;
++ iovec = malloc(sizeof(*iovec) *
++ le32toh(virtblk_dev_page.blk_config.seg_max));
++ if (!iovec) {
++ mpsslog("%s: can't alloc iovec: %s\n",
++ mic->name, strerror(ENOMEM));
++ goto _stop_virtblk;
++ }
++
++ block_poll.fd = mic->mic_virtblk.virtio_block_fd;
++ block_poll.events = POLLIN;
++ for (mic->mic_virtblk.signaled = 0;
++ !mic->mic_virtblk.signaled;) {
++ block_poll.revents = 0;
++ /* timeout in 1 sec to see signaled */
++ ret = poll(&block_poll, 1, 1000);
++ if (ret < 0) {
++ mpsslog("%s %d: poll failed: %s\n",
++ __func__, __LINE__,
++ strerror(errno));
++ continue;
++ }
++
++ if (!(block_poll.revents & POLLIN)) {
++#ifdef DEBUG
++ mpsslog("%s %d: block_poll.revents=0x%x\n",
++ __func__, __LINE__, block_poll.revents);
++#endif
++ continue;
++ }
++
++ /* POLLIN */
++ while (vring.info->avail_idx !=
++ le16toh(vring.vr.avail->idx)) {
++ /* read header element */
++ avail_idx =
++ vring.info->avail_idx &
++ (vring.vr.num - 1);
++ desc_idx = le16toh(
++ vring.vr.avail->ring[avail_idx]);
++ desc = &vring.vr.desc[desc_idx];
++#ifdef DEBUG
++ mpsslog("%s() %d: avail_idx=%d ",
++ __func__, __LINE__,
++ vring.info->avail_idx);
++ mpsslog("vring.vr.num=%d desc=%p\n",
++ vring.vr.num, desc);
++#endif
++ status = header_error_check(desc);
++ ret = read_header(
++ mic->mic_virtblk.virtio_block_fd,
++ &hdr, desc_idx);
++ if (ret < 0) {
++ mpsslog("%s() %d %s: ret=%d %s\n",
++ __func__, __LINE__,
++ mic->name, ret,
++ strerror(errno));
++ break;
++ }
++ /* buffer element */
++ piov = iovec;
++ status = 0;
++ fos = mic->mic_virtblk.backend_addr +
++ (hdr.sector * SECTOR_SIZE);
++ buffer_desc_idx = next_desc(desc);
++ desc_idx = buffer_desc_idx;
++ for (desc = &vring.vr.desc[buffer_desc_idx];
++ desc->flags & VRING_DESC_F_NEXT;
++ desc_idx = next_desc(desc),
++ desc = &vring.vr.desc[desc_idx]) {
++ piov->iov_len = desc->len;
++ piov->iov_base = fos;
++ piov++;
++ fos += desc->len;
++ }
++ /* Returning NULLs for VIRTIO_BLK_T_GET_ID. */
++ if (hdr.type & ~(VIRTIO_BLK_T_OUT |
++ VIRTIO_BLK_T_GET_ID)) {
++ /*
++ VIRTIO_BLK_T_IN - does not do
++ anything. Probably for documenting.
++ VIRTIO_BLK_T_SCSI_CMD - for
++ virtio_scsi.
++ VIRTIO_BLK_T_FLUSH - turned off in
++ config space.
++ VIRTIO_BLK_T_BARRIER - defined but not
++ used in anywhere.
++ */
++ mpsslog("%s() %d: type %x ",
++ __func__, __LINE__,
++ hdr.type);
++ mpsslog("is not supported\n");
++ status = -ENOTSUP;
++
++ } else {
++ ret = transfer_blocks(
++ mic->mic_virtblk.virtio_block_fd,
++ iovec,
++ piov - iovec);
++ if (ret < 0 &&
++ status != 0)
++ status = ret;
++ }
++ /* write status and update used pointer */
++ if (status != 0)
++ status = status_error_check(desc);
++ ret = write_status(
++ mic->mic_virtblk.virtio_block_fd,
++ &status);
++#ifdef DEBUG
++ mpsslog("%s() %d: write status=%d on desc=%p\n",
++ __func__, __LINE__,
++ status, desc);
++#endif
++ }
++ }
++ free(iovec);
++_stop_virtblk:
++ stop_virtblk(mic);
++_close_backend:
++ close_backend(mic);
++ } /* forever */
++
++ pthread_exit(NULL);
++}
++
++static void
++reset(struct mic_info *mic)
++{
++#define RESET_TIMEOUT 120
++ int i = RESET_TIMEOUT;
++ setsysfs(mic->name, "state", "reset");
++ while (i) {
++ char *state;
++ state = readsysfs(mic->name, "state");
++ if (!state)
++ goto retry;
++ mpsslog("%s: %s %d state %s\n",
++ mic->name, __func__, __LINE__, state);
++
++ if (!strcmp(state, "ready")) {
++ free(state);
++ break;
++ }
++ free(state);
++retry:
++ sleep(1);
++ i--;
++ }
++}
++
++static int
++get_mic_shutdown_status(struct mic_info *mic, char *shutdown_status)
++{
++ if (!strcmp(shutdown_status, "nop"))
++ return MIC_NOP;
++ if (!strcmp(shutdown_status, "crashed"))
++ return MIC_CRASHED;
++ if (!strcmp(shutdown_status, "halted"))
++ return MIC_HALTED;
++ if (!strcmp(shutdown_status, "poweroff"))
++ return MIC_POWER_OFF;
++ if (!strcmp(shutdown_status, "restart"))
++ return MIC_RESTART;
++ mpsslog("%s: BUG invalid status %s\n", mic->name, shutdown_status);
++ /* Invalid state */
++ assert(0);
++};
++
++static int get_mic_state(struct mic_info *mic)
++{
++ char *state = NULL;
++ enum mic_states mic_state;
++
++ while (!state) {
++ state = readsysfs(mic->name, "state");
++ sleep(1);
++ }
++ mpsslog("%s: %s %d state %s\n",
++ mic->name, __func__, __LINE__, state);
++
++ if (!strcmp(state, "ready")) {
++ mic_state = MIC_READY;
++ } else if (!strcmp(state, "booting")) {
++ mic_state = MIC_BOOTING;
++ } else if (!strcmp(state, "online")) {
++ mic_state = MIC_ONLINE;
++ } else if (!strcmp(state, "shutting_down")) {
++ mic_state = MIC_SHUTTING_DOWN;
++ } else if (!strcmp(state, "reset_failed")) {
++ mic_state = MIC_RESET_FAILED;
++ } else if (!strcmp(state, "resetting")) {
++ mic_state = MIC_RESETTING;
++ } else {
++ mpsslog("%s: BUG invalid state %s\n", mic->name, state);
++ assert(0);
++ }
++
++ free(state);
++ return mic_state;
++};
++
++static void mic_handle_shutdown(struct mic_info *mic)
++{
++#define SHUTDOWN_TIMEOUT 60
++ int i = SHUTDOWN_TIMEOUT;
++ char *shutdown_status;
++ while (i) {
++ shutdown_status = readsysfs(mic->name, "shutdown_status");
++ if (!shutdown_status) {
++ sleep(1);
++ continue;
++ }
++ mpsslog("%s: %s %d shutdown_status %s\n",
++ mic->name, __func__, __LINE__, shutdown_status);
++ switch (get_mic_shutdown_status(mic, shutdown_status)) {
++ case MIC_RESTART:
++ mic->restart = 1;
++ case MIC_HALTED:
++ case MIC_POWER_OFF:
++ case MIC_CRASHED:
++ free(shutdown_status);
++ goto reset;
++ default:
++ break;
++ }
++ free(shutdown_status);
++ sleep(1);
++ i--;
++ }
++reset:
++ if (!i)
++ mpsslog("%s: %s %d timing out waiting for shutdown_status %s\n",
++ mic->name, __func__, __LINE__, shutdown_status);
++ reset(mic);
++}
++
++static int open_state_fd(struct mic_info *mic)
++{
++ char pathname[PATH_MAX];
++ int fd;
++
++ snprintf(pathname, PATH_MAX - 1, "%s/%s/%s",
++ MICSYSFSDIR, mic->name, "state");
++
++ fd = open(pathname, O_RDONLY);
++ if (fd < 0)
++ mpsslog("%s: opening file %s failed %s\n",
++ mic->name, pathname, strerror(errno));
++ return fd;
++}
++
++static int block_till_state_change(int fd, struct mic_info *mic)
++{
++ struct pollfd ufds[1];
++ char value[PAGE_SIZE];
++ int ret;
++
++ ufds[0].fd = fd;
++ ufds[0].events = POLLERR | POLLPRI;
++ ret = poll(ufds, 1, -1);
++ if (ret < 0) {
++ mpsslog("%s: %s %d poll failed %s\n",
++ mic->name, __func__, __LINE__, strerror(errno));
++ return ret;
++ }
++
++ ret = lseek(fd, 0, SEEK_SET);
++ if (ret < 0) {
++ mpsslog("%s: %s %d Failed to seek to 0: %s\n",
++ mic->name, __func__, __LINE__, strerror(errno));
++ return ret;
++ }
++
++ ret = read(fd, value, sizeof(value));
++ if (ret < 0) {
++ mpsslog("%s: %s %d Failed to read sysfs entry: %s\n",
++ mic->name, __func__, __LINE__, strerror(errno));
++ return ret;
++ }
++
++ return 0;
++}
++
++static void *
++mic_config(void *arg)
++{
++ struct mic_info *mic = (struct mic_info *)arg;
++ int fd, ret, stat = 0;
++
++ fd = open_state_fd(mic);
++ if (fd < 0) {
++ mpsslog("%s: %s %d open state fd failed %s\n",
++ mic->name, __func__, __LINE__, strerror(errno));
++ goto exit;
++ }
++
++ do {
++ ret = block_till_state_change(fd, mic);
++ if (ret < 0) {
++ mpsslog("%s: %s %d block_till_state_change error %s\n",
++ mic->name, __func__, __LINE__, strerror(errno));
++ goto close_exit;
++ }
++
++ switch (get_mic_state(mic)) {
++ case MIC_SHUTTING_DOWN:
++ mic_handle_shutdown(mic);
++ break;
++ case MIC_READY:
++ case MIC_RESET_FAILED:
++ ret = kill(mic->pid, SIGTERM);
++ mpsslog("%s: %s %d kill pid %d ret %d\n",
++ mic->name, __func__, __LINE__,
++ mic->pid, ret);
++ if (!ret) {
++ ret = waitpid(mic->pid, &stat,
++ WIFSIGNALED(stat));
++ mpsslog("%s: %s %d waitpid ret %d pid %d\n",
++ mic->name, __func__, __LINE__,
++ ret, mic->pid);
++ }
++ if (mic->boot_on_resume) {
++ setsysfs(mic->name, "state", "boot");
++ mic->boot_on_resume = 0;
++ }
++ goto close_exit;
++ default:
++ break;
++ }
++ } while (1);
++
++close_exit:
++ close(fd);
++exit:
++ init_mic(mic);
++ pthread_exit(NULL);
++}
++
++static void
++set_cmdline(struct mic_info *mic)
++{
++ char buffer[PATH_MAX];
++ int len;
++
++ len = snprintf(buffer, PATH_MAX,
++ "clocksource=tsc highres=off nohz=off ");
++ len += snprintf(buffer + len, PATH_MAX - len,
++ "cpufreq_on;corec6_off;pc3_off;pc6_off ");
++ len += snprintf(buffer + len, PATH_MAX - len,
++ "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0",
++ mic->id + 1);
++
++ setsysfs(mic->name, "cmdline", buffer);
++ mpsslog("%s: Command line: \"%s\"\n", mic->name, buffer);
++ snprintf(buffer, PATH_MAX, "172.31.%d.1", mic->id + 1);
++ mpsslog("%s: IPADDR: \"%s\"\n", mic->name, buffer);
++}
++
++static void
++set_log_buf_info(struct mic_info *mic)
++{
++ int fd;
++ off_t len;
++ char system_map[] = "/lib/firmware/mic/System.map";
++ char *map, *temp, log_buf[17] = {'\0'};
++
++ fd = open(system_map, O_RDONLY);
++ if (fd < 0) {
++ mpsslog("%s: Opening System.map failed: %d\n",
++ mic->name, errno);
++ return;
++ }
++ len = lseek(fd, 0, SEEK_END);
++ if (len < 0) {
++ mpsslog("%s: Reading System.map size failed: %d\n",
++ mic->name, errno);
++ close(fd);
++ return;
++ }
++ map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
++ if (map == MAP_FAILED) {
++ mpsslog("%s: mmap of System.map failed: %d\n",
++ mic->name, errno);
++ close(fd);
++ return;
++ }
++ temp = strstr(map, "__log_buf");
++ if (!temp) {
++ mpsslog("%s: __log_buf not found: %d\n", mic->name, errno);
++ munmap(map, len);
++ close(fd);
++ return;
++ }
++ strncpy(log_buf, temp - 19, 16);
++ setsysfs(mic->name, "log_buf_addr", log_buf);
++ mpsslog("%s: log_buf_addr: %s\n", mic->name, log_buf);
++ temp = strstr(map, "log_buf_len");
++ if (!temp) {
++ mpsslog("%s: log_buf_len not found: %d\n", mic->name, errno);
++ munmap(map, len);
++ close(fd);
++ return;
++ }
++ strncpy(log_buf, temp - 19, 16);
++ setsysfs(mic->name, "log_buf_len", log_buf);
++ mpsslog("%s: log_buf_len: %s\n", mic->name, log_buf);
++ munmap(map, len);
++ close(fd);
++}
++
++static void
++change_virtblk_backend(int x, siginfo_t *siginfo, void *p)
++{
++ struct mic_info *mic;
++
++ for (mic = mic_list.next; mic != NULL; mic = mic->next)
++ mic->mic_virtblk.signaled = 1/* true */;
++}
++
++static void
++set_mic_boot_params(struct mic_info *mic)
++{
++ set_log_buf_info(mic);
++ set_cmdline(mic);
++}
++
++static void *
++init_mic(void *arg)
++{
++ struct mic_info *mic = (struct mic_info *)arg;
++ struct sigaction ignore = {
++ .sa_flags = 0,
++ .sa_handler = SIG_IGN
++ };
++ struct sigaction act = {
++ .sa_flags = SA_SIGINFO,
++ .sa_sigaction = change_virtblk_backend,
++ };
++ char buffer[PATH_MAX];
++ int err, fd;
++
++ /*
++ * Currently, one virtio block device is supported for each MIC card
++ * at a time. Any user (or test) can send a SIGUSR1 to the MIC daemon.
++ * The signal informs the virtio block backend about a change in the
++ * configuration file which specifies the virtio backend file name on
++ * the host. Virtio block backend then re-reads the configuration file
++ * and switches to the new block device. This signalling mechanism may
++ * not be required once multiple virtio block devices are supported by
++ * the MIC daemon.
++ */
++ sigaction(SIGUSR1, &ignore, NULL);
++retry:
++ fd = open_state_fd(mic);
++ if (fd < 0) {
++ mpsslog("%s: %s %d open state fd failed %s\n",
++ mic->name, __func__, __LINE__, strerror(errno));
++ sleep(2);
++ goto retry;
++ }
++
++ if (mic->restart) {
++ snprintf(buffer, PATH_MAX, "boot");
++ setsysfs(mic->name, "state", buffer);
++ mpsslog("%s restarting mic %d\n",
++ mic->name, mic->restart);
++ mic->restart = 0;
++ }
++
++ while (1) {
++ while (block_till_state_change(fd, mic)) {
++ mpsslog("%s: %s %d block_till_state_change error %s\n",
++ mic->name, __func__, __LINE__, strerror(errno));
++ sleep(2);
++ continue;
++ }
++
++ if (get_mic_state(mic) == MIC_BOOTING)
++ break;
++ }
++
++ mic->pid = fork();
++ switch (mic->pid) {
++ case 0:
++ add_virtio_device(mic, &virtcons_dev_page.dd);
++ add_virtio_device(mic, &virtnet_dev_page.dd);
++ err = pthread_create(&mic->mic_console.console_thread, NULL,
++ virtio_console, mic);
++ if (err)
++ mpsslog("%s virtcons pthread_create failed %s\n",
++ mic->name, strerror(err));
++ err = pthread_create(&mic->mic_net.net_thread, NULL,
++ virtio_net, mic);
++ if (err)
++ mpsslog("%s virtnet pthread_create failed %s\n",
++ mic->name, strerror(err));
++ err = pthread_create(&mic->mic_virtblk.block_thread, NULL,
++ virtio_block, mic);
++ if (err)
++ mpsslog("%s virtblk pthread_create failed %s\n",
++ mic->name, strerror(err));
++ sigemptyset(&act.sa_mask);
++ err = sigaction(SIGUSR1, &act, NULL);
++ if (err)
++ mpsslog("%s sigaction SIGUSR1 failed %s\n",
++ mic->name, strerror(errno));
++ while (1)
++ sleep(60);
++ case -1:
++ mpsslog("fork failed MIC name %s id %d errno %d\n",
++ mic->name, mic->id, errno);
++ break;
++ default:
++ err = pthread_create(&mic->config_thread, NULL,
++ mic_config, mic);
++ if (err)
++ mpsslog("%s mic_config pthread_create failed %s\n",
++ mic->name, strerror(err));
++ }
++
++ return NULL;
++}
++
++static void
++start_daemon(void)
++{
++ struct mic_info *mic;
++ int err;
++
++ for (mic = mic_list.next; mic; mic = mic->next) {
++ set_mic_boot_params(mic);
++ err = pthread_create(&mic->init_thread, NULL, init_mic, mic);
++ if (err)
++ mpsslog("%s init_mic pthread_create failed %s\n",
++ mic->name, strerror(err));
++ }
++
++ while (1)
++ sleep(60);
++}
++
++static int
++init_mic_list(void)
++{
++ struct mic_info *mic = &mic_list;
++ struct dirent *file;
++ DIR *dp;
++ int cnt = 0;
++
++ dp = opendir(MICSYSFSDIR);
++ if (!dp)
++ return 0;
++
++ while ((file = readdir(dp)) != NULL) {
++ if (!strncmp(file->d_name, "mic", 3)) {
++ mic->next = calloc(1, sizeof(struct mic_info));
++ if (mic->next) {
++ mic = mic->next;
++ mic->id = atoi(&file->d_name[3]);
++ mic->name = malloc(strlen(file->d_name) + 16);
++ if (mic->name)
++ strcpy(mic->name, file->d_name);
++ mpsslog("MIC name %s id %d\n", mic->name,
++ mic->id);
++ cnt++;
++ }
++ }
++ }
++
++ closedir(dp);
++ return cnt;
++}
++
++void
++mpsslog(char *format, ...)
++{
++ va_list args;
++ char buffer[4096];
++ char ts[52], *ts1;
++ time_t t;
++
++ if (logfp == NULL)
++ return;
++
++ va_start(args, format);
++ vsprintf(buffer, format, args);
++ va_end(args);
++
++ time(&t);
++ ts1 = ctime_r(&t, ts);
++ ts1[strlen(ts1) - 1] = '\0';
++ fprintf(logfp, "%s: %s", ts1, buffer);
++
++ fflush(logfp);
++}
++
++int
++main(int argc, char *argv[])
++{
++ int cnt;
++ pid_t pid;
++
++ myname = argv[0];
++
++ logfp = fopen(LOGFILE_NAME, "a+");
++ if (!logfp) {
++ fprintf(stderr, "cannot open logfile '%s'\n", LOGFILE_NAME);
++ exit(1);
++ }
++ pid = fork();
++ switch (pid) {
++ case 0:
++ break;
++ case -1:
++ exit(2);
++ default:
++ exit(0);
++ }
++
++ mpsslog("MIC Daemon start\n");
++
++ cnt = init_mic_list();
++ if (cnt == 0) {
++ mpsslog("MIC module not loaded\n");
++ exit(3);
++ }
++ mpsslog("MIC found %d devices\n", cnt);
++
++ start_daemon();
++
++ exit(0);
++}
+diff --git a/samples/mic/mpssd/mpssd.h b/samples/mic/mpssd/mpssd.h
+new file mode 100644
+index 000000000000..8bd64944aacc
+--- /dev/null
++++ b/samples/mic/mpssd/mpssd.h
+@@ -0,0 +1,103 @@
++/*
++ * Intel MIC Platform Software Stack (MPSS)
++ *
++ * Copyright(c) 2013 Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License, version 2, as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ * Intel MIC User Space Tools.
++ */
++#ifndef _MPSSD_H_
++#define _MPSSD_H_
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <dirent.h>
++#include <libgen.h>
++#include <pthread.h>
++#include <stdarg.h>
++#include <time.h>
++#include <errno.h>
++#include <sys/dir.h>
++#include <sys/ioctl.h>
++#include <sys/poll.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <sys/mman.h>
++#include <sys/utsname.h>
++#include <sys/wait.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <netdb.h>
++#include <pthread.h>
++#include <signal.h>
++#include <limits.h>
++#include <syslog.h>
++#include <getopt.h>
++#include <net/if.h>
++#include <linux/if_tun.h>
++#include <linux/if_tun.h>
++#include <linux/virtio_ids.h>
++
++#define MICSYSFSDIR "/sys/class/mic"
++#define LOGFILE_NAME "/var/log/mpssd"
++#define PAGE_SIZE 4096
++
++struct mic_console_info {
++ pthread_t console_thread;
++ int virtio_console_fd;
++ void *console_dp;
++};
++
++struct mic_net_info {
++ pthread_t net_thread;
++ int virtio_net_fd;
++ int tap_fd;
++ void *net_dp;
++};
++
++struct mic_virtblk_info {
++ pthread_t block_thread;
++ int virtio_block_fd;
++ void *block_dp;
++ volatile sig_atomic_t signaled;
++ char *backend_file;
++ int backend;
++ void *backend_addr;
++ long backend_size;
++};
++
++struct mic_info {
++ int id;
++ char *name;
++ pthread_t config_thread;
++ pthread_t init_thread;
++ pid_t pid;
++ struct mic_console_info mic_console;
++ struct mic_net_info mic_net;
++ struct mic_virtblk_info mic_virtblk;
++ int restart;
++ int boot_on_resume;
++ struct mic_info *next;
++};
++
++__attribute__((format(printf, 1, 2)))
++void mpsslog(char *format, ...);
++char *readsysfs(char *dir, char *entry);
++int setsysfs(char *dir, char *entry, char *value);
++#endif
+diff --git a/samples/mic/mpssd/sysfs.c b/samples/mic/mpssd/sysfs.c
+new file mode 100644
+index 000000000000..8dd326936083
+--- /dev/null
++++ b/samples/mic/mpssd/sysfs.c
+@@ -0,0 +1,102 @@
++/*
++ * Intel MIC Platform Software Stack (MPSS)
++ *
++ * Copyright(c) 2013 Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License, version 2, as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ * Intel MIC User Space Tools.
++ */
++
++#include "mpssd.h"
++
++#define PAGE_SIZE 4096
++
++char *
++readsysfs(char *dir, char *entry)
++{
++ char filename[PATH_MAX];
++ char value[PAGE_SIZE];
++ char *string = NULL;
++ int fd;
++ int len;
++
++ if (dir == NULL)
++ snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry);
++ else
++ snprintf(filename, PATH_MAX,
++ "%s/%s/%s", MICSYSFSDIR, dir, entry);
++
++ fd = open(filename, O_RDONLY);
++ if (fd < 0) {
++ mpsslog("Failed to open sysfs entry '%s': %s\n",
++ filename, strerror(errno));
++ return NULL;
++ }
++
++ len = read(fd, value, sizeof(value));
++ if (len < 0) {
++ mpsslog("Failed to read sysfs entry '%s': %s\n",
++ filename, strerror(errno));
++ goto readsys_ret;
++ }
++ if (len == 0)
++ goto readsys_ret;
++
++ value[len - 1] = '\0';
++
++ string = malloc(strlen(value) + 1);
++ if (string)
++ strcpy(string, value);
++
++readsys_ret:
++ close(fd);
++ return string;
++}
++
++int
++setsysfs(char *dir, char *entry, char *value)
++{
++ char filename[PATH_MAX];
++ char *oldvalue;
++ int fd, ret = 0;
++
++ if (dir == NULL)
++ snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry);
++ else
++ snprintf(filename, PATH_MAX, "%s/%s/%s",
++ MICSYSFSDIR, dir, entry);
++
++ oldvalue = readsysfs(dir, entry);
++
++ fd = open(filename, O_RDWR);
++ if (fd < 0) {
++ ret = errno;
++ mpsslog("Failed to open sysfs entry '%s': %s\n",
++ filename, strerror(errno));
++ goto done;
++ }
++
++ if (!oldvalue || strcmp(value, oldvalue)) {
++ if (write(fd, value, strlen(value)) < 0) {
++ ret = errno;
++ mpsslog("Failed to write new sysfs entry '%s': %s\n",
++ filename, strerror(errno));
++ }
++ }
++ close(fd);
++done:
++ if (oldvalue)
++ free(oldvalue);
++ return ret;
++}
+diff --git a/samples/seccomp/bpf-helper.h b/samples/seccomp/bpf-helper.h
+index 38ee70f3cd5b..1d8de9edd858 100644
+--- a/samples/seccomp/bpf-helper.h
++++ b/samples/seccomp/bpf-helper.h
+@@ -138,7 +138,7 @@ union arg64 {
+ #define ARG_32(idx) \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx))
+
+-/* Loads hi into A and lo in X */
++/* Loads lo into M[0] and hi into M[1] and A */
+ #define ARG_64(idx) \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)), \
+ BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \
+@@ -153,88 +153,107 @@ union arg64 {
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 1, 0), \
+ jt
+
+-/* Checks the lo, then swaps to check the hi. A=lo,X=hi */
++#define JA32(value, jt) \
++ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \
++ jt
++
++#define JGE32(value, jt) \
++ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \
++ jt
++
++#define JGT32(value, jt) \
++ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \
++ jt
++
++#define JLE32(value, jt) \
++ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \
++ jt
++
++#define JLT32(value, jt) \
++ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \
++ jt
++
++/*
++ * All the JXX64 checks assume lo is saved in M[0] and hi is saved in both
++ * A and M[1]. This invariant is kept by restoring A if necessary.
++ */
+ #define JEQ64(lo, hi, jt) \
++ /* if (hi != arg.hi) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
++ /* if (lo != arg.lo) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \
+- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
++ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
++ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+ #define JNE64(lo, hi, jt) \
+- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 5, 0), \
+- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
++ /* if (hi != arg.hi) goto MATCH; */ \
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \
++ BPF_STMT(BPF_LD+BPF_MEM, 0), \
++ /* if (lo != arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \
+- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
++ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+-
+-#define JA32(value, jt) \
+- BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \
+- jt
++ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+ #define JA64(lo, hi, jt) \
++ /* if (hi & arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \
+- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
++ BPF_STMT(BPF_LD+BPF_MEM, 0), \
++ /* if (lo & arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \
+- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
++ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
++ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+-#define JGE32(value, jt) \
+- BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \
+- jt
+-
+-#define JLT32(value, jt) \
+- BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \
+- jt
+-
+-/* Shortcut checking if hi > arg.hi. */
+ #define JGE64(lo, hi, jt) \
++ /* if (hi > arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
++ /* if (hi != arg.hi) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
++ BPF_STMT(BPF_LD+BPF_MEM, 0), \
++ /* if (lo >= arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \
+- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+- jt, \
+- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+-
+-#define JLT64(lo, hi, jt) \
+- BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
+- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+- BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \
+- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
++ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
++ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+-#define JGT32(value, jt) \
+- BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \
+- jt
+-
+-#define JLE32(value, jt) \
+- BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \
+- jt
+-
+-/* Check hi > args.hi first, then do the GE checking */
+ #define JGT64(lo, hi, jt) \
++ /* if (hi > arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
++ /* if (hi != arg.hi) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
++ BPF_STMT(BPF_LD+BPF_MEM, 0), \
++ /* if (lo > arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \
+- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
++ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
++ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+ #define JLE64(lo, hi, jt) \
+- BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 6, 0), \
+- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \
+- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
++ /* if (hi < arg.hi) goto MATCH; */ \
++ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
++ /* if (hi != arg.hi) goto NOMATCH; */ \
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
++ BPF_STMT(BPF_LD+BPF_MEM, 0), \
++ /* if (lo <= arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \
+- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
++ BPF_STMT(BPF_LD+BPF_MEM, 1), \
++ jt, \
++ BPF_STMT(BPF_LD+BPF_MEM, 1)
++
++#define JLT64(lo, hi, jt) \
++ /* if (hi < arg.hi) goto MATCH; */ \
++ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
++ /* if (hi != arg.hi) goto NOMATCH; */ \
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
++ BPF_STMT(BPF_LD+BPF_MEM, 0), \
++ /* if (lo < arg.lo) goto MATCH; */ \
++ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 2, 0), \
++ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
++ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+ #define LOAD_SYSCALL_NR \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
+diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
+index 1d5acbe0c08b..86240d02b530 100644
+--- a/sound/core/seq/seq_fifo.c
++++ b/sound/core/seq/seq_fifo.c
+@@ -135,6 +135,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
+ f->tail = cell;
+ if (f->head == NULL)
+ f->head = cell;
++ cell->next = NULL;
+ f->cells++;
+ spin_unlock_irqrestore(&f->lock, flags);
+
+@@ -214,6 +215,8 @@ void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
+ spin_lock_irqsave(&f->lock, flags);
+ cell->next = f->head;
+ f->head = cell;
++ if (!f->tail)
++ f->tail = cell;
+ f->cells++;
+ spin_unlock_irqrestore(&f->lock, flags);
+ }
+diff --git a/sound/core/timer.c b/sound/core/timer.c
+index ae4ea2e2e7fe..278a332f97bd 100644
+--- a/sound/core/timer.c
++++ b/sound/core/timer.c
+@@ -1700,9 +1700,21 @@ static int snd_timer_user_params(struct file *file,
+ return -EBADFD;
+ if (copy_from_user(&params, _params, sizeof(params)))
+ return -EFAULT;
+- if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
+- err = -EINVAL;
+- goto _end;
++ if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
++ u64 resolution;
++
++ if (params.ticks < 1) {
++ err = -EINVAL;
++ goto _end;
++ }
++
++ /* Don't allow resolution less than 1ms */
++ resolution = snd_timer_resolution(tu->timeri);
++ resolution *= params.ticks;
++ if (resolution < 1000000) {
++ err = -EINVAL;
++ goto _end;
++ }
+ }
+ if (params.queue_size > 0 &&
+ (params.queue_size < 32 || params.queue_size > 1024)) {
+diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
+index 9667cbfb0ca2..ab4cdab5cfa5 100644
+--- a/sound/pci/ctxfi/cthw20k1.c
++++ b/sound/pci/ctxfi/cthw20k1.c
+@@ -27,12 +27,6 @@
+ #include "cthw20k1.h"
+ #include "ct20k1reg.h"
+
+-#if BITS_PER_LONG == 32
+-#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
+-#else
+-#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
+-#endif
+-
+ struct hw20k1 {
+ struct hw hw;
+ spinlock_t reg_20k1_lock;
+@@ -1904,19 +1898,18 @@ static int hw_card_start(struct hw *hw)
+ {
+ int err;
+ struct pci_dev *pci = hw->pci;
++ const unsigned int dma_bits = BITS_PER_LONG;
+
+ err = pci_enable_device(pci);
+ if (err < 0)
+ return err;
+
+ /* Set DMA transfer mask */
+- if (dma_set_mask(&pci->dev, CT_XFI_DMA_MASK) < 0 ||
+- dma_set_coherent_mask(&pci->dev, CT_XFI_DMA_MASK) < 0) {
+- dev_err(hw->card->dev,
+- "architecture does not support PCI busmaster DMA with mask 0x%llx\n",
+- CT_XFI_DMA_MASK);
+- err = -ENXIO;
+- goto error1;
++ if (dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
++ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
++ } else {
++ dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
++ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
+ }
+
+ if (!hw->io_base) {
+diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
+index 9dc2950e1ab7..d86678c2a957 100644
+--- a/sound/pci/ctxfi/cthw20k2.c
++++ b/sound/pci/ctxfi/cthw20k2.c
+@@ -26,12 +26,6 @@
+ #include "cthw20k2.h"
+ #include "ct20k2reg.h"
+
+-#if BITS_PER_LONG == 32
+-#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
+-#else
+-#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
+-#endif
+-
+ struct hw20k2 {
+ struct hw hw;
+ /* for i2c */
+@@ -2029,19 +2023,18 @@ static int hw_card_start(struct hw *hw)
+ int err = 0;
+ struct pci_dev *pci = hw->pci;
+ unsigned int gctl;
++ const unsigned int dma_bits = BITS_PER_LONG;
+
+ err = pci_enable_device(pci);
+ if (err < 0)
+ return err;
+
+ /* Set DMA transfer mask */
+- if (dma_set_mask(&pci->dev, CT_XFI_DMA_MASK) < 0 ||
+- dma_set_coherent_mask(&pci->dev, CT_XFI_DMA_MASK) < 0) {
+- dev_err(hw->card->dev,
+- "architecture does not support PCI busmaster DMA with mask 0x%llx\n",
+- CT_XFI_DMA_MASK);
+- err = -ENXIO;
+- goto error1;
++ if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
++ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
++ } else {
++ dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
++ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
+ }
+
+ if (!hw->io_base) {
+diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
+index ad4a1e9a3ae1..8f3e5e9d8bdb 100644
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -2208,9 +2208,9 @@ static const struct pci_device_id azx_ids[] = {
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ /* Lewisburg */
+ { PCI_DEVICE(0x8086, 0xa1f0),
+- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
++ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
+ { PCI_DEVICE(0x8086, 0xa270),
+- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
++ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
+ /* Lynx Point-LP */
+ { PCI_DEVICE(0x8086, 0x9c20),
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 00c50d58f108..cf0785ddbd14 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -5560,6 +5560,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
+ SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
+ SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
++ SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
+ SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
+@@ -5674,6 +5675,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
+ SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+ SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
++ SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+ SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
+ SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
+ SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
+@@ -6047,6 +6049,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
+ SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC298_STANDARD_PINS,
+ {0x17, 0x90170150}),
++ SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_SPK_VOLUME,
++ {0x12, 0xb7a60140},
++ {0x13, 0xb7a60150},
++ {0x17, 0x90170110},
++ {0x1a, 0x03011020},
++ {0x21, 0x03211030}),
+ {}
+ };
+