Release 4.9 samples/mic/mpssd/mpssd.c
/*
* 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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 388 | 99.49% | 1 | 50.00% |
ashutosh dixit | ashutosh dixit | 2 | 0.51% | 1 | 50.00% |
| Total | 390 | 100.00% | 2 | 100.00% |
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 232 | 100.00% | 1 | 100.00% |
| Total | 232 | 100.00% | 1 | 100.00% |
#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);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 78 | 100.00% | 1 | 100.00% |
| Total | 78 | 100.00% | 1 | 100.00% |
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 72 | 100.00% | 1 | 100.00% |
| Total | 72 | 100.00% | 1 | 100.00% |
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 130 | 99.24% | 1 | 50.00% |
ashutosh dixit | ashutosh dixit | 1 | 0.76% | 1 | 50.00% |
| Total | 131 | 100.00% | 2 | 100.00% |
/* 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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 45 | 100.00% | 1 | 100.00% |
| Total | 45 | 100.00% | 1 | 100.00% |
/* Sum up all the IOVEC length */
static ssize_t
sum_iovec_len(struct mic_copy_desc *copy)
{
ssize_t sum = 0;
unsigned int i;
for (i = 0; i < copy->iovcnt; i++)
sum += copy->iov[i].iov_len;
return sum;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 48 | 97.96% | 1 | 50.00% |
mahesh khanwalkar | mahesh khanwalkar | 1 | 2.04% | 1 | 50.00% |
| Total | 49 | 100.00% | 2 | 100.00% |
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));
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 63 | 98.44% | 1 | 50.00% |
sudeep dutt | sudeep dutt | 1 | 1.56% | 1 | 50.00% |
| Total | 64 | 100.00% | 2 | 100.00% |
/* Display an iovec */
static void
disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy,
const char *s, int line)
{
unsigned 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);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 74 | 97.37% | 1 | 33.33% |
sudeep dutt | sudeep dutt | 1 | 1.32% | 1 | 33.33% |
mahesh khanwalkar | mahesh khanwalkar | 1 | 1.32% | 1 | 33.33% |
| Total | 76 | 100.00% | 3 | 100.00% |
static inline __u16 read_avail_idx(struct mic_vring *vr)
{
return ACCESS_ONCE(vr->info->avail_idx);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 22 | 100.00% | 1 | 100.00% |
| Total | 22 | 100.00% | 1 | 100.00% |
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 77 | 100.00% | 1 | 100.00% |
| Total | 77 | 100.00% | 1 | 100.00% |
/* 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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 67 | 100.00% | 1 | 100.00% |
| Total | 67 | 100.00% | 1 | 100.00% |
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ashutosh dixit | ashutosh dixit | 65 | 100.00% | 1 | 100.00% |
| Total | 65 | 100.00% | 1 | 100.00% |
/*
* 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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 331 | 95.11% | 1 | 33.33% |
ashutosh dixit | ashutosh dixit | 17 | 4.89% | 2 | 66.67% |
| Total | 348 | 100.00% | 3 | 100.00% |
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 181 | 81.90% | 1 | 50.00% |
ashutosh dixit | ashutosh dixit | 40 | 18.10% | 1 | 50.00% |
| Total | 221 | 100.00% | 2 | 100.00% |
/* 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();
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
caz yokoyama | caz yokoyama | 80 | 100.00% | 1 | 100.00% |
| Total | 80 | 100.00% | 1 | 100.00% |
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;