mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-25 08:11:45 +00:00
8444 lines
228 KiB
Diff
8444 lines
228 KiB
Diff
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}),
|
|
{}
|
|
};
|
|
|