aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShuah Khan2016-09-16 16:53:52 -0500
committerGreg Kroah-Hartman2017-03-11 23:37:23 -0600
commitfaf6aa4b129d2edb80a95a4b61f955fda5a194f4 (patch)
tree7004761a754aacc95d8eec5fd0f165a11aa49ee2 /Documentation
parentdd4534d88b93a911983503851ec9441787a4997d (diff)
downloadti-linux-kernel-faf6aa4b129d2edb80a95a4b61f955fda5a194f4.tar.gz
ti-linux-kernel-faf6aa4b129d2edb80a95a4b61f955fda5a194f4.tar.xz
ti-linux-kernel-faf6aa4b129d2edb80a95a4b61f955fda5a194f4.zip
samples: move mic/mpssd example code from Documentation
commit 6bee835dd54e279f3d3ae2eca92a9c394b4fd028 upstream. Move mic/mpssd examples to samples and remove it from Documentation Makefile. Create a new Makefile to build mic/mpssd. It can be built from top level directory or from mic/mpssd directory: Run make -C samples/mic/mpssd or cd samples/mic/mpssd; make Acked-by: Jonathan Corbet <corbet@lwn.net> Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com> [backported to 4.4-stable as this code is broken on newer versions of gcc and we don't want to break the build for a Documentation sample. - gregkh] Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'Documentation')
-rw-r--r--Documentation/Makefile2
-rw-r--r--Documentation/mic/Makefile1
-rw-r--r--Documentation/mic/mpssd/.gitignore1
-rw-r--r--Documentation/mic/mpssd/Makefile21
-rwxr-xr-xDocumentation/mic/mpssd/micctrl173
-rwxr-xr-xDocumentation/mic/mpssd/mpss200
-rw-r--r--Documentation/mic/mpssd/mpssd.c1826
-rw-r--r--Documentation/mic/mpssd/mpssd.h103
-rw-r--r--Documentation/mic/mpssd/sysfs.c102
9 files changed, 1 insertions, 2428 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile
index bc0548201755..fc759598c4c9 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,4 +1,4 @@
1subdir-y := accounting auxdisplay blackfin connector \ 1subdir-y := accounting auxdisplay blackfin connector \
2 filesystems filesystems ia64 laptops mic misc-devices \ 2 filesystems filesystems ia64 laptops misc-devices \
3 networking pcmcia prctl ptp spi timers vDSO video4linux \ 3 networking pcmcia prctl ptp spi timers vDSO video4linux \
4 watchdog 4 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 @@
1subdir-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 @@
1mpssd
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 @@
1ifndef CROSS_COMPILE
2# List of programs to build
3hostprogs-$(CONFIG_X86_64) := mpssd
4
5mpssd-objs := mpssd.o sysfs.o
6
7# Tell kbuild to always build the programs
8always := $(hostprogs-y)
9
10HOSTCFLAGS += -I$(objtree)/usr/include -I$(srctree)/tools/include
11
12ifdef DEBUG
13HOSTCFLAGS += -DDEBUG=$(DEBUG)
14endif
15
16HOSTLOADLIBES_mpssd := -lpthread
17
18install:
19 install mpssd /usr/sbin/mpssd
20 install micctrl /usr/sbin/micctrl
21endif
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 @@
1#!/bin/bash
2# Intel MIC Platform Software Stack (MPSS)
3#
4# Copyright(c) 2013 Intel Corporation.
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License, version 2, as
8# published by the Free Software Foundation.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# The full GNU General Public License is included in this distribution in
16# the file called "COPYING".
17#
18# Intel MIC User Space Tools.
19#
20# micctrl - Controls MIC boot/start/stop.
21#
22# chkconfig: 2345 95 05
23# description: start MPSS stack processing.
24#
25### BEGIN INIT INFO
26# Provides: micctrl
27### END INIT INFO
28
29# Source function library.
30. /etc/init.d/functions
31
32sysfs="/sys/class/mic"
33
34_status()
35{
36 f=$sysfs/$1
37 echo -e $1 state: "`cat $f/state`" shutdown_status: "`cat $f/shutdown_status`"
38}
39
40status()
41{
42 if [ "`echo $1 | head -c3`" == "mic" ]; then
43 _status $1
44 return $?
45 fi
46 for f in $sysfs/*
47 do
48 _status `basename $f`
49 RETVAL=$?
50 [ $RETVAL -ne 0 ] && return $RETVAL
51 done
52 return 0
53}
54
55_reset()
56{
57 f=$sysfs/$1
58 echo reset > $f/state
59}
60
61reset()
62{
63 if [ "`echo $1 | head -c3`" == "mic" ]; then
64 _reset $1
65 return $?
66 fi
67 for f in $sysfs/*
68 do
69 _reset `basename $f`
70 RETVAL=$?
71 [ $RETVAL -ne 0 ] && return $RETVAL
72 done
73 return 0
74}
75
76_boot()
77{
78 f=$sysfs/$1
79 echo "linux" > $f/bootmode
80 echo "mic/uos.img" > $f/firmware
81 echo "mic/$1.image" > $f/ramdisk
82 echo "boot" > $f/state
83}
84
85boot()
86{
87 if [ "`echo $1 | head -c3`" == "mic" ]; then
88 _boot $1
89 return $?
90 fi
91 for f in $sysfs/*
92 do
93 _boot `basename $f`
94 RETVAL=$?
95 [ $RETVAL -ne 0 ] && return $RETVAL
96 done
97 return 0
98}
99
100_shutdown()
101{
102 f=$sysfs/$1
103 echo shutdown > $f/state
104}
105
106shutdown()
107{
108 if [ "`echo $1 | head -c3`" == "mic" ]; then
109 _shutdown $1
110 return $?
111 fi
112 for f in $sysfs/*
113 do
114 _shutdown `basename $f`
115 RETVAL=$?
116 [ $RETVAL -ne 0 ] && return $RETVAL
117 done
118 return 0
119}
120
121_wait()
122{
123 f=$sysfs/$1
124 while [ "`cat $f/state`" != "offline" -a "`cat $f/state`" != "online" ]
125 do
126 sleep 1
127 echo -e "Waiting for $1 to go offline"
128 done
129}
130
131wait()
132{
133 if [ "`echo $1 | head -c3`" == "mic" ]; then
134 _wait $1
135 return $?
136 fi
137 # Wait for the cards to go offline
138 for f in $sysfs/*
139 do
140 _wait `basename $f`
141 RETVAL=$?
142 [ $RETVAL -ne 0 ] && return $RETVAL
143 done
144 return 0
145}
146
147if [ ! -d "$sysfs" ]; then
148 echo -e $"Module unloaded "
149 exit 3
150fi
151
152case $1 in
153 -s)
154 status $2
155 ;;
156 -r)
157 reset $2
158 ;;
159 -b)
160 boot $2
161 ;;
162 -S)
163 shutdown $2
164 ;;
165 -w)
166 wait $2
167 ;;
168 *)
169 echo $"Usage: $0 {-s (status) |-r (reset) |-b (boot) |-S (shutdown) |-w (wait)}"
170 exit 2
171esac
172
173exit $?
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 @@
1#!/bin/bash
2# Intel MIC Platform Software Stack (MPSS)
3#
4# Copyright(c) 2013 Intel Corporation.
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License, version 2, as
8# published by the Free Software Foundation.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# The full GNU General Public License is included in this distribution in
16# the file called "COPYING".
17#
18# Intel MIC User Space Tools.
19#
20# mpss Start mpssd.
21#
22# chkconfig: 2345 95 05
23# description: start MPSS stack processing.
24#
25### BEGIN INIT INFO
26# Provides: mpss
27# Required-Start:
28# Required-Stop:
29# Short-Description: MPSS stack control
30# Description: MPSS stack control
31### END INIT INFO
32
33# Source function library.
34. /etc/init.d/functions
35
36exec=/usr/sbin/mpssd
37sysfs="/sys/class/mic"
38mic_modules="mic_host mic_x100_dma scif"
39
40start()
41{
42 [ -x $exec ] || exit 5
43
44 if [ "`ps -e | awk '{print $4}' | grep mpssd | head -1`" = "mpssd" ]; then
45 echo -e $"MPSSD already running! "
46 success
47 echo
48 return 0
49 fi
50
51 echo -e $"Starting MPSS Stack"
52 echo -e $"Loading MIC drivers:" $mic_modules
53
54 modprobe -a $mic_modules
55 RETVAL=$?
56 if [ $RETVAL -ne 0 ]; then
57 failure
58 echo
59 return $RETVAL
60 fi
61
62 # Start the daemon
63 echo -n $"Starting MPSSD "
64 $exec
65 RETVAL=$?
66 if [ $RETVAL -ne 0 ]; then
67 failure
68 echo
69 return $RETVAL
70 fi
71 success
72 echo
73
74 sleep 5
75
76 # Boot the cards
77 micctrl -b
78
79 # Wait till ping works
80 for f in $sysfs/*
81 do
82 count=100
83 ipaddr=`cat $f/cmdline`
84 ipaddr=${ipaddr#*address,}
85 ipaddr=`echo $ipaddr | cut -d, -f1 | cut -d\; -f1`
86 while [ $count -ge 0 ]
87 do
88 echo -e "Pinging "`basename $f`" "
89 ping -c 1 $ipaddr &> /dev/null
90 RETVAL=$?
91 if [ $RETVAL -eq 0 ]; then
92 success
93 break
94 fi
95 sleep 1
96 count=`expr $count - 1`
97 done
98 [ $RETVAL -ne 0 ] && failure || success
99 echo
100 done
101 return $RETVAL
102}
103
104stop()
105{
106 echo -e $"Shutting down MPSS Stack: "
107
108 # Bail out if module is unloaded
109 if [ ! -d "$sysfs" ]; then
110 echo -n $"Module unloaded "
111 success
112 echo
113 return 0
114 fi
115
116 # Shut down the cards.
117 micctrl -S
118
119 # Wait for the cards to go offline
120 for f in $sysfs/*
121 do
122 while [ "`cat $f/state`" != "ready" ]
123 do
124 sleep 1
125 echo -e "Waiting for "`basename $f`" to become ready"
126 done
127 done
128
129 # Display the status of the cards
130 micctrl -s
131
132 # Kill MPSSD now
133 echo -n $"Killing MPSSD"
134 killall -9 mpssd 2>/dev/null
135 RETVAL=$?
136 [ $RETVAL -ne 0 ] && failure || success
137 echo
138 return $RETVAL
139}
140
141restart()
142{
143 stop
144 sleep 5
145 start
146}
147
148status()
149{
150 micctrl -s
151 if [ "`ps -e | awk '{print $4}' | grep mpssd | head -n 1`" = "mpssd" ]; then
152 echo "mpssd is running"
153 else
154 echo "mpssd is stopped"
155 fi
156 return 0
157}
158
159unload()
160{
161 if [ ! -d "$sysfs" ]; then
162 echo -n $"No MIC_HOST Module: "
163 success
164 echo
165 return
166 fi
167
168 stop
169
170 sleep 5
171 echo -n $"Removing MIC drivers:" $mic_modules
172 modprobe -r $mic_modules
173 RETVAL=$?
174 [ $RETVAL -ne 0 ] && failure || success
175 echo
176 return $RETVAL
177}
178
179case $1 in
180 start)
181 start
182 ;;
183 stop)
184 stop
185 ;;
186 restart)
187 restart
188 ;;
189 status)
190 status
191 ;;
192 unload)
193 unload
194 ;;
195 *)
196 echo $"Usage: $0 {start|stop|restart|status|unload}"
197 exit 2
198esac
199
200exit $?
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 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2013 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
17 *
18 * Intel MIC User Space Tools.
19 */
20
21#define _GNU_SOURCE
22
23#include <stdlib.h>
24#include <fcntl.h>
25#include <getopt.h>
26#include <assert.h>
27#include <unistd.h>
28#include <stdbool.h>
29#include <signal.h>
30#include <poll.h>
31#include <features.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <sys/mman.h>
35#include <sys/socket.h>
36#include <linux/virtio_ring.h>
37#include <linux/virtio_net.h>
38#include <linux/virtio_console.h>
39#include <linux/virtio_blk.h>
40#include <linux/version.h>
41#include "mpssd.h"
42#include <linux/mic_ioctl.h>
43#include <linux/mic_common.h>
44#include <tools/endian.h>
45
46static void *init_mic(void *arg);
47
48static FILE *logfp;
49static struct mic_info mic_list;
50
51#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
52
53#define min_t(type, x, y) ({ \
54 type __min1 = (x); \
55 type __min2 = (y); \
56 __min1 < __min2 ? __min1 : __min2; })
57
58/* align addr on a size boundary - adjust address up/down if needed */
59#define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1)))
60#define _ALIGN_UP(addr, size) _ALIGN_DOWN(addr + size - 1, size)
61
62/* align addr on a size boundary - adjust address up if needed */
63#define _ALIGN(addr, size) _ALIGN_UP(addr, size)
64
65/* to align the pointer to the (next) page boundary */
66#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
67
68#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
69
70#define GSO_ENABLED 1
71#define MAX_GSO_SIZE (64 * 1024)
72#define ETH_H_LEN 14
73#define MAX_NET_PKT_SIZE (_ALIGN_UP(MAX_GSO_SIZE + ETH_H_LEN, 64))
74#define MIC_DEVICE_PAGE_END 0x1000
75
76#ifndef VIRTIO_NET_HDR_F_DATA_VALID
77#define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */
78#endif
79
80static struct {
81 struct mic_device_desc dd;
82 struct mic_vqconfig vqconfig[2];
83 __u32 host_features, guest_acknowledgements;
84 struct virtio_console_config cons_config;
85} virtcons_dev_page = {
86 .dd = {
87 .type = VIRTIO_ID_CONSOLE,
88 .num_vq = ARRAY_SIZE(virtcons_dev_page.vqconfig),
89 .feature_len = sizeof(virtcons_dev_page.host_features),
90 .config_len = sizeof(virtcons_dev_page.cons_config),
91 },
92 .vqconfig[0] = {
93 .num = htole16(MIC_VRING_ENTRIES),
94 },
95 .vqconfig[1] = {
96 .num = htole16(MIC_VRING_ENTRIES),
97 },
98};
99
100static struct {
101 struct mic_device_desc dd;
102 struct mic_vqconfig vqconfig[2];
103 __u32 host_features, guest_acknowledgements;
104 struct virtio_net_config net_config;
105} virtnet_dev_page = {
106 .dd = {
107 .type = VIRTIO_ID_NET,
108 .num_vq = ARRAY_SIZE(virtnet_dev_page.vqconfig),
109 .feature_len = sizeof(virtnet_dev_page.host_features),
110 .config_len = sizeof(virtnet_dev_page.net_config),
111 },
112 .vqconfig[0] = {
113 .num = htole16(MIC_VRING_ENTRIES),
114 },
115 .vqconfig[1] = {
116 .num = htole16(MIC_VRING_ENTRIES),
117 },
118#if GSO_ENABLED
119 .host_features = htole32(
120 1 << VIRTIO_NET_F_CSUM |
121 1 << VIRTIO_NET_F_GSO |
122 1 << VIRTIO_NET_F_GUEST_TSO4 |
123 1 << VIRTIO_NET_F_GUEST_TSO6 |
124 1 << VIRTIO_NET_F_GUEST_ECN),
125#else
126 .host_features = 0,
127#endif
128};
129
130static const char *mic_config_dir = "/etc/mpss";
131static const char *virtblk_backend = "VIRTBLK_BACKEND";
132static struct {
133 struct mic_device_desc dd;
134 struct mic_vqconfig vqconfig[1];
135 __u32 host_features, guest_acknowledgements;
136 struct virtio_blk_config blk_config;
137} virtblk_dev_page = {
138 .dd = {
139 .type = VIRTIO_ID_BLOCK,
140 .num_vq = ARRAY_SIZE(virtblk_dev_page.vqconfig),
141 .feature_len = sizeof(virtblk_dev_page.host_features),
142 .config_len = sizeof(virtblk_dev_page.blk_config),
143 },
144 .vqconfig[0] = {
145 .num = htole16(MIC_VRING_ENTRIES),
146 },
147 .host_features =
148 htole32(1<<VIRTIO_BLK_F_SEG_MAX),
149 .blk_config = {
150 .seg_max = htole32(MIC_VRING_ENTRIES - 2),
151 .capacity = htole64(0),
152 }
153};
154
155static char *myname;
156
157static int
158tap_configure(struct mic_info *mic, char *dev)
159{
160 pid_t pid;
161 char *ifargv[7];
162 char ipaddr[IFNAMSIZ];
163 int ret = 0;
164
165 pid = fork();
166 if (pid == 0) {
167 ifargv[0] = "ip";
168 ifargv[1] = "link";
169 ifargv[2] = "set";
170 ifargv[3] = dev;
171 ifargv[4] = "up";
172 ifargv[5] = NULL;
173 mpsslog("Configuring %s\n", dev);
174 ret = execvp("ip", ifargv);
175 if (ret < 0) {
176 mpsslog("%s execvp failed errno %s\n",
177 mic->name, strerror(errno));
178 return ret;
179 }
180 }
181 if (pid < 0) {
182 mpsslog("%s fork failed errno %s\n",
183 mic->name, strerror(errno));
184 return ret;
185 }
186
187 ret = waitpid(pid, NULL, 0);
188 if (ret < 0) {
189 mpsslog("%s waitpid failed errno %s\n",
190 mic->name, strerror(errno));
191 return ret;
192 }
193
194 snprintf(ipaddr, IFNAMSIZ, "172.31.%d.254/24", mic->id + 1);
195
196 pid = fork();
197 if (pid == 0) {
198 ifargv[0] = "ip";
199 ifargv[1] = "addr";
200 ifargv[2] = "add";
201 ifargv[3] = ipaddr;
202 ifargv[4] = "dev";
203 ifargv[5] = dev;
204 ifargv[6] = NULL;
205 mpsslog("Configuring %s ipaddr %s\n", dev, ipaddr);
206 ret = execvp("ip", ifargv);
207 if (ret < 0) {
208 mpsslog("%s execvp failed errno %s\n",
209 mic->name, strerror(errno));
210 return ret;
211 }
212 }
213 if (pid < 0) {
214 mpsslog("%s fork failed errno %s\n",
215 mic->name, strerror(errno));
216 return ret;
217 }
218
219 ret = waitpid(pid, NULL, 0);
220 if (ret < 0) {
221 mpsslog("%s waitpid failed errno %s\n",
222 mic->name, strerror(errno));
223 return ret;
224 }
225 mpsslog("MIC name %s %s %d DONE!\n",
226 mic->name, __func__, __LINE__);
227 return 0;
228}
229
230static int tun_alloc(struct mic_info *mic, char *dev)
231{
232 struct ifreq ifr;
233 int fd, err;
234#if GSO_ENABLED
235 unsigned offload;
236#endif
237 fd = open("/dev/net/tun", O_RDWR);
238 if (fd < 0) {
239 mpsslog("Could not open /dev/net/tun %s\n", strerror(errno));
240 goto done;
241 }
242
243 memset(&ifr, 0, sizeof(ifr));
244
245 ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
246 if (*dev)
247 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
248
249 err = ioctl(fd, TUNSETIFF, (void *)&ifr);
250 if (err < 0) {
251 mpsslog("%s %s %d TUNSETIFF failed %s\n",
252 mic->name, __func__, __LINE__, strerror(errno));
253 close(fd);
254 return err;
255 }
256#if GSO_ENABLED
257 offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_TSO_ECN;
258
259 err = ioctl(fd, TUNSETOFFLOAD, offload);
260 if (err < 0) {
261 mpsslog("%s %s %d TUNSETOFFLOAD failed %s\n",
262 mic->name, __func__, __LINE__, strerror(errno));
263 close(fd);
264 return err;
265 }
266#endif
267 strcpy(dev, ifr.ifr_name);
268 mpsslog("Created TAP %s\n", dev);
269done:
270 return fd;
271}
272
273#define NET_FD_VIRTIO_NET 0
274#define NET_FD_TUN 1
275#define MAX_NET_FD 2
276
277static void set_dp(struct mic_info *mic, int type, void *dp)
278{
279 switch (type) {
280 case VIRTIO_ID_CONSOLE:
281 mic->mic_console.console_dp = dp;
282 return;
283 case VIRTIO_ID_NET:
284 mic->mic_net.net_dp = dp;
285 return;
286 case VIRTIO_ID_BLOCK:
287 mic->mic_virtblk.block_dp = dp;
288 return;
289 }
290 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
291 assert(0);
292}
293
294static void *get_dp(struct mic_info *mic, int type)
295{
296 switch (type) {
297 case VIRTIO_ID_CONSOLE:
298 return mic->mic_console.console_dp;
299 case VIRTIO_ID_NET:
300 return mic->mic_net.net_dp;
301 case VIRTIO_ID_BLOCK:
302 return mic->mic_virtblk.block_dp;
303 }
304 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
305 assert(0);
306 return NULL;
307}
308
309static struct mic_device_desc *get_device_desc(struct mic_info *mic, int type)
310{
311 struct mic_device_desc *d;
312 int i;
313 void *dp = get_dp(mic, type);
314
315 for (i = sizeof(struct mic_bootparam); i < PAGE_SIZE;
316 i += mic_total_desc_size(d)) {
317 d = dp + i;
318
319 /* End of list */
320 if (d->type == 0)
321 break;
322
323 if (d->type == -1)
324 continue;
325
326 mpsslog("%s %s d-> type %d d %p\n",
327 mic->name, __func__, d->type, d);
328
329 if (d->type == (__u8)type)
330 return d;
331 }
332 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
333 return NULL;
334}
335
336/* See comments in vhost.c for explanation of next_desc() */
337static unsigned next_desc(struct vring_desc *desc)
338{
339 unsigned int next;
340
341 if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT))
342 return -1U;
343 next = le16toh(desc->next);
344 return next;
345}
346
347/* Sum up all the IOVEC length */
348static ssize_t
349sum_iovec_len(struct mic_copy_desc *copy)
350{
351 ssize_t sum = 0;
352 int i;
353
354 for (i = 0; i < copy->iovcnt; i++)
355 sum += copy->iov[i].iov_len;
356 return sum;
357}
358
359static inline void verify_out_len(struct mic_info *mic,
360 struct mic_copy_desc *copy)
361{
362 if (copy->out_len != sum_iovec_len(copy)) {
363 mpsslog("%s %s %d BUG copy->out_len 0x%x len 0x%zx\n",
364 mic->name, __func__, __LINE__,
365 copy->out_len, sum_iovec_len(copy));
366 assert(copy->out_len == sum_iovec_len(copy));
367 }
368}
369
370/* Display an iovec */
371static void
372disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy,
373 const char *s, int line)
374{
375 int i;
376
377 for (i = 0; i < copy->iovcnt; i++)
378 mpsslog("%s %s %d copy->iov[%d] addr %p len 0x%zx\n",
379 mic->name, s, line, i,
380 copy->iov[i].iov_base, copy->iov[i].iov_len);
381}
382
383static inline __u16 read_avail_idx(struct mic_vring *vr)
384{
385 return ACCESS_ONCE(vr->info->avail_idx);
386}
387
388static inline void txrx_prepare(int type, bool tx, struct mic_vring *vr,
389 struct mic_copy_desc *copy, ssize_t len)
390{
391 copy->vr_idx = tx ? 0 : 1;
392 copy->update_used = true;
393 if (type == VIRTIO_ID_NET)
394 copy->iov[1].iov_len = len - sizeof(struct virtio_net_hdr);
395 else
396 copy->iov[0].iov_len = len;
397}
398
399/* Central API which triggers the copies */
400static int
401mic_virtio_copy(struct mic_info *mic, int fd,
402 struct mic_vring *vr, struct mic_copy_desc *copy)
403{
404 int ret;
405
406 ret = ioctl(fd, MIC_VIRTIO_COPY_DESC, copy);
407 if (ret) {
408 mpsslog("%s %s %d errno %s ret %d\n",
409 mic->name, __func__, __LINE__,
410 strerror(errno), ret);
411 }
412 return ret;
413}
414
415static inline unsigned _vring_size(unsigned int num, unsigned long align)
416{
417 return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (3 + num)
418 + align - 1) & ~(align - 1))
419 + sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
420}
421
422/*
423 * This initialization routine requires at least one
424 * vring i.e. vr0. vr1 is optional.
425 */
426static void *
427init_vr(struct mic_info *mic, int fd, int type,
428 struct mic_vring *vr0, struct mic_vring *vr1, int num_vq)
429{
430 int vr_size;
431 char *va;
432
433 vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES,
434 MIC_VIRTIO_RING_ALIGN) +
435 sizeof(struct _mic_vring_info));
436 va = mmap(NULL, MIC_DEVICE_PAGE_END + vr_size * num_vq,
437 PROT_READ, MAP_SHARED, fd, 0);
438 if (MAP_FAILED == va) {
439 mpsslog("%s %s %d mmap failed errno %s\n",
440 mic->name, __func__, __LINE__,
441 strerror(errno));
442 goto done;
443 }
444 set_dp(mic, type, va);
445 vr0->va = (struct mic_vring *)&va[MIC_DEVICE_PAGE_END];
446 vr0->info = vr0->va +
447 _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN);
448 vring_init(&vr0->vr,
449 MIC_VRING_ENTRIES, vr0->va, MIC_VIRTIO_RING_ALIGN);
450 mpsslog("%s %s vr0 %p vr0->info %p vr_size 0x%x vring 0x%x ",
451 __func__, mic->name, vr0->va, vr0->info, vr_size,
452 _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
453 mpsslog("magic 0x%x expected 0x%x\n",
454 le32toh(vr0->info->magic), MIC_MAGIC + type);
455 assert(le32toh(vr0->info->magic) == MIC_MAGIC + type);
456 if (vr1) {
457 vr1->va = (struct mic_vring *)
458 &va[MIC_DEVICE_PAGE_END + vr_size];
459 vr1->info = vr1->va + _vring_size(MIC_VRING_ENTRIES,
460 MIC_VIRTIO_RING_ALIGN);
461 vring_init(&vr1->vr,
462 MIC_VRING_ENTRIES, vr1->va, MIC_VIRTIO_RING_ALIGN);
463 mpsslog("%s %s vr1 %p vr1->info %p vr_size 0x%x vring 0x%x ",
464 __func__, mic->name, vr1->va, vr1->info, vr_size,
465 _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
466 mpsslog("magic 0x%x expected 0x%x\n",
467 le32toh(vr1->info->magic), MIC_MAGIC + type + 1);
468 assert(le32toh(vr1->info->magic) == MIC_MAGIC + type + 1);
469 }
470done:
471 return va;
472}
473
474static int
475wait_for_card_driver(struct mic_info *mic, int fd, int type)
476{
477 struct pollfd pollfd;
478 int err;
479 struct mic_device_desc *desc = get_device_desc(mic, type);
480 __u8 prev_status;
481
482 if (!desc)
483 return -ENODEV;
484 prev_status = desc->status;
485 pollfd.fd = fd;
486 mpsslog("%s %s Waiting .... desc-> type %d status 0x%x\n",
487 mic->name, __func__, type, desc->status);
488
489 while (1) {
490 pollfd.events = POLLIN;
491 pollfd.revents = 0;
492 err = poll(&pollfd, 1, -1);
493 if (err < 0) {
494 mpsslog("%s %s poll failed %s\n",
495 mic->name, __func__, strerror(errno));
496 continue;
497 }
498
499 if (pollfd.revents) {
500 if (desc->status != prev_status) {
501 mpsslog("%s %s Waiting... desc-> type %d "
502 "status 0x%x\n",
503 mic->name, __func__, type,
504 desc->status);
505 prev_status = desc->status;
506 }
507 if (desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
508 mpsslog("%s %s poll.revents %d\n",
509 mic->name, __func__, pollfd.revents);
510 mpsslog("%s %s desc-> type %d status 0x%x\n",
511 mic->name, __func__, type,
512 desc->status);
513 break;
514 }
515 }
516 }
517 return 0;
518}
519
520/* Spin till we have some descriptors */
521static void
522spin_for_descriptors(struct mic_info *mic, struct mic_vring *vr)
523{
524 __u16 avail_idx = read_avail_idx(vr);
525
526 while (avail_idx == le16toh(ACCESS_ONCE(vr->vr.avail->idx))) {
527#ifdef DEBUG
528 mpsslog("%s %s waiting for desc avail %d info_avail %d\n",
529 mic->name, __func__,
530 le16toh(vr->vr.avail->idx), vr->info->avail_idx);
531#endif
532 sched_yield();
533 }
534}
535
536static void *
537virtio_net(void *arg)
538{
539 static __u8 vnet_hdr[2][sizeof(struct virtio_net_hdr)];
540 static __u8 vnet_buf[2][MAX_NET_PKT_SIZE] __attribute__ ((aligned(64)));
541 struct iovec vnet_iov[2][2] = {
542 { { .iov_base = vnet_hdr[0], .iov_len = sizeof(vnet_hdr[0]) },
543 { .iov_base = vnet_buf[0], .iov_len = sizeof(vnet_buf[0]) } },
544 { { .iov_base = vnet_hdr[1], .iov_len = sizeof(vnet_hdr[1]) },
545 { .iov_base = vnet_buf[1], .iov_len = sizeof(vnet_buf[1]) } },
546 };
547 struct iovec *iov0 = vnet_iov[0], *iov1 = vnet_iov[1];
548 struct mic_info *mic = (struct mic_info *)arg;
549 char if_name[IFNAMSIZ];
550 struct pollfd net_poll[MAX_NET_FD];
551 struct mic_vring tx_vr, rx_vr;
552 struct mic_copy_desc copy;
553 struct mic_device_desc *desc;
554 int err;
555
556 snprintf(if_name, IFNAMSIZ, "mic%d", mic->id);
557 mic->mic_net.tap_fd = tun_alloc(mic, if_name);
558 if (mic->mic_net.tap_fd < 0)
559 goto done;
560
561 if (tap_configure(mic, if_name))
562 goto done;
563 mpsslog("MIC name %s id %d\n", mic->name, mic->id);
564
565 net_poll[NET_FD_VIRTIO_NET].fd = mic->mic_net.virtio_net_fd;
566 net_poll[NET_FD_VIRTIO_NET].events = POLLIN;
567 net_poll[NET_FD_TUN].fd = mic->mic_net.tap_fd;
568 net_poll[NET_FD_TUN].events = POLLIN;
569
570 if (MAP_FAILED == init_vr(mic, mic->mic_net.virtio_net_fd,
571 VIRTIO_ID_NET, &tx_vr, &rx_vr,
572 virtnet_dev_page.dd.num_vq)) {
573 mpsslog("%s init_vr failed %s\n",
574 mic->name, strerror(errno));
575 goto done;
576 }
577
578 copy.iovcnt = 2;
579 desc = get_device_desc(mic, VIRTIO_ID_NET);
580
581 while (1) {
582 ssize_t len;
583
584 net_poll[NET_FD_VIRTIO_NET].revents = 0;
585 net_poll[NET_FD_TUN].revents = 0;
586
587 /* Start polling for data from tap and virtio net */
588 err = poll(net_poll, 2, -1);
589 if (err < 0) {
590 mpsslog("%s poll failed %s\n",
591 __func__, strerror(errno));
592 continue;
593 }
594 if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
595 err = wait_for_card_driver(mic,
596 mic->mic_net.virtio_net_fd,
597 VIRTIO_ID_NET);
598 if (err) {
599 mpsslog("%s %s %d Exiting...\n",
600 mic->name, __func__, __LINE__);
601 break;
602 }
603 }
604 /*
605 * Check if there is data to be read from TUN and write to
606 * virtio net fd if there is.
607 */
608 if (net_poll[NET_FD_TUN].revents & POLLIN) {
609 copy.iov = iov0;
610 len = readv(net_poll[NET_FD_TUN].fd,
611 copy.iov, copy.iovcnt);
612 if (len > 0) {
613 struct virtio_net_hdr *hdr
614 = (struct virtio_net_hdr *)vnet_hdr[0];
615
616 /* Disable checksums on the card since we are on
617 a reliable PCIe link */
618 hdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID;
619#ifdef DEBUG
620 mpsslog("%s %s %d hdr->flags 0x%x ", mic->name,
621 __func__, __LINE__, hdr->flags);
622 mpsslog("copy.out_len %d hdr->gso_type 0x%x\n",
623 copy.out_len, hdr->gso_type);
624#endif
625#ifdef DEBUG
626 disp_iovec(mic, copy, __func__, __LINE__);
627 mpsslog("%s %s %d read from tap 0x%lx\n",
628 mic->name, __func__, __LINE__,
629 len);
630#endif
631 spin_for_descriptors(mic, &tx_vr);
632 txrx_prepare(VIRTIO_ID_NET, 1, &tx_vr, &copy,
633 len);
634
635 err = mic_virtio_copy(mic,
636 mic->mic_net.virtio_net_fd, &tx_vr,
637 &copy);
638 if (err < 0) {
639 mpsslog("%s %s %d mic_virtio_copy %s\n",
640 mic->name, __func__, __LINE__,
641 strerror(errno));
642 }
643 if (!err)
644 verify_out_len(mic, &copy);
645#ifdef DEBUG
646 disp_iovec(mic, copy, __func__, __LINE__);
647 mpsslog("%s %s %d wrote to net 0x%lx\n",
648 mic->name, __func__, __LINE__,
649 sum_iovec_len(&copy));
650#endif
651 /* Reinitialize IOV for next run */
652 iov0[1].iov_len = MAX_NET_PKT_SIZE;
653 } else if (len < 0) {
654 disp_iovec(mic, &copy, __func__, __LINE__);
655 mpsslog("%s %s %d read failed %s ", mic->name,
656 __func__, __LINE__, strerror(errno));
657 mpsslog("cnt %d sum %zd\n",
658 copy.iovcnt, sum_iovec_len(&copy));
659 }
660 }
661
662 /*
663 * Check if there is data to be read from virtio net and
664 * write to TUN if there is.
665 */
666 if (net_poll[NET_FD_VIRTIO_NET].revents & POLLIN) {
667 while (rx_vr.info->avail_idx !=
668 le16toh(rx_vr.vr.avail->idx)) {
669 copy.iov = iov1;
670 txrx_prepare(VIRTIO_ID_NET, 0, &rx_vr, &copy,
671 MAX_NET_PKT_SIZE
672 + sizeof(struct virtio_net_hdr));
673
674 err = mic_virtio_copy(mic,
675 mic->mic_net.virtio_net_fd, &rx_vr,
676 &copy);
677 if (!err) {
678#ifdef DEBUG
679 struct virtio_net_hdr *hdr
680 = (struct virtio_net_hdr *)
681 vnet_hdr[1];
682
683 mpsslog("%s %s %d hdr->flags 0x%x, ",
684 mic->name, __func__, __LINE__,
685 hdr->flags);
686 mpsslog("out_len %d gso_type 0x%x\n",
687 copy.out_len,
688 hdr->gso_type);
689#endif
690 /* Set the correct output iov_len */
691 iov1[1].iov_len = copy.out_len -
692 sizeof(struct virtio_net_hdr);
693 verify_out_len(mic, &copy);
694#ifdef DEBUG
695 disp_iovec(mic, copy, __func__,
696 __LINE__);
697 mpsslog("%s %s %d ",
698 mic->name, __func__, __LINE__);
699 mpsslog("read from net 0x%lx\n",
700 sum_iovec_len(copy));
701#endif
702 len = writev(net_poll[NET_FD_TUN].fd,
703 copy.iov, copy.iovcnt);
704 if (len != sum_iovec_len(&copy)) {
705 mpsslog("Tun write failed %s ",
706 strerror(errno));
707 mpsslog("len 0x%zx ", len);
708 mpsslog("read_len 0x%zx\n",
709 sum_iovec_len(&copy));
710 } else {
711#ifdef DEBUG
712 disp_iovec(mic, &copy, __func__,
713 __LINE__);
714 mpsslog("%s %s %d ",
715 mic->name, __func__,
716 __LINE__);
717 mpsslog("wrote to tap 0x%lx\n",
718 len);
719#endif
720 }
721 } else {
722 mpsslog("%s %s %d mic_virtio_copy %s\n",
723 mic->name, __func__, __LINE__,
724 strerror(errno));
725 break;
726 }
727 }
728 }
729 if (net_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
730 mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
731 }
732done:
733 pthread_exit(NULL);
734}
735
736/* virtio_console */
737#define VIRTIO_CONSOLE_FD 0
738#define MONITOR_FD (VIRTIO_CONSOLE_FD + 1)
739#define MAX_CONSOLE_FD (MONITOR_FD + 1) /* must be the last one + 1 */
740#define MAX_BUFFER_SIZE PAGE_SIZE
741
742static void *
743virtio_console(void *arg)
744{
745 static __u8 vcons_buf[2][PAGE_SIZE];
746 struct iovec vcons_iov[2] = {
747 { .iov_base = vcons_buf[0], .iov_len = sizeof(vcons_buf[0]) },
748 { .iov_base = vcons_buf[1], .iov_len = sizeof(vcons_buf[1]) },
749 };
750 struct iovec *iov0 = &vcons_iov[0], *iov1 = &vcons_iov[1];
751 struct mic_info *mic = (struct mic_info *)arg;
752 int err;
753 struct pollfd console_poll[MAX_CONSOLE_FD];
754 int pty_fd;
755 char *pts_name;
756 ssize_t len;
757 struct mic_vring tx_vr, rx_vr;
758 struct mic_copy_desc copy;
759 struct mic_device_desc *desc;
760
761 pty_fd = posix_openpt(O_RDWR);
762 if (pty_fd < 0) {
763 mpsslog("can't open a pseudoterminal master device: %s\n",
764 strerror(errno));
765 goto _return;
766 }
767 pts_name = ptsname(pty_fd);
768 if (pts_name == NULL) {
769 mpsslog("can't get pts name\n");
770 goto _close_pty;
771 }
772 printf("%s console message goes to %s\n", mic->name, pts_name);
773 mpsslog("%s console message goes to %s\n", mic->name, pts_name);
774 err = grantpt(pty_fd);
775 if (err < 0) {
776 mpsslog("can't grant access: %s %s\n",
777 pts_name, strerror(errno));
778 goto _close_pty;
779 }
780 err = unlockpt(pty_fd);
781 if (err < 0) {
782 mpsslog("can't unlock a pseudoterminal: %s %s\n",
783 pts_name, strerror(errno));
784 goto _close_pty;
785 }
786 console_poll[MONITOR_FD].fd = pty_fd;
787 console_poll[MONITOR_FD].events = POLLIN;
788
789 console_poll[VIRTIO_CONSOLE_FD].fd = mic->mic_console.virtio_console_fd;
790 console_poll[VIRTIO_CONSOLE_FD].events = POLLIN;
791
792 if (MAP_FAILED == init_vr(mic, mic->mic_console.virtio_console_fd,
793 VIRTIO_ID_CONSOLE, &tx_vr, &rx_vr,
794 virtcons_dev_page.dd.num_vq)) {
795 mpsslog("%s init_vr failed %s\n",
796 mic->name, strerror(errno));
797 goto _close_pty;
798 }
799
800 copy.iovcnt = 1;
801 desc = get_device_desc(mic, VIRTIO_ID_CONSOLE);
802
803 for (;;) {
804 console_poll[MONITOR_FD].revents = 0;
805 console_poll[VIRTIO_CONSOLE_FD].revents = 0;
806 err = poll(console_poll, MAX_CONSOLE_FD, -1);
807 if (err < 0) {
808 mpsslog("%s %d: poll failed: %s\n", __func__, __LINE__,
809 strerror(errno));
810 continue;
811 }
812 if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
813 err = wait_for_card_driver(mic,
814 mic->mic_console.virtio_console_fd,
815 VIRTIO_ID_CONSOLE);
816 if (err) {
817 mpsslog("%s %s %d Exiting...\n",
818 mic->name, __func__, __LINE__);
819 break;
820 }
821 }
822
823 if (console_poll[MONITOR_FD].revents & POLLIN) {
824 copy.iov = iov0;
825 len = readv(pty_fd, copy.iov, copy.iovcnt);
826 if (len > 0) {
827#ifdef DEBUG
828 disp_iovec(mic, copy, __func__, __LINE__);
829 mpsslog("%s %s %d read from tap 0x%lx\n",
830 mic->name, __func__, __LINE__,
831 len);
832#endif
833 spin_for_descriptors(mic, &tx_vr);
834 txrx_prepare(VIRTIO_ID_CONSOLE, 1, &tx_vr,
835 &copy, len);
836
837 err = mic_virtio_copy(mic,
838 mic->mic_console.virtio_console_fd,
839 &tx_vr, &copy);
840 if (err < 0) {
841 mpsslog("%s %s %d mic_virtio_copy %s\n",
842 mic->name, __func__, __LINE__,
843 strerror(errno));
844 }
845 if (!err)
846 verify_out_len(mic, &copy);
847#ifdef DEBUG
848 disp_iovec(mic, copy, __func__, __LINE__);
849 mpsslog("%s %s %d wrote to net 0x%lx\n",
850 mic->name, __func__, __LINE__,
851 sum_iovec_len(copy));
852#endif
853 /* Reinitialize IOV for next run */
854 iov0->iov_len = PAGE_SIZE;
855 } else if (len < 0) {
856 disp_iovec(mic, &copy, __func__, __LINE__);
857 mpsslog("%s %s %d read failed %s ",
858 mic->name, __func__, __LINE__,
859 strerror(errno));
860 mpsslog("cnt %d sum %zd\n",
861 copy.iovcnt, sum_iovec_len(&copy));
862 }
863 }
864
865 if (console_poll[VIRTIO_CONSOLE_FD].revents & POLLIN) {
866 while (rx_vr.info->avail_idx !=
867 le16toh(rx_vr.vr.avail->idx)) {
868 copy.iov = iov1;
869 txrx_prepare(VIRTIO_ID_CONSOLE, 0, &rx_vr,
870 &copy, PAGE_SIZE);
871
872 err = mic_virtio_copy(mic,
873 mic->mic_console.virtio_console_fd,
874 &rx_vr, &copy);
875 if (!err) {
876 /* Set the correct output iov_len */
877 iov1->iov_len = copy.out_len;
878 verify_out_len(mic, &copy);
879#ifdef DEBUG
880 disp_iovec(mic, copy, __func__,
881 __LINE__);
882 mpsslog("%s %s %d ",
883 mic->name, __func__, __LINE__);
884 mpsslog("read from net 0x%lx\n",
885 sum_iovec_len(copy));
886#endif
887 len = writev(pty_fd,
888 copy.iov, copy.iovcnt);
889 if (len != sum_iovec_len(&copy)) {
890 mpsslog("Tun write failed %s ",
891 strerror(errno));
892 mpsslog("len 0x%zx ", len);
893 mpsslog("read_len 0x%zx\n",
894 sum_iovec_len(&copy));
895 } else {
896#ifdef DEBUG
897 disp_iovec(mic, copy, __func__,
898 __LINE__);
899 mpsslog("%s %s %d ",
900 mic->name, __func__,
901 __LINE__);
902 mpsslog("wrote to tap 0x%lx\n",
903 len);
904#endif
905 }
906 } else {
907 mpsslog("%s %s %d mic_virtio_copy %s\n",
908 mic->name, __func__, __LINE__,
909 strerror(errno));
910 break;
911 }
912 }
913 }
914 if (console_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
915 mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
916 }
917_close_pty:
918 close(pty_fd);
919_return:
920 pthread_exit(NULL);
921}
922
923static void
924add_virtio_device(struct mic_info *mic, struct mic_device_desc *dd)
925{
926 char path[PATH_MAX];
927 int fd, err;
928
929 snprintf(path, PATH_MAX, "/dev/mic%d", mic->id);
930 fd = open(path, O_RDWR);
931 if (fd < 0) {
932 mpsslog("Could not open %s %s\n", path, strerror(errno));
933 return;
934 }
935
936 err = ioctl(fd, MIC_VIRTIO_ADD_DEVICE, dd);
937 if (err < 0) {
938 mpsslog("Could not add %d %s\n", dd->type, strerror(errno));
939 close(fd);
940 return;
941 }
942 switch (dd->type) {
943 case VIRTIO_ID_NET:
944 mic->mic_net.virtio_net_fd = fd;
945 mpsslog("Added VIRTIO_ID_NET for %s\n", mic->name);
946 break;
947 case VIRTIO_ID_CONSOLE:
948 mic->mic_console.virtio_console_fd = fd;
949 mpsslog("Added VIRTIO_ID_CONSOLE for %s\n", mic->name);
950 break;
951 case VIRTIO_ID_BLOCK:
952 mic->mic_virtblk.virtio_block_fd = fd;
953 mpsslog("Added VIRTIO_ID_BLOCK for %s\n", mic->name);
954 break;
955 }
956}
957
958static bool
959set_backend_file(struct mic_info *mic)
960{
961 FILE *config;
962 char buff[PATH_MAX], *line, *evv, *p;
963
964 snprintf(buff, PATH_MAX, "%s/mpssd%03d.conf", mic_config_dir, mic->id);
965 config = fopen(buff, "r");
966 if (config == NULL)
967 return false;
968 do { /* look for "virtblk_backend=XXXX" */
969 line = fgets(buff, PATH_MAX, config);
970 if (line == NULL)
971 break;
972 if (*line == '#')
973 continue;
974 p = strchr(line, '\n');
975 if (p)
976 *p = '\0';
977 } while (strncmp(line, virtblk_backend, strlen(virtblk_backend)) != 0);
978 fclose(config);
979 if (line == NULL)
980 return false;
981 evv = strchr(line, '=');
982 if (evv == NULL)
983 return false;
984 mic->mic_virtblk.backend_file = malloc(strlen(evv) + 1);
985 if (mic->mic_virtblk.backend_file == NULL) {
986 mpsslog("%s %d can't allocate memory\n", mic->name, mic->id);
987 return false;
988 }
989 strcpy(mic->mic_virtblk.backend_file, evv + 1);
990 return true;
991}
992
993#define SECTOR_SIZE 512
994static bool
995set_backend_size(struct mic_info *mic)
996{
997 mic->mic_virtblk.backend_size = lseek(mic->mic_virtblk.backend, 0,
998 SEEK_END);
999 if (mic->mic_virtblk.backend_size < 0) {
1000 mpsslog("%s: can't seek: %s\n",
1001 mic->name, mic->mic_virtblk.backend_file);
1002 return false;
1003 }
1004 virtblk_dev_page.blk_config.capacity =
1005 mic->mic_virtblk.backend_size / SECTOR_SIZE;
1006 if ((mic->mic_virtblk.backend_size % SECTOR_SIZE) != 0)
1007 virtblk_dev_page.blk_config.capacity++;
1008
1009 virtblk_dev_page.blk_config.capacity =
1010 htole64(virtblk_dev_page.blk_config.capacity);
1011
1012 return true;
1013}
1014
1015static bool
1016open_backend(struct mic_info *mic)
1017{
1018 if (!set_backend_file(mic))
1019 goto _error_exit;
1020 mic->mic_virtblk.backend = open(mic->mic_virtblk.backend_file, O_RDWR);
1021 if (mic->mic_virtblk.backend < 0) {
1022 mpsslog("%s: can't open: %s\n", mic->name,
1023 mic->mic_virtblk.backend_file);
1024 goto _error_free;
1025 }
1026 if (!set_backend_size(mic))
1027 goto _error_close;
1028 mic->mic_virtblk.backend_addr = mmap(NULL,
1029 mic->mic_virtblk.backend_size,
1030 PROT_READ|PROT_WRITE, MAP_SHARED,
1031 mic->mic_virtblk.backend, 0L);
1032 if (mic->mic_virtblk.backend_addr == MAP_FAILED) {
1033 mpsslog("%s: can't map: %s %s\n",
1034 mic->name, mic->mic_virtblk.backend_file,
1035 strerror(errno));
1036 goto _error_close;
1037 }
1038 return true;
1039
1040 _error_close:
1041 close(mic->mic_virtblk.backend);
1042 _error_free:
1043 free(mic->mic_virtblk.backend_file);
1044 _error_exit:
1045 return false;
1046}
1047
1048static void
1049close_backend(struct mic_info *mic)
1050{
1051 munmap(mic->mic_virtblk.backend_addr, mic->mic_virtblk.backend_size);
1052 close(mic->mic_virtblk.backend);
1053 free(mic->mic_virtblk.backend_file);
1054}
1055
1056static bool
1057start_virtblk(struct mic_info *mic, struct mic_vring *vring)
1058{
1059 if (((unsigned long)&virtblk_dev_page.blk_config % 8) != 0) {
1060 mpsslog("%s: blk_config is not 8 byte aligned.\n",
1061 mic->name);
1062 return false;
1063 }
1064 add_virtio_device(mic, &virtblk_dev_page.dd);
1065 if (MAP_FAILED == init_vr(mic, mic->mic_virtblk.virtio_block_fd,
1066 VIRTIO_ID_BLOCK, vring, NULL,
1067 virtblk_dev_page.dd.num_vq)) {
1068 mpsslog("%s init_vr failed %s\n",
1069 mic->name, strerror(errno));
1070 return false;
1071 }
1072 return true;
1073}
1074
1075static void
1076stop_virtblk(struct mic_info *mic)
1077{
1078 int vr_size, ret;
1079
1080 vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES,
1081 MIC_VIRTIO_RING_ALIGN) +
1082 sizeof(struct _mic_vring_info));
1083 ret = munmap(mic->mic_virtblk.block_dp,
1084 MIC_DEVICE_PAGE_END + vr_size * virtblk_dev_page.dd.num_vq);
1085 if (ret < 0)
1086 mpsslog("%s munmap errno %d\n", mic->name, errno);
1087 close(mic->mic_virtblk.virtio_block_fd);
1088}
1089
1090static __u8
1091header_error_check(struct vring_desc *desc)
1092{
1093 if (le32toh(desc->len) != sizeof(struct virtio_blk_outhdr)) {
1094 mpsslog("%s() %d: length is not sizeof(virtio_blk_outhd)\n",
1095 __func__, __LINE__);
1096 return -EIO;
1097 }
1098 if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT)) {
1099 mpsslog("%s() %d: alone\n",
1100 __func__, __LINE__);
1101 return -EIO;
1102 }
1103 if (le16toh(desc->flags) & VRING_DESC_F_WRITE) {
1104 mpsslog("%s() %d: not read\n",
1105 __func__, __LINE__);
1106 return -EIO;
1107 }
1108 return 0;
1109}
1110
1111static int
1112read_header(int fd, struct virtio_blk_outhdr *hdr, __u32 desc_idx)
1113{
1114 struct iovec iovec;
1115 struct mic_copy_desc copy;
1116
1117 iovec.iov_len = sizeof(*hdr);
1118 iovec.iov_base = hdr;
1119 copy.iov = &iovec;
1120 copy.iovcnt = 1;
1121 copy.vr_idx = 0; /* only one vring on virtio_block */
1122 copy.update_used = false; /* do not update used index */
1123 return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
1124}
1125
1126static int
1127transfer_blocks(int fd, struct iovec *iovec, __u32 iovcnt)
1128{
1129 struct mic_copy_desc copy;
1130
1131 copy.iov = iovec;
1132 copy.iovcnt = iovcnt;
1133 copy.vr_idx = 0; /* only one vring on virtio_block */
1134 copy.update_used = false; /* do not update used index */
1135 return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
1136}
1137
1138static __u8
1139status_error_check(struct vring_desc *desc)
1140{
1141 if (le32toh(desc->len) != sizeof(__u8)) {
1142 mpsslog("%s() %d: length is not sizeof(status)\n",
1143 __func__, __LINE__);
1144 return -EIO;
1145 }
1146 return 0;
1147}
1148
1149static int
1150write_status(int fd, __u8 *status)
1151{
1152 struct iovec iovec;
1153 struct mic_copy_desc copy;
1154
1155 iovec.iov_base = status;
1156 iovec.iov_len = sizeof(*status);
1157 copy.iov = &iovec;
1158 copy.iovcnt = 1;
1159 copy.vr_idx = 0; /* only one vring on virtio_block */
1160 copy.update_used = true; /* Update used index */
1161 return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
1162}
1163
1164#ifndef VIRTIO_BLK_T_GET_ID
1165#define VIRTIO_BLK_T_GET_ID 8
1166#endif
1167
1168static void *
1169virtio_block(void *arg)
1170{
1171 struct mic_info *mic = (struct mic_info *)arg;
1172 int ret;
1173 struct pollfd block_poll;
1174 struct mic_vring vring;
1175 __u16 avail_idx;
1176 __u32 desc_idx;
1177 struct vring_desc *desc;
1178 struct iovec *iovec, *piov;
1179 __u8 status;
1180 __u32 buffer_desc_idx;
1181 struct virtio_blk_outhdr hdr;
1182 void *fos;
1183
1184 for (;;) { /* forever */
1185 if (!open_backend(mic)) { /* No virtblk */
1186 for (mic->mic_virtblk.signaled = 0;
1187 !mic->mic_virtblk.signaled;)
1188 sleep(1);
1189 continue;
1190 }
1191
1192 /* backend file is specified. */
1193 if (!start_virtblk(mic, &vring))
1194 goto _close_backend;
1195 iovec = malloc(sizeof(*iovec) *
1196 le32toh(virtblk_dev_page.blk_config.seg_max));
1197 if (!iovec) {
1198 mpsslog("%s: can't alloc iovec: %s\n",
1199 mic->name, strerror(ENOMEM));
1200 goto _stop_virtblk;
1201 }
1202
1203 block_poll.fd = mic->mic_virtblk.virtio_block_fd;
1204 block_poll.events = POLLIN;
1205 for (mic->mic_virtblk.signaled = 0;
1206 !mic->mic_virtblk.signaled;) {
1207 block_poll.revents = 0;
1208 /* timeout in 1 sec to see signaled */
1209 ret = poll(&block_poll, 1, 1000);
1210 if (ret < 0) {
1211 mpsslog("%s %d: poll failed: %s\n",
1212 __func__, __LINE__,
1213 strerror(errno));
1214 continue;
1215 }
1216
1217 if (!(block_poll.revents & POLLIN)) {
1218#ifdef DEBUG
1219 mpsslog("%s %d: block_poll.revents=0x%x\n",
1220 __func__, __LINE__, block_poll.revents);
1221#endif
1222 continue;
1223 }
1224
1225 /* POLLIN */
1226 while (vring.info->avail_idx !=
1227 le16toh(vring.vr.avail->idx)) {
1228 /* read header element */
1229 avail_idx =
1230 vring.info->avail_idx &
1231 (vring.vr.num - 1);
1232 desc_idx = le16toh(
1233 vring.vr.avail->ring[avail_idx]);
1234 desc = &vring.vr.desc[desc_idx];
1235#ifdef DEBUG
1236 mpsslog("%s() %d: avail_idx=%d ",
1237 __func__, __LINE__,
1238 vring.info->avail_idx);
1239 mpsslog("vring.vr.num=%d desc=%p\n",
1240 vring.vr.num, desc);
1241#endif
1242 status = header_error_check(desc);
1243 ret = read_header(
1244 mic->mic_virtblk.virtio_block_fd,
1245 &hdr, desc_idx);
1246 if (ret < 0) {
1247 mpsslog("%s() %d %s: ret=%d %s\n",
1248 __func__, __LINE__,
1249 mic->name, ret,
1250 strerror(errno));
1251 break;
1252 }
1253 /* buffer element */
1254 piov = iovec;
1255 status = 0;
1256 fos = mic->mic_virtblk.backend_addr +
1257 (hdr.sector * SECTOR_SIZE);
1258 buffer_desc_idx = next_desc(desc);
1259 desc_idx = buffer_desc_idx;
1260 for (desc = &vring.vr.desc[buffer_desc_idx];
1261 desc->flags & VRING_DESC_F_NEXT;
1262 desc_idx = next_desc(desc),
1263 desc = &vring.vr.desc[desc_idx]) {
1264 piov->iov_len = desc->len;
1265 piov->iov_base = fos;
1266 piov++;
1267 fos += desc->len;
1268 }
1269 /* Returning NULLs for VIRTIO_BLK_T_GET_ID. */
1270 if (hdr.type & ~(VIRTIO_BLK_T_OUT |
1271 VIRTIO_BLK_T_GET_ID)) {
1272 /*
1273 VIRTIO_BLK_T_IN - does not do
1274 anything. Probably for documenting.
1275 VIRTIO_BLK_T_SCSI_CMD - for
1276 virtio_scsi.
1277 VIRTIO_BLK_T_FLUSH - turned off in
1278 config space.
1279 VIRTIO_BLK_T_BARRIER - defined but not
1280 used in anywhere.
1281 */
1282 mpsslog("%s() %d: type %x ",
1283 __func__, __LINE__,
1284 hdr.type);
1285 mpsslog("is not supported\n");
1286 status = -ENOTSUP;
1287
1288 } else {
1289 ret = transfer_blocks(
1290 mic->mic_virtblk.virtio_block_fd,
1291 iovec,
1292 piov - iovec);
1293 if (ret < 0 &&
1294 status != 0)
1295 status = ret;
1296 }
1297 /* write status and update used pointer */
1298 if (status != 0)
1299 status = status_error_check(desc);
1300 ret = write_status(
1301 mic->mic_virtblk.virtio_block_fd,
1302 &status);
1303#ifdef DEBUG
1304 mpsslog("%s() %d: write status=%d on desc=%p\n",
1305 __func__, __LINE__,
1306 status, desc);
1307#endif
1308 }
1309 }
1310 free(iovec);
1311_stop_virtblk:
1312 stop_virtblk(mic);
1313_close_backend:
1314 close_backend(mic);
1315 } /* forever */
1316
1317 pthread_exit(NULL);
1318}
1319
1320static void
1321reset(struct mic_info *mic)
1322{
1323#define RESET_TIMEOUT 120
1324 int i = RESET_TIMEOUT;
1325 setsysfs(mic->name, "state", "reset");
1326 while (i) {
1327 char *state;
1328 state = readsysfs(mic->name, "state");
1329 if (!state)
1330 goto retry;
1331 mpsslog("%s: %s %d state %s\n",
1332 mic->name, __func__, __LINE__, state);
1333
1334 if (!strcmp(state, "ready")) {
1335 free(state);
1336 break;
1337 }
1338 free(state);
1339retry:
1340 sleep(1);
1341 i--;
1342 }
1343}
1344
1345static int
1346get_mic_shutdown_status(struct mic_info *mic, char *shutdown_status)
1347{
1348 if (!strcmp(shutdown_status, "nop"))
1349 return MIC_NOP;
1350 if (!strcmp(shutdown_status, "crashed"))
1351 return MIC_CRASHED;
1352 if (!strcmp(shutdown_status, "halted"))
1353 return MIC_HALTED;
1354 if (!strcmp(shutdown_status, "poweroff"))
1355 return MIC_POWER_OFF;
1356 if (!strcmp(shutdown_status, "restart"))
1357 return MIC_RESTART;
1358 mpsslog("%s: BUG invalid status %s\n", mic->name, shutdown_status);
1359 /* Invalid state */
1360 assert(0);
1361};
1362
1363static int get_mic_state(struct mic_info *mic)
1364{
1365 char *state = NULL;
1366 enum mic_states mic_state;
1367
1368 while (!state) {
1369 state = readsysfs(mic->name, "state");
1370 sleep(1);
1371 }
1372 mpsslog("%s: %s %d state %s\n",
1373 mic->name, __func__, __LINE__, state);
1374
1375 if (!strcmp(state, "ready")) {
1376 mic_state = MIC_READY;
1377 } else if (!strcmp(state, "booting")) {
1378 mic_state = MIC_BOOTING;
1379 } else if (!strcmp(state, "online")) {
1380 mic_state = MIC_ONLINE;
1381 } else if (!strcmp(state, "shutting_down")) {
1382 mic_state = MIC_SHUTTING_DOWN;
1383 } else if (!strcmp(state, "reset_failed")) {
1384 mic_state = MIC_RESET_FAILED;
1385 } else if (!strcmp(state, "resetting")) {
1386 mic_state = MIC_RESETTING;
1387 } else {
1388 mpsslog("%s: BUG invalid state %s\n", mic->name, state);
1389 assert(0);
1390 }
1391
1392 free(state);
1393 return mic_state;
1394};
1395
1396static void mic_handle_shutdown(struct mic_info *mic)
1397{
1398#define SHUTDOWN_TIMEOUT 60
1399 int i = SHUTDOWN_TIMEOUT;
1400 char *shutdown_status;
1401 while (i) {
1402 shutdown_status = readsysfs(mic->name, "shutdown_status");
1403 if (!shutdown_status) {
1404 sleep(1);
1405 continue;
1406 }
1407 mpsslog("%s: %s %d shutdown_status %s\n",
1408 mic->name, __func__, __LINE__, shutdown_status);
1409 switch (get_mic_shutdown_status(mic, shutdown_status)) {
1410 case MIC_RESTART:
1411 mic->restart = 1;
1412 case MIC_HALTED:
1413 case MIC_POWER_OFF:
1414 case MIC_CRASHED:
1415 free(shutdown_status);
1416 goto reset;
1417 default:
1418 break;
1419 }
1420 free(shutdown_status);
1421 sleep(1);
1422 i--;
1423 }
1424reset:
1425 if (!i)
1426 mpsslog("%s: %s %d timing out waiting for shutdown_status %s\n",
1427 mic->name, __func__, __LINE__, shutdown_status);
1428 reset(mic);
1429}
1430
1431static int open_state_fd(struct mic_info *mic)
1432{
1433 char pathname[PATH_MAX];
1434 int fd;
1435
1436 snprintf(pathname, PATH_MAX - 1, "%s/%s/%s",
1437 MICSYSFSDIR, mic->name, "state");
1438
1439 fd = open(pathname, O_RDONLY);
1440 if (fd < 0)
1441 mpsslog("%s: opening file %s failed %s\n",
1442 mic->name, pathname, strerror(errno));
1443 return fd;
1444}
1445
1446static int block_till_state_change(int fd, struct mic_info *mic)
1447{
1448 struct pollfd ufds[1];
1449 char value[PAGE_SIZE];
1450 int ret;
1451
1452 ufds[0].fd = fd;
1453 ufds[0].events = POLLERR | POLLPRI;
1454 ret = poll(ufds, 1, -1);
1455 if (ret < 0) {
1456 mpsslog("%s: %s %d poll failed %s\n",
1457 mic->name, __func__, __LINE__, strerror(errno));
1458 return ret;
1459 }
1460
1461 ret = lseek(fd, 0, SEEK_SET);
1462 if (ret < 0) {
1463 mpsslog("%s: %s %d Failed to seek to 0: %s\n",
1464 mic->name, __func__, __LINE__, strerror(errno));
1465 return ret;
1466 }
1467
1468 ret = read(fd, value, sizeof(value));
1469 if (ret < 0) {
1470 mpsslog("%s: %s %d Failed to read sysfs entry: %s\n",
1471 mic->name, __func__, __LINE__, strerror(errno));
1472 return ret;
1473 }
1474
1475 return 0;
1476}
1477
1478static void *
1479mic_config(void *arg)
1480{
1481 struct mic_info *mic = (struct mic_info *)arg;
1482 int fd, ret, stat = 0;
1483
1484 fd = open_state_fd(mic);
1485 if (fd < 0) {
1486 mpsslog("%s: %s %d open state fd failed %s\n",
1487 mic->name, __func__, __LINE__, strerror(errno));
1488 goto exit;
1489 }
1490
1491 do {
1492 ret = block_till_state_change(fd, mic);
1493 if (ret < 0) {
1494 mpsslog("%s: %s %d block_till_state_change error %s\n",
1495 mic->name, __func__, __LINE__, strerror(errno));
1496 goto close_exit;
1497 }
1498
1499 switch (get_mic_state(mic)) {
1500 case MIC_SHUTTING_DOWN:
1501 mic_handle_shutdown(mic);
1502 break;
1503 case MIC_READY:
1504 case MIC_RESET_FAILED:
1505 ret = kill(mic->pid, SIGTERM);
1506 mpsslog("%s: %s %d kill pid %d ret %d\n",
1507 mic->name, __func__, __LINE__,
1508 mic->pid, ret);
1509 if (!ret) {
1510 ret = waitpid(mic->pid, &stat,
1511 WIFSIGNALED(stat));
1512 mpsslog("%s: %s %d waitpid ret %d pid %d\n",
1513 mic->name, __func__, __LINE__,
1514 ret, mic->pid);
1515 }
1516 if (mic->boot_on_resume) {
1517 setsysfs(mic->name, "state", "boot");
1518 mic->boot_on_resume = 0;
1519 }
1520 goto close_exit;
1521 default:
1522 break;
1523 }
1524 } while (1);
1525
1526close_exit:
1527 close(fd);
1528exit:
1529 init_mic(mic);
1530 pthread_exit(NULL);
1531}
1532
1533static void
1534set_cmdline(struct mic_info *mic)
1535{
1536 char buffer[PATH_MAX];
1537 int len;
1538
1539 len = snprintf(buffer, PATH_MAX,
1540 "clocksource=tsc highres=off nohz=off ");
1541 len += snprintf(buffer + len, PATH_MAX - len,
1542 "cpufreq_on;corec6_off;pc3_off;pc6_off ");
1543 len += snprintf(buffer + len, PATH_MAX - len,
1544 "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0",
1545 mic->id + 1);
1546
1547 setsysfs(mic->name, "cmdline", buffer);
1548 mpsslog("%s: Command line: \"%s\"\n", mic->name, buffer);
1549 snprintf(buffer, PATH_MAX, "172.31.%d.1", mic->id + 1);
1550 mpsslog("%s: IPADDR: \"%s\"\n", mic->name, buffer);
1551}
1552
1553static void
1554set_log_buf_info(struct mic_info *mic)
1555{
1556 int fd;
1557 off_t len;
1558 char system_map[] = "/lib/firmware/mic/System.map";
1559 char *map, *temp, log_buf[17] = {'\0'};
1560
1561 fd = open(system_map, O_RDONLY);
1562 if (fd < 0) {
1563 mpsslog("%s: Opening System.map failed: %d\n",
1564 mic->name, errno);
1565 return;
1566 }
1567 len = lseek(fd, 0, SEEK_END);
1568 if (len < 0) {
1569 mpsslog("%s: Reading System.map size failed: %d\n",
1570 mic->name, errno);
1571 close(fd);
1572 return;
1573 }
1574 map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
1575 if (map == MAP_FAILED) {
1576 mpsslog("%s: mmap of System.map failed: %d\n",
1577 mic->name, errno);
1578 close(fd);
1579 return;
1580 }
1581 temp = strstr(map, "__log_buf");
1582 if (!temp) {
1583 mpsslog("%s: __log_buf not found: %d\n", mic->name, errno);
1584 munmap(map, len);
1585 close(fd);
1586 return;
1587 }
1588 strncpy(log_buf, temp - 19, 16);
1589 setsysfs(mic->name, "log_buf_addr", log_buf);
1590 mpsslog("%s: log_buf_addr: %s\n", mic->name, log_buf);
1591 temp = strstr(map, "log_buf_len");
1592 if (!temp) {
1593 mpsslog("%s: log_buf_len not found: %d\n", mic->name, errno);
1594 munmap(map, len);
1595 close(fd);
1596 return;
1597 }
1598 strncpy(log_buf, temp - 19, 16);
1599 setsysfs(mic->name, "log_buf_len", log_buf);
1600 mpsslog("%s: log_buf_len: %s\n", mic->name, log_buf);
1601 munmap(map, len);
1602 close(fd);
1603}
1604
1605static void
1606change_virtblk_backend(int x, siginfo_t *siginfo, void *p)
1607{
1608 struct mic_info *mic;
1609
1610 for (mic = mic_list.next; mic != NULL; mic = mic->next)
1611 mic->mic_virtblk.signaled = 1/* true */;
1612}
1613
1614static void
1615set_mic_boot_params(struct mic_info *mic)
1616{
1617 set_log_buf_info(mic);
1618 set_cmdline(mic);
1619}
1620
1621static void *
1622init_mic(void *arg)
1623{
1624 struct mic_info *mic = (struct mic_info *)arg;
1625 struct sigaction ignore = {
1626 .sa_flags = 0,
1627 .sa_handler = SIG_IGN
1628 };
1629 struct sigaction act = {
1630 .sa_flags = SA_SIGINFO,
1631 .sa_sigaction = change_virtblk_backend,
1632 };
1633 char buffer[PATH_MAX];
1634 int err, fd;
1635
1636 /*
1637 * Currently, one virtio block device is supported for each MIC card
1638 * at a time. Any user (or test) can send a SIGUSR1 to the MIC daemon.
1639 * The signal informs the virtio block backend about a change in the
1640 * configuration file which specifies the virtio backend file name on
1641 * the host. Virtio block backend then re-reads the configuration file
1642 * and switches to the new block device. This signalling mechanism may
1643 * not be required once multiple virtio block devices are supported by
1644 * the MIC daemon.
1645 */
1646 sigaction(SIGUSR1, &ignore, NULL);
1647retry:
1648 fd = open_state_fd(mic);
1649 if (fd < 0) {
1650 mpsslog("%s: %s %d open state fd failed %s\n",
1651 mic->name, __func__, __LINE__, strerror(errno));
1652 sleep(2);
1653 goto retry;
1654 }
1655
1656 if (mic->restart) {
1657 snprintf(buffer, PATH_MAX, "boot");
1658 setsysfs(mic->name, "state", buffer);
1659 mpsslog("%s restarting mic %d\n",
1660 mic->name, mic->restart);
1661 mic->restart = 0;
1662 }
1663
1664 while (1) {
1665 while (block_till_state_change(fd, mic)) {
1666 mpsslog("%s: %s %d block_till_state_change error %s\n",
1667 mic->name, __func__, __LINE__, strerror(errno));
1668 sleep(2);
1669 continue;
1670 }
1671
1672 if (get_mic_state(mic) == MIC_BOOTING)
1673 break;
1674 }
1675
1676 mic->pid = fork();
1677 switch (mic->pid) {
1678 case 0:
1679 add_virtio_device(mic, &virtcons_dev_page.dd);
1680 add_virtio_device(mic, &virtnet_dev_page.dd);
1681 err = pthread_create(&mic->mic_console.console_thread, NULL,
1682 virtio_console, mic);
1683 if (err)
1684 mpsslog("%s virtcons pthread_create failed %s\n",
1685 mic->name, strerror(err));
1686 err = pthread_create(&mic->mic_net.net_thread, NULL,
1687 virtio_net, mic);
1688 if (err)
1689 mpsslog("%s virtnet pthread_create failed %s\n",
1690 mic->name, strerror(err));
1691 err = pthread_create(&mic->mic_virtblk.block_thread, NULL,
1692 virtio_block, mic);
1693 if (err)
1694 mpsslog("%s virtblk pthread_create failed %s\n",
1695 mic->name, strerror(err));
1696 sigemptyset(&act.sa_mask);
1697 err = sigaction(SIGUSR1, &act, NULL);
1698 if (err)
1699 mpsslog("%s sigaction SIGUSR1 failed %s\n",
1700 mic->name, strerror(errno));
1701 while (1)
1702 sleep(60);
1703 case -1:
1704 mpsslog("fork failed MIC name %s id %d errno %d\n",
1705 mic->name, mic->id, errno);
1706 break;
1707 default:
1708 err = pthread_create(&mic->config_thread, NULL,
1709 mic_config, mic);
1710 if (err)
1711 mpsslog("%s mic_config pthread_create failed %s\n",
1712 mic->name, strerror(err));
1713 }
1714
1715 return NULL;
1716}
1717
1718static void
1719start_daemon(void)
1720{
1721 struct mic_info *mic;
1722 int err;
1723
1724 for (mic = mic_list.next; mic; mic = mic->next) {
1725 set_mic_boot_params(mic);
1726 err = pthread_create(&mic->init_thread, NULL, init_mic, mic);
1727 if (err)
1728 mpsslog("%s init_mic pthread_create failed %s\n",
1729 mic->name, strerror(err));
1730 }
1731
1732 while (1)
1733 sleep(60);
1734}
1735
1736static int
1737init_mic_list(void)
1738{
1739 struct mic_info *mic = &mic_list;
1740 struct dirent *file;
1741 DIR *dp;
1742 int cnt = 0;
1743
1744 dp = opendir(MICSYSFSDIR);
1745 if (!dp)
1746 return 0;
1747
1748 while ((file = readdir(dp)) != NULL) {
1749 if (!strncmp(file->d_name, "mic", 3)) {
1750 mic->next = calloc(1, sizeof(struct mic_info));
1751 if (mic->next) {
1752 mic = mic->next;
1753 mic->id = atoi(&file->d_name[3]);
1754 mic->name = malloc(strlen(file->d_name) + 16);
1755 if (mic->name)
1756 strcpy(mic->name, file->d_name);
1757 mpsslog("MIC name %s id %d\n", mic->name,
1758 mic->id);
1759 cnt++;
1760 }
1761 }
1762 }
1763
1764 closedir(dp);
1765 return cnt;
1766}
1767
1768void
1769mpsslog(char *format, ...)
1770{
1771 va_list args;
1772 char buffer[4096];
1773 char ts[52], *ts1;
1774 time_t t;
1775
1776 if (logfp == NULL)
1777 return;
1778
1779 va_start(args, format);
1780 vsprintf(buffer, format, args);
1781 va_end(args);
1782
1783 time(&t);
1784 ts1 = ctime_r(&t, ts);
1785 ts1[strlen(ts1) - 1] = '\0';
1786 fprintf(logfp, "%s: %s", ts1, buffer);
1787
1788 fflush(logfp);
1789}
1790
1791int
1792main(int argc, char *argv[])
1793{
1794 int cnt;
1795 pid_t pid;
1796
1797 myname = argv[0];
1798
1799 logfp = fopen(LOGFILE_NAME, "a+");
1800 if (!logfp) {
1801 fprintf(stderr, "cannot open logfile '%s'\n", LOGFILE_NAME);
1802 exit(1);
1803 }
1804 pid = fork();
1805 switch (pid) {
1806 case 0:
1807 break;
1808 case -1:
1809 exit(2);
1810 default:
1811 exit(0);
1812 }
1813
1814 mpsslog("MIC Daemon start\n");
1815
1816 cnt = init_mic_list();
1817 if (cnt == 0) {
1818 mpsslog("MIC module not loaded\n");
1819 exit(3);
1820 }
1821 mpsslog("MIC found %d devices\n", cnt);
1822
1823 start_daemon();
1824
1825 exit(0);
1826}
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 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2013 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
17 *
18 * Intel MIC User Space Tools.
19 */
20#ifndef _MPSSD_H_
21#define _MPSSD_H_
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <fcntl.h>
27#include <unistd.h>
28#include <dirent.h>
29#include <libgen.h>
30#include <pthread.h>
31#include <stdarg.h>
32#include <time.h>
33#include <errno.h>
34#include <sys/dir.h>
35#include <sys/ioctl.h>
36#include <sys/poll.h>
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <sys/stat.h>
40#include <sys/types.h>
41#include <sys/mman.h>
42#include <sys/utsname.h>
43#include <sys/wait.h>
44#include <netinet/in.h>
45#include <arpa/inet.h>
46#include <netdb.h>
47#include <pthread.h>
48#include <signal.h>
49#include <limits.h>
50#include <syslog.h>
51#include <getopt.h>
52#include <net/if.h>
53#include <linux/if_tun.h>
54#include <linux/if_tun.h>
55#include <linux/virtio_ids.h>
56
57#define MICSYSFSDIR "/sys/class/mic"
58#define LOGFILE_NAME "/var/log/mpssd"
59#define PAGE_SIZE 4096
60
61struct mic_console_info {
62 pthread_t console_thread;
63 int virtio_console_fd;
64 void *console_dp;
65};
66
67struct mic_net_info {
68 pthread_t net_thread;
69 int virtio_net_fd;
70 int tap_fd;
71 void *net_dp;
72};
73
74struct mic_virtblk_info {
75 pthread_t block_thread;
76 int virtio_block_fd;
77 void *block_dp;
78 volatile sig_atomic_t signaled;
79 char *backend_file;
80 int backend;
81 void *backend_addr;
82 long backend_size;
83};
84
85struct mic_info {
86 int id;
87 char *name;
88 pthread_t config_thread;
89 pthread_t init_thread;
90 pid_t pid;
91 struct mic_console_info mic_console;
92 struct mic_net_info mic_net;
93 struct mic_virtblk_info mic_virtblk;
94 int restart;
95 int boot_on_resume;
96 struct mic_info *next;
97};
98
99__attribute__((format(printf, 1, 2)))
100void mpsslog(char *format, ...);
101char *readsysfs(char *dir, char *entry);
102int setsysfs(char *dir, char *entry, char *value);
103#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 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2013 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
17 *
18 * Intel MIC User Space Tools.
19 */
20
21#include "mpssd.h"
22
23#define PAGE_SIZE 4096
24
25char *
26readsysfs(char *dir, char *entry)
27{
28 char filename[PATH_MAX];
29 char value[PAGE_SIZE];
30 char *string = NULL;
31 int fd;
32 int len;
33
34 if (dir == NULL)
35 snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry);
36 else
37 snprintf(filename, PATH_MAX,
38 "%s/%s/%s", MICSYSFSDIR, dir, entry);
39
40 fd = open(filename, O_RDONLY);
41 if (fd < 0) {
42 mpsslog("Failed to open sysfs entry '%s': %s\n",
43 filename, strerror(errno));
44 return NULL;
45 }
46
47 len = read(fd, value, sizeof(value));
48 if (len < 0) {
49 mpsslog("Failed to read sysfs entry '%s': %s\n",
50 filename, strerror(errno));
51 goto readsys_ret;
52 }
53 if (len == 0)
54 goto readsys_ret;
55
56 value[len - 1] = '\0';
57
58 string = malloc(strlen(value) + 1);
59 if (string)
60 strcpy(string, value);
61
62readsys_ret:
63 close(fd);
64 return string;
65}
66
67int
68setsysfs(char *dir, char *entry, char *value)
69{
70 char filename[PATH_MAX];
71 char *oldvalue;
72 int fd, ret = 0;
73
74 if (dir == NULL)
75 snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry);
76 else
77 snprintf(filename, PATH_MAX, "%s/%s/%s",
78 MICSYSFSDIR, dir, entry);
79
80 oldvalue = readsysfs(dir, entry);
81
82 fd = open(filename, O_RDWR);
83 if (fd < 0) {
84 ret = errno;
85 mpsslog("Failed to open sysfs entry '%s': %s\n",
86 filename, strerror(errno));
87 goto done;
88 }
89
90 if (!oldvalue || strcmp(value, oldvalue)) {
91 if (write(fd, value, strlen(value)) < 0) {
92 ret = errno;
93 mpsslog("Failed to write new sysfs entry '%s': %s\n",
94 filename, strerror(errno));
95 }
96 }
97 close(fd);
98done:
99 if (oldvalue)
100 free(oldvalue);
101 return ret;
102}