diff options
author | 2017-03-12 08:17:37 -0400 | |
---|---|---|
committer | 2017-03-12 08:17:37 -0400 | |
commit | 91367744ce5b3751a6e8288292d5d2692aaff55f (patch) | |
tree | c98b4264ed278cac4462a93e3990604a2c84128d | |
parent | Enable crypto API for systemd as its required for systemd versions >= 233. Se... (diff) | |
download | linux-patches-91367744ce5b3751a6e8288292d5d2692aaff55f.tar.gz linux-patches-91367744ce5b3751a6e8288292d5d2692aaff55f.tar.bz2 linux-patches-91367744ce5b3751a6e8288292d5d2692aaff55f.zip |
Linux patch 4.4.534.4-57
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1052_linux-4.4.53.patch | 8444 |
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, ©, +- len); +- +- err = mic_virtio_copy(mic, +- mic->mic_net.virtio_net_fd, &tx_vr, +- ©); +- if (err < 0) { +- mpsslog("%s %s %d mic_virtio_copy %s\n", +- mic->name, __func__, __LINE__, +- strerror(errno)); +- } +- if (!err) +- verify_out_len(mic, ©); +-#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(©)); +-#endif +- /* Reinitialize IOV for next run */ +- iov0[1].iov_len = MAX_NET_PKT_SIZE; +- } else if (len < 0) { +- disp_iovec(mic, ©, __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(©)); +- } +- } +- +- /* +- * 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, ©, +- MAX_NET_PKT_SIZE +- + sizeof(struct virtio_net_hdr)); +- +- err = mic_virtio_copy(mic, +- mic->mic_net.virtio_net_fd, &rx_vr, +- ©); +- 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, ©); +-#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(©)) { +- mpsslog("Tun write failed %s ", +- strerror(errno)); +- mpsslog("len 0x%zx ", len); +- mpsslog("read_len 0x%zx\n", +- sum_iovec_len(©)); +- } else { +-#ifdef DEBUG +- disp_iovec(mic, ©, __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, +- ©, len); +- +- err = mic_virtio_copy(mic, +- mic->mic_console.virtio_console_fd, +- &tx_vr, ©); +- if (err < 0) { +- mpsslog("%s %s %d mic_virtio_copy %s\n", +- mic->name, __func__, __LINE__, +- strerror(errno)); +- } +- if (!err) +- verify_out_len(mic, ©); +-#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, ©, __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(©)); +- } +- } +- +- 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, +- ©, PAGE_SIZE); +- +- err = mic_virtio_copy(mic, +- mic->mic_console.virtio_console_fd, +- &rx_vr, ©); +- if (!err) { +- /* Set the correct output iov_len */ +- iov1->iov_len = copy.out_len; +- verify_out_len(mic, ©); +-#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(©)) { +- mpsslog("Tun write failed %s ", +- strerror(errno)); +- mpsslog("len 0x%zx ", len); +- mpsslog("read_len 0x%zx\n", +- sum_iovec_len(©)); +- } 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, ©); +-} +- +-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, ©); +-} +- +-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, ©); +-} +- +-#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 == ®ulator_class) ++ if (consumer->dev && consumer->dev->class == ®ulator_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, ©, ++ len); ++ ++ err = mic_virtio_copy(mic, ++ mic->mic_net.virtio_net_fd, &tx_vr, ++ ©); ++ if (err < 0) { ++ mpsslog("%s %s %d mic_virtio_copy %s\n", ++ mic->name, __func__, __LINE__, ++ strerror(errno)); ++ } ++ if (!err) ++ verify_out_len(mic, ©); ++#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(©)); ++#endif ++ /* Reinitialize IOV for next run */ ++ iov0[1].iov_len = MAX_NET_PKT_SIZE; ++ } else if (len < 0) { ++ disp_iovec(mic, ©, __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(©)); ++ } ++ } ++ ++ /* ++ * 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, ©, ++ MAX_NET_PKT_SIZE ++ + sizeof(struct virtio_net_hdr)); ++ ++ err = mic_virtio_copy(mic, ++ mic->mic_net.virtio_net_fd, &rx_vr, ++ ©); ++ 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, ©); ++#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(©)) { ++ mpsslog("Tun write failed %s ", ++ strerror(errno)); ++ mpsslog("len 0x%zx ", len); ++ mpsslog("read_len 0x%zx\n", ++ sum_iovec_len(©)); ++ } else { ++#ifdef DEBUG ++ disp_iovec(mic, ©, __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, ++ ©, len); ++ ++ err = mic_virtio_copy(mic, ++ mic->mic_console.virtio_console_fd, ++ &tx_vr, ©); ++ if (err < 0) { ++ mpsslog("%s %s %d mic_virtio_copy %s\n", ++ mic->name, __func__, __LINE__, ++ strerror(errno)); ++ } ++ if (!err) ++ verify_out_len(mic, ©); ++#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, ©, __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(©)); ++ } ++ } ++ ++ 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, ++ ©, PAGE_SIZE); ++ ++ err = mic_virtio_copy(mic, ++ mic->mic_console.virtio_console_fd, ++ &rx_vr, ©); ++ if (!err) { ++ /* Set the correct output iov_len */ ++ iov1->iov_len = copy.out_len; ++ verify_out_len(mic, ©); ++#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(©)) { ++ mpsslog("Tun write failed %s ", ++ strerror(errno)); ++ mpsslog("len 0x%zx ", len); ++ mpsslog("read_len 0x%zx\n", ++ sum_iovec_len(©)); ++ } 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, ©); ++} ++ ++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, ©); ++} ++ ++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, ©); ++} ++ ++#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(¶ms, _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}), + {} + }; + |